find_in_set不利⽤索引_10分钟让你明⽩MySQL是如何利⽤索
引的
⼀、前⾔
在MySQL中进⾏SQL优化的时候,经常会在⼀些情况下,对 MySQL 能否利⽤索引有⼀些迷惑。
譬如:
1. MySQL 在遇到范围查询条件的时候就停⽌匹配了,那么到底是哪些范围条件?
2. MySQL 在LIKE进⾏模糊匹配的时候⼜是如何利⽤索引的呢?
3. MySQL 到底在怎么样的情况下能够利⽤索引进⾏排序?
今天,我将会⽤⼀个模型,把这些问题都⼀⼀解答,让你对MySQL索引的使⽤不再畏惧
⼆、知识补充
key_len
下载mysql为什么下载不了EXPLAIN执⾏计划中有⼀列 key_len ⽤于表⽰本次查询中,所选择的索引长度有多少字节,通常我们可借此判断联合索引有多少列被选择了。
在这⾥ key_len ⼤⼩的计算规则是:
⼀般地,key_len 等于索引列类型字节长度,例如int类型为4 bytes,bigint为8 bytes;
如果是字符串类型,还需要同时考虑字符集因素,例如:CHAR(30) UTF8则key_len⾄少是90 bytes;
若该列类型定义时允许NULL,其key_len还需要再加 1 bytes;
若该列类型为变长类型,例如 VARCHAR(TEXTBLOB不允许整列创建索引,如果创建部分索引也被视为动态列类型),其key_len还需要再加 2 bytes;
三、哪些条件能⽤到索引?
⾸先⾮常感谢登博,给了我⼀个很好的启发,我通过他的⽂章,然后结合⾃⼰的理解,制作出了这幅图
乍⼀看,是不是很晕,不急,我们慢慢来看
图中⼀共分了三个部分:
1. Index Key :MySQL是⽤来确定扫描的数据范围,实际就是可以利⽤到的MySQL索引部分,体现在Key Length。
2. Index Filter:MySQL⽤来确定哪些数据是可以⽤索引去过滤,在启⽤ICP后,可以⽤上索引的部分。
3. Table Filter:MySQL⽆法⽤索引过滤,回表取回⾏数据后,到server层进⾏数据过滤。
我们细细展开。
Index Key
Index Key是⽤来确定MySQL的⼀个扫描范围,分为上边界和下边界。
MySQL利⽤=、>=、> 来确定下边界(first key),利⽤最左原则,⾸先判断第⼀个索引键值在where条件中是否存在,如果存在,则判断⽐较符号,如果为(=,>=)中的⼀种,加⼊下边界的界定,然后继续
判断下⼀个索引键,如果存在且是(>),则将该键值加⼊到下边界的界定,停⽌匹配下⼀个索引键;如果不存在,直接停⽌下边界匹配。
exp:idx_c1_c2_c3(c1,c2,c3)where c1>=1 and c2>2 and c3=1--> first key (c1,c2)--> c1为 '>=' ,加⼊下边界界定,继续匹配下⼀个-->c2 为'>',加⼊下边界界定,停⽌匹配
上边界(last key)和下边界(first key)类似,⾸先判断是否是否是(=,<=)中的⼀种,如果是,加⼊界定,继续下⼀个索引键值匹配,如果是(
exp:idx_c1_c2_c3(c1,c2,c3)where c1<=1 and c2=2 and c3<3--> first key (c1,c2,c3)--> c1为 '<=',加⼊上边界界定,继续匹配下⼀个--> c2为'='加⼊上边界界定,继续匹配下⼀个--> c3 为 '
注:这⾥简单的记忆是,如果⽐较符号中包含’=’号,’>=’也是包含’=’,那么该索引键是可以被利⽤的,可以继续匹配后⾯的索引键值;如果不存在’=’,也就是’>’,’
Index Filter
字⾯理解就是可以⽤索引去过滤。也就是字段在索引键值中,但是⽆法⽤去确定Index Key的部分。
exp:idex_c1_c2_c3where c1>=1 and c2<=2 and c3 =1index key --> c1index filter--> c2 c3
注:这⾥简单的记忆是,如果⽐较符号中包含’=’号,’>=’也是包含’=’,那么该索引键是可以被利⽤的,可以继续匹配后⾯的索引键值;如果不存在’=’,也就是’>’,’
Index Filter
字⾯理解就是可以⽤索引去过滤。也就是字段在索引键值中,但是⽆法⽤去确定Index Key的部分。
exp:idex_c1_c2_c3where c1>=1 and c2<=2 and c3 =1index key --> c1index filter--> c2 c3
这⾥为什么index key 只是c1呢?因为c2 是⽤来确定上边界的,但是上边界的c1没有出现(<=,=),⽽下边界中,c1是>=,c2没有出现,因此index key 只有c1字段。c2,c3 都出现在索引中,被当做index filter.
Table Filter
⽆法利⽤索引完成过滤,就只能⽤table filter。此时引擎层会将⾏数据返回到server层,然后server层进⾏table filter。
四、Between 和 Like 的处理
那么如果查询中存在between 和like,MySQL是如何进⾏处理的呢?
Between
where c1 between 'a' and 'b'等价于 where c1>='a' and c1 <='b',所以进⾏相应的替换,然后带⼊上层模型,确定上下边界即可。
Like
⾸先需要确认的是%不能是最在最左侧,where c1 like '%a' 这样的查询是⽆法利⽤索引的,因为索引的匹配需要符合最左前缀原则
where c1 like 'a%' 其实等价于 where c1>='a' and c1 ⼤家可以仔细思考下。
五、索引的排序
在数据库中,如果⽆法利⽤索引完成排序,随着过滤数据的数据量的上升,排序的成本会越来越⼤,即使是采⽤了limit,但是数据库是会选择将结果集进⾏全部排序,再取排序后的limit 记录,⽽且 MySQL 针对可以⽤索引完成排序的limit 有优化,更能减少成本。
Make sure it uses index It is very important to have ORDER BY with LIMIT executed without scanning and sorting full result set, so it is important for it to use index – in this case index range sca
n will be started and query execution stopped as soon as soon as required amount of rows generated.
存在⼀张表,c1,c2,c3上⾯有索引,select c1,c2,c3 from t1; 查询⾛的是索引全扫描,因此呈现的数据相当于在没有索引的情况下select
c1,c2,c3 from t1 order by c1,c2,c3; 的结果
因此,索引的有序性规则是怎么样的呢?
c1=3 —> c2 有序,c3 ⽆序
c1=3,c2=2 — > c3 有序
c1 in(1,2) —> c2 ⽆序 ,c3 ⽆序
有个⼩规律,idx_c1_c2_c3,那么如何确定某个字段是有序的呢?c1 在索引的最前⾯,肯定是有序的,c2在第⼆个位置,只有在c1唯⼀确定⼀个值的时候,c2才是有序的,如果c1有多个值,那么c2 将不⼀定有序,同理,c3也是类似
六、⼩结
针对MySQL索引,我这边只是提到了在单表查询情况下的模型,通过这篇⽂章,想必⼤家应该了解到MySQL⼤部分情况下是如何利⽤索引的,如果存在疑问,欢迎联系我。
你「在看」吗?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论