理解MySQL中索引的顺序

理解MySQL中索引的顺序,mysql,database,indexing,Mysql,Database,Indexing,一个包含1000万条目的表中有3列。col1,col2,col3。col1存储最多2位数的数字,col2存储最多9位数的数字,col3存储0或1 现在,当我按col1、col2、col3的顺序组合索引时,我会得到一些select操作的结果,其中包含where条件中涉及的所有3列-指定col1和col3的精确值,而col2的范围约为0.5秒,而如果我将其按col3、col1、col2的顺序排序,则执行相同的查询需要大约10秒 据我所知,mysql中的索引按照我指定的顺序将3列中的值适当地连接起来,

一个包含1000万条目的表中有3列。col1,col2,col3。col1存储最多2位数的数字,col2存储最多9位数的数字,col3存储0或1

现在,当我按col1、col2、col3的顺序组合索引时,我会得到一些select操作的结果,其中包含where条件中涉及的所有3列-指定col1和col3的精确值,而col2的范围约为0.5秒,而如果我将其按col3、col1、col2的顺序排序,则执行相同的查询需要大约10秒

据我所知,mysql中的索引按照我指定的顺序将3列中的值适当地连接起来,并在初始排序后进行查询时运行二进制搜索。根据这种理解,在一开始提到col3应该与按照col1、col2、col3的顺序写它是等价的,因为如果我指定col3=1或col3=0,它将搜索范围缩小了一半


请解释一下异常现象

很难做出这样的决定,但就我个人而言,我会选择索引

INDEX `compound_index`(col1,col2,col3);
如果我没有进行范围扫描,我会创建

INDEX `compound_index`(col2,col1,col3);
as col2最有可能具有更好的基数

一般来说,如果没有表列的范围扫描,则具有更好的基数的列将成为索引的第一列,依此类推

如果您有范围扫描,松散索引扫描比覆盖索引效果更好

如果WHERE子句给出了col2的值范围,那么索引中col2之后的任何内容都不是很有用

如果不清楚,假设你在col1,col2,col3上建立索引,你的where子句是,col1=5,col2在2和4之间,col3=1。因此,SQL引擎最多可以转到索引中从col1=5、col2=2和col3=1开始的位置。理论上,它可以说当它到达col2=2的末尾,当它看到第一个col2=3,col3=0时,它可以跳到col2=3,col3=1。类似地,当它到达col2=4,col3=0时,它可以跳到col2=4,col3=1。但实际上,在指数中跳转相对较慢。引擎以块的形式读取索引,因此一旦它得到一个块,如果它按顺序搜索该块,它就已经在内存中拥有了所有的索引。但要跳过它,可能需要读取另一个块,这意味着额外的I/o操作。我想大多数SQL引擎都会说,一旦你给出了一个范围,索引中的所有内容都不会被使用。因此,引擎很可能会扫描从5,2到5,4的所有记录,并在运行时选择col3=1,而不是在索引中跳转

因此,当你说col3总是0或1时。我认为col1和col2的值范围更广?为了便于讨论,我们假设它们每个都有10个可能的值,并且col2上的范围包括3个值。让我们假设在所有值之间有一个相对均匀的分布-1和2的数量相等,等等

然后,如果在col1、col2、col3上建立索引,引擎可以使用col1立即将搜索范围缩小到索引的10%,使用col2将搜索范围缩小到索引的30%或总数的3%

如果在col3、col2、col1上建立索引,那么引擎可以使用col3将搜索范围缩小到索引的50%,col2缩小到索引的30%,或15%

选项b的引擎搜索的索引是选项1的5倍。所以是的,它会慢一些