繁体   English   中英

为什么mysql更喜欢扫描表而不是使用复合索引?

[英]why mysql prefer to scan the table rather than using composite index?

我有这张桌子:

商业:

bussId | x | y | bussStatus | 

我想运行此查询:

SELECT * FROM bussiness  WHERE  (bussiness.x BETWEEN 31.214857 AND 31.658529) AND (bussiness.y BETWEEN  34.502798 AND 34.918799) AND bussId > 500 AND bussStatus >0

EXPLAIN查询返回以下结果:

Id : 1
select_type : SIMPLE
table : bussiness
type : range
possible_keys : PRIMARY,bussStatus,xy,bussId_xy_status
key : PRIMARY
key_len : 4
ref : NULL
rows : 134680
Extra : Using where

这表明mysql选择使用PRIMARY键,尽管有一个复合索引bussId_xy_status可以对x,y,status和bussId进行排序!

这是您的查询:

SELECT b.*
FROM business b
WHERE (b.x BETWEEN 31.214857 AND 31.658529) AND
      (b.y BETWEEN 34.502798 AND 34.918799) AND
      b.bussId > 500 AND
      b.bussStatus > 0;

WHERE子句中的所有比较都是不平等的。 这意味着组合索引的用途非常有限-只有索引中的第一列可以最有效地使用。 优化程序已确定使用主键进行全表扫描最有效,这可能是由于bussid上的条件bussid MySQL 文档对复合索引及其使用方式进行了很好的回顾。

如果您需要进行这些类型的地理比较,则可以考虑使用空间索引-参见此处

编辑:

游民。 我参考的MySQL文档在解释多列索引方面做得还不够。 索引基本上提供两种访问功能:索引查找和索引扫描。 查找使索引可以转到正确的一组值。 索引扫描允许索引识别两个值之间的所有行。 (最常见的索引类型是支持这两种操作的B树索引。)

考虑一个表t,其索引为(a, b, c) 索引可被用于where子句当所有的比较是通过与连接和至少一个是上a 因此,该索引可用于:

where a = 'xyz'
where a > 'xyz'
where a in ('xyz', 'tbd')

首先是平等。 后两个是不等式,因为单个索引查找是不够的。

该索引通常不能用于:

where b = 'xyz'
where a = 'xyz' or b = 'xyz'

引入第二列会发生什么?

where a = 'xyz' and b = 'abc'
where a > 'xyz' and b = 'abc'
where a in ('xyz', 'tbd') and b = 'abc'

对于第一种情况,该索引可以被充分利用。 对于后两个,如果有的话,仅使用索引的“ a”部分。 优化器可能决定根本不使用索引,因为第一部分选择了太多行。

一般规则可以描述如下。 多列索引可用于具有以下条件的where子句:

  • where子句中的所有比较均通过AND连接。
  • 对于索引中的第一个“ n”键(“左前缀”),比较是相等的(即=IS NULL )。
  • n + 1键允许进行任何比较
  • “ n”可以等于零

该索引无法帮助在“ n + 1”键之后进行任何后续比较。 它可以以另一种方式提供帮助,这可以作为覆盖索引,但这是一个单独的主题。

在您的情况下,所有比较都是不等式,因此“ n”为0。只有索引中的第一个键可以被有效使用,并且优化器认为这样做的选择性不足以提高效率。

还要注意,只要列上有函数,就不会使用索引。 在您的情况下,这不是问题,但是很简单: a + 0 = 0 可以防止使用索引(我认为这个特定示例在不同的数据库中可能会有所不同)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM