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

T. *_*nes 5 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 = '');
Run Code Online (Sandbox Code Playgroud)

等价的集合查询(每个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 = '';
Run Code Online (Sandbox Code Playgroud)

解释这些问题

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
Run Code Online (Sandbox Code Playgroud)

数据库模式

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;
Run Code Online (Sandbox Code Playgroud)

e4c*_*4c5 2

这是因为mysql只使用一个索引来进行简单的查询。

如果在多个索引之间进行选择,MySQL通常会使用找到最少行数的索引(最具选择性的索引)。

然而,从5.0版本开始,mysql可以并且将会通过 索引合并优化来使用两个索引。不幸的是,这种情况并不总是发生,即使发生,结果也不是那么好

第一个解释输出显示在带有 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))
Run Code Online (Sandbox Code Playgroud)