【发布时间】:2020-03-03 22:38:21
【问题描述】:
我有以下疑问:
SELECT `assignments`.`id`
FROM `assignments`
WHERE
`assignments`.`account_id` = 742
AND `assignments`.`method` != 'stray'
AND (
`assignments`.`judge_id` = 2349724
OR (
`assignments`.`role_id` IN (234, 8745)
AND `assignments`.`judge_id` IS null
)
);
这个表目前有 660 万条记录,而且流量很大。我们最慢的查询是上面那个,即使有一个以 account_id、method、judge_id 和 role_id 为目标的索引,它也需要大约 0.5 秒才能运行。
查询确实使用了提供的索引,但似乎并没有给它带来太大的提升。
我可以在这里做些什么来改进查询并将其缩短到 100 毫秒以下? 660 万条记录真的不算多=\
我还想补充一点,如果我只是将查询限制在 account_id 子句(它有自己的索引),速度差不多。所以我真的很困惑。
以下是仅使用account_id的执行计划:
EXPLAIN select `assignments`.id FROM `assignments`WHERE `assignments`.`account_id` = 374;
+----+-------------+-------------+------------+------+----------------------------------------------------------------------+------------------------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------------+------------+------+----------------------------------------------------------------------+------------------------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | assignments | NULL | ref | assignments_account_id_index,assignments_account_id_updated_at_index | assignments_account_id_index | 9 | const | 965 | 100.00 | Using index |
+----+-------------+-------------+------------+------+----------------------------------------------------------------------+------------------------------+---------+-------+------+----------+-------------+
创建表语法:
CREATE TABLE `assignments` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`key` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`batch` int(10) unsigned NOT NULL,
`account_id` bigint(20) unsigned DEFAULT NULL,
`season_id` bigint(20) unsigned DEFAULT NULL,
`judge_id` bigint(20) unsigned DEFAULT NULL,
`role_id` bigint(20) unsigned DEFAULT NULL,
`entry_id` bigint(20) unsigned NOT NULL,
`score_set_id` bigint(20) unsigned NOT NULL,
`slug` char(8) COLLATE utf8_unicode_ci DEFAULT NULL,
`method` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`original_method` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`status` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'none',
`locked` tinyint(1) NOT NULL DEFAULT '0',
`conflict_of_interest` tinyint(1) NOT NULL DEFAULT '0',
`raw_score` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`raw_total` double NOT NULL DEFAULT '0',
`weighted_score` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`weighted_total` double NOT NULL DEFAULT '0',
`weight_sum` decimal(8,2) NOT NULL DEFAULT '0.00',
`progress` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`consensus` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`top_pick_preference` tinyint(3) unsigned DEFAULT NULL,
`top_pick_winner` tinyint(1) NOT NULL DEFAULT '0',
`top_pick_rank` int(11) DEFAULT NULL,
`total_votes` bigint(20) unsigned NOT NULL DEFAULT '0',
`scored_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `assignments_key_unique` (`key`),
KEY `assignments_account_id_index` (`account_id`),
KEY `assignments_judge_id_index` (`judge_id`),
KEY `assignments_role_id_index` (`role_id`),
KEY `assignments_entry_id_index` (`entry_id`),
KEY `assignments_score_set_id_index` (`score_set_id`),
KEY `assignments_season_id_index` (`season_id`),
KEY `assignments_slug_index` (`slug`),
KEY `assignments_status_index` (`status`),
KEY `assignments_method_index` (`method`),
KEY `assignments_original_method_index` (`original_method`),
KEY `assignments_account_id_updated_at_index` (`account_id`,`updated_at`)
) ENGINE=InnoDB AUTO_INCREMENT=661994447 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
【问题讨论】:
-
MySql 利用复合索引的能力在第一个范围条件下结束。在这种情况下,
(account_id, method, judge_id, role_id)上的索引只能利用 account_id 和方法的索引,因为!=是一个“范围”条件。 -
问题是,即使我将查询限制为仅 account_id,如前所述 - 它仍然一样快/慢。
-
关于方法方面,我应该简单地定义哪些值是有效的,而不是什么不是?
-
能否贴出查询执行平面?
-
@Uueerdo -
OR使用同一列 变成了IN。否则,OR对优化非常致命。IN的排名介于=和“范围”之间,具体取决于几件事。
标签: mysql sql indexing query-optimization query-performance