以下是三个MySQL查询。第一个返回我在一个查询中寻找的所有内容,而后两个返回相同的聚合结果,但在两个查询中。
我想知道为什么单个查询运行时间要长2-100倍,而且似乎所有三个查询之间的处理时间应相等。有没有办法优化单个查询以便像单个查询一样快速运行?在单个查询的WHERE语句中添加更多OR并不会增加处理时间,但我遇到需要执行更多OR的情况,并且最终单个查询将与运行十个单独查询一样快。
单个查询似乎也会在运行后缓存,第一次运行可能需要几分钟,而单个查询总是在同一时间范围内完成。
多列索引会在这里产生很大的不同吗?
值得注意的是,该表没有ID字段作为主索引。这会导致这种不良行为吗?
这里很难运行测试,因为该表有一亿行,并且添加列和索引的时间接近一天。
单一查询(4.2s)
SELECT name_id
FROM staging_company_search
WHERE
(name_word_0 = 'the' AND name_word_1 = 'glazier')
OR (name_word_0 = 'bridgewaters' AND name_word_1 = '');
等效的集合查询(每次0.8秒)
SELECT name_id
FROM staging_company_search
WHERE name_word_0 = 'the' AND name_word_1 = 'glazier';
SELECT name_id
FROM staging_company_search
WHERE name_word_0 = 'bridgewaters' AND name_word_1 = '';
对这些问题的解释
id select_type table type possible_keys key key_len ref rows extra
1 SIMPLE staging_company_search range name_word_0,name_word_1 name_word_0 102 NULL 2197605 Using index condition; Using where
1 SIMPLE staging_company_search ref name_word_0,name_word_1 name_word_1 102 const 128 Using index condition; Using where
1 SIMPLE staging_company_search ref name_word_0,name_word_1 name_word_0 102 const 33 Using index condition; Using where
数据库模式
CREATE TABLE `staging_company_search` (
`name_id` int(11) unsigned NOT NULL DEFAULT '0',
`name_word_0` varchar(100) NOT NULL,
`name_word_1` varchar(100) NOT NULL,
KEY `name_id` (`name_id`),
KEY `name_word_0` (`name_word_0`),
KEY `name_word_1` (`name_word_1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
答案 0 :(得分:2)
我不是专家,但我相信这是因为MySQL处理索引的方式,它必须检查几个条件(“OR”)。这可以在“解释查询”中看到,其中第一个查询需要在返回结果之前检查更多行。
我认为两个小结果的结合应该会有更好的表现。你能试试以下吗?
SELECT name_id
FROM staging_company_search
WHERE (name_word_0 = 'the' AND name_word_1 = 'glazier')
UNION ALL
SELECT name_id
FROM staging_company_search
WHERE (name_word_0 = 'bridgewaters' AND name_word_1 = '');
答案 1 :(得分:2)
您在第一个查询中使用OR子句会使您的索引失效。 MySQL有点愚蠢。它正在进行全表扫描:查看每一行。使用AND-only查询UNION一起好多了。
要使您的AND-only查询更快,请在(name_word_0, name_word_1, name_id)
上创建复合索引。通过对该索引的随机访问可以完全满足您的查询,并且应该使用两个megarow表以亚秒级运行。
答案 2 :(得分:2)
这是因为mysql只使用一个索引进行简单查询。
如果在多个索引之间有选择,MySQL通常会使用 找到最小行数的索引(最具选择性 索引)。
但是,从版本5.0到Index merge optimization,mysql可以并且将使用两个索引。不幸的是,它并不总是发生,即使它确实发生了结果aren't all that great。
第一个解释输出显示索引合并优化不会在您的查询中使用OR子句。它只使用name_word_0
name_word_0非常适合WHERE name_word_0 = 'the' AND name_word_1 = 'glazier';
,但正如第三个解释的输出所示,它根本不适合WHERE name_word_0 = 'bridgewaters' AND name_word_1 = '';
因此合并查询真的很慢。你可以通过创建一个跨越name_word_0和name_word_1的复合索引来克服这个问题。我注意到你的钥匙很长。你可以创建一个部分索引,并可能进一步加快速度。
CREATE INDEX word01 ON staging_company_search (name_word_0(20), name_word_1(20))