一、前言在MySQL中进行SQL优化的时候,在某些情况下,MySQL是否可以使用索引,往往会有一些困惑。例如:1、MySQL遇到范围查询条件就停止匹配,那么范围条件是什么?2、MySQL在LIKE进行模糊匹配时如何使用索引?3、MySQL在什么情况下可以使用索引进行排序?今天,我就用一个模型来一一解答这些问题,让你不再害怕使用MySQL索引。2.知识补充key_len在EXPLAIN执行计划中有一列key_len,用来表示本次查询中选择的索引的字节长度。通常,我们可以用它来确定在联合索引中选择了多少列。这里key_len大小的计算规则是:一般key_len等于索引列类型的字节长度,比如int类型是4字节,bigint是8字节;如果是字符串类型,需要同时考虑字符集因素,例如:CHAR(30)对于UTF8,key_len至少为90字节;如果列类型定义允许NULL,则其key_len需要增加1个字节;如果列类型是变长类型,比如VARCHAR(TEXT\BLOB不允许整列创建索引,如果创建部分索引也视为动态列类型),其key_len需要加上2字节;3.哪些条件可以使用索引?首先非常感谢邓波,给了我很好的启发。我通过了他的文章,结合自己的理解,做了这张图。数据范围其实就是MySQL索引中可以使用的部分,体现在KeyLength中。2.IndexFilter:MySQL用来判断哪些数据可以被索引过滤。启用ICP后,索引就可以使用了。3、表过滤:MySQL不能使用索引过滤。回表取行数据后,再到server层进行数据过滤。让我们展开。IndexKeyIndexKey用于确定MySQL的一个扫描范围,分为上边界和下边界。MySQL使用=、>=、>来确定下边界(第一个键)。使用最左原则,首先判断where条件中第一个索引键值是否存在。如果存在,则判断比较符号。如果是(=,>=),则添加下边界的定义,然后继续判断下一个索引键,如果存在且是(>),则将键值添加到下边界的定义中,并停止匹配下一个索引键;如果不存在,直接停止下界匹配。exp:idx_c1_c2_c3(c1,c2,c3)wherec1>=1andc2>2andc3=1-->firstkey(c1,c2)-->c1为'>=',添加下边界定义,继续匹配下-->c2如果是'>',加上下边界停止匹配。上边界(lastkey)与下边界(firstkey)类似,先判断是否为(=,<=)之一,如果是则添加边界,继续下一个索引键值匹配,如果是(<),加limit,停止匹配exp:idx_c1_c2_c3(c1,c2,c3)wherec1<=1andc2=2andc3<3-->firstkey(c1,c2,c3)-->c1为'<=',加上边界定义,继续匹配下-->c2为'=',添加上边界定义,继续匹配下-->c3为'<',添加上边界定义,停止匹配注意:这里简单记忆就是,如果比较符号中包含'=','>='也包含'=',则索引键可以使用,可以继续匹配后面的索引键值;如果不存在'=',即'>','<',这两个,后面的索引键值无法匹配。同时,上下界不能混用。哪个边界可以使用更多的索引键值就是最终可以使用的索引键值的数量。IndexFilter的字面理解就是可以使用索引来进行过滤。即该字段在索引键值中,但不能用于确定索引键的部分。exp:idex_c1_c2_c3wherec1>=1andc2<=2andc3=1indexkey-->c1indexfilter-->c2c3为什么这里的indexkey只有c1?因为c2是用来判断上边界的,但是上边界的c1没有出现(<=,=),而在下边界,c1是>=,c2也没有出现,所以indexkey只有c1场。c2和c3都出现在索引中,被认为是索引过滤器。TableFilter不能使用索引来完成过滤,所以只能使用tablefilter。此时引擎层会将行数据返回给服务器层,然后服务器层进行表过滤。4、Between和Like的处理那么如果查询中存在between和like,MySQL是如何处理的呢?Betweenwherec1between'a'and'b'等价于wherec1>='a'andc1<='b',所以做相应的替换,然后带入上层模型中确定上下边界Like首先需要确认的是,%不能在最左边,这里c1like'%a'不能使用索引,因为索引匹配需要遵守最左前缀原则wherec1like'a%'实际上是相当于wherec1>='a'andc1<'b'大家可以仔细想想。5、索引排序在数据库中,如果不能使用索引来完成排序,随着过滤数据量的增加,排序的成本也会增加。即使使用了limit,数据库也会选择对结果集进行排序,然后将排序后的limit记录取下来,而mysql针对可以用索引排序的limit进行了优化,这样更能降低成本。确保它使用索引在不扫描和排序完整结果集的情况下执行带有LIMIT的ORDERBY非常重要,因此使用索引对它来说很重要-在这种情况下,索引范围扫描将开始并停止查询执行一旦生成所需的行数。CREATETABLE`t1`(`id`int(11)NOTNULLAUTO_INCREMENT,`c1`int(11)NOTNULLDEFAULT'0',`c2`int(11)NOTNULLDEFAULT'0',`c3`int(11)NOTNULLDEFAULT'0',`c4`int(11)NOTNULLDEFAULT'0',`c5`int(11)NOTNULLDEFAULT'0',PRIMARYKEY(`id`),KEY`idx_c1_c2_c3`(`c1`,`c2`,`c3`))ENGINE=InnoDBAUTO_INCREMENT=8DEFAULTCHARSET=utf8mb4select*fromt1;+----+----+----+----+----+----+|id|c1|c2|c3|c4|c5|+----+----+----+----+----+----+|1|3|3|2|0|0||2|2|4|5|0|0||3|3|2|4|0|0||4|1|3|2|0|0||5|1|3|3|0|0||6|2|3|5|0|0||7|3|2|6|0|0|+----+----+----+----+----+----+7rowsinset(0.00sec)selectc1,c2,c3fromt1;+----+----+----+|c1|c2|c3|+----+----+----+|1|3|2||1|3|3||2|3|5||2|4|5||3|2|4||3|2|6||3|3|2|+----+----+----+7rowsinset(0.00sec)有一张表,c1,c2,c3上面有索引,selectc1,c2,c3fromt1;该查询使用索引的全扫描,所以呈现的数据等同于没有索引的结果selectc1,c2,c3fromt1orderbyc1,c2,c3;那么,索引的排序规则是怎样的呢?c1=3—>c2有序,c3无序c1=3,c2=2—>c3有序c1in(1,2)—>c2无序,c3无序有小规矩,idx_c1_c2_c3,那么如何判断某个字段是有序的吗?c1在索引的前面,一定是有序的,c2在第二个位置,只有当c1***确定一个值的时候,c2才是有序的,如果c1有多个值,那么c2就不是必须的井然有序。同样,c3也类似。已收录,如有问题请联系我
