mysql - 如果 MySQL 对 AND 条件使用索引,为什么或何时不对 OR 条件使用索引?

标签 mysql sql indexing query-optimization explain

我有一个表the_table,其属性为the_table.idthe_table.firstValthe_table.secondVal(主键当然是 the_table.id)。

在第一个非键属性上定义索引后,如下所示:

CREATE INDEX idx_firstval  
ON the_table (firstVal);

以下析取 (OR) 查询的 EXPLAIN 结果

SELECT * FROM the_table WHERE the_table.firstVal = 'A' OR the_table.secondVal = 'B';

| id    | select_type | table     | type    | possible_keys | key   | key_len   | ref   | rows  | Extra
| 1     | SIMPLE      | the_table | ALL     | idx_firstval  | NULL  | NULL      | NULL  | 3436  | Using where

这表明索引idx_firstval未被使用。现在,以下联合 (AND) 查询的 EXPLAIN 结果

SELECT * FROM the_table WHERE the_table.firstVal = 'A' AND the_table.secondVal = 'B';

| id    | select_type   | table     | type  | possible_keys | key           | key_len   | ref   | rows  | Extra 
| 1     | SIMPLE        | the_table | ref   | idx_firstval  | idx_firstval  | 767       | const | 124   | Using index condition; Using where

这显示了这次正在使用的索引。

为什么MySQL 选择不在析取查询中使用索引,而在连接查询中使用索引?

我已经搜索过了,正如this thread中的答案所建议的那样,“在查询中使用 OR 通常会导致查询优化器放弃使用索引查找并恢复到扫描”。然而,这并不能回答为什么会发生这种情况,而只是回答它确实发生了。

Another thread试图回答为什么析取查询不使用索引,但我认为它这样做失败了 - 它只是得出结论,OP正在使用一个小型数据库。我想知道析取和连接情况之间的区别

最佳答案

因为MySQL执行计划只对一张表使用一个索引。

如果 MySQL 对 idx_firstval 使用范围扫描来满足 firstVal 列上的相等谓词,那么 MySQL 仍需要检查 secondVal 上的条件专栏。


使用AND,MySQL只需要检查索引范围扫描返回的行。需要检查的行集受条件约束。


使用OR,MySQL需要检查索引范围扫描未返回的行,以及表中的所有其余行。如果没有索引,则意味着对表进行全面扫描。如果我们对表进行完整扫描来检查 SecondVal,那么检查扫描中的两个条件(即包含索引访问和完整访问的计划)的成本会更低。扫描会更贵。)

(如果包含firstVal和secondVal的复合索引可用,那么对于OR查询,可以想象优化器可能认为通过执行以下操作来检查表中的所有行的成本较低全索引扫描,然后查找数据页。)


当我们了解优化器可以执行哪些操作时,我们就可以避免使用 OR 并重写查询,以返回等效的结果集,并使用更明确定义组合的查询模式两套

SELECT a.*
  FROM the_table a
 WHERE a.firstVal = 'A'

UNION ALL

SELECT b.*
  FROM the_table b
 WHERE b.secondVal = 'B'
   AND NOT ( b.firstVal <=> 'A' )

(如果我们希望按特定顺序返回行,请添加 ORDER BY)

关于mysql - 如果 MySQL 对 AND 条件使用索引,为什么或何时不对 OR 条件使用索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61596458/

相关文章:

Mysql,如何找到矩形边界的交集

mySQL LIKE 管道上的查询

C:创建索引,我做错了什么?

java - SQL 错误 : 933, SQLState: 42000 和 ORA-00933: SQL 命令未正确结束

mysql - 根据 MySQL 中的 WHERE 子句创建具有不同值的重复更新

r - 使用df [col]访问列给出:错误 'x'对于 'sort.list'必须是原子的

sql - Postgres where查询优化

mysql - 结果中出现重复行

mysql - 如何修复迁移 Laravel 中的 'error : SQLSTATE[HY000]'

mysql - 如何使用 MySQL 批量更新(从选择中)