为什么这些MySQL查询在看起来等效时需要花费大量不同的时间来处理?

时间:2015-10-23 00:11:07

标签: mysql indexing

以下是三个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;

3 个答案:

答案 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))