索引分析
1.单表的优化:
上面的注释已经提到了 BTree 索引的工作原理,在一个联合索引中,按照创建索引时的字段的顺序,来为其进行排序
select a,b from t1 where x = 1 and y > 1 order by z ;联合索引为(x,y,z),x,z给出了一个确切的值,y给出的是一个范围,
我们 explain它,会有 using filesort,这是因为 y > 1条件是一个范围值,虽然也会用到索引,用到的是索引的排序,而不是查询。
而且因为y的值给得不准确,y确定不了,就找不到z,所以z不会用到索引,要通过z去排序,又没有索引用,所以MySQL 只能自己进行文件内排序filesort
2.多表的优化(Join 语句的优化)
1.尽可能减少Join语句中的 NestedLoop的循环总次数:"永远用小结果集驱动大的结果集"
2.优先优化NestedLoop的内层循环
3.保证Join语句中被驱动表上的Join条件字段已经被索引
4.当无法保证被驱动表的Join条件字段被索引且内存资源充足的前提下,不要太吝啬 JoinBuffer的设置
如:select * from class left join book on class .card =book.card left join phone on book.card = phone.card,
因为这条select的执行顺序是,先查询class表,再查询book,再查询phone
这是一个 三表连接,按照上面的原则,class表应该是最小的,phone 表应该是最大的,用class 去驱动 book,用book驱动phone,
而且需为被驱动的表上的join条件字段添加索引,
原理:这里是left join,需为右边那张表的连接字段添加索引,因为左连接 左边那张表应该全部包含进来,右边那张表只进来重合的那部分,
即右边有的,左边一定有,这样的话,右边为公共区域,更加关键,所以一定要为右边建立索引,这里就是要为book.card 和 phone.card 建立
索引失效(如何避免)
要实验的话,select 后面的 字段需要不满足 覆盖索引,不然的话,索引不会失效,还是会用到覆盖索引
1.全值匹配我最爱
2.最佳左前缀法则 如果索引了多列,要遵循最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列
(是where 后面字段的顺序需遵循,和select 后面的字段无关,select 后面的字段只会影响该索引是否为覆盖索引)
3.不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
4.存储引擎不能使用索引中范围条件右边的列
5.尽量使用 覆盖索引(只访问索引的查询(索引列和查询列一致)减少 select *)
6.mysql 在使用 不等于(!=或者<>)的时候无法使用索引,会导致全表扫描
7.使用is null,is not null 也无法使用索引
8.like 以通配符开头('%abc...')mysql 索引失效会变成全表扫描的操作
原因分析:一开始就以 % 开头,会导致无法准确定位,无法通过索引找到那个值
解决办法:1.将 % 放到后面 (不完善) 2.使用覆盖索引,(如果用到了覆盖索引,并且需要模糊查询的字段在覆盖索引中)
9.字符串不加 ‘ ’ ,索引失效
10.少用 or,用它来连接时索引失效
优化口诀总结:
全值匹配我最爱,最左前缀要遵守
带头大哥不能死,中间兄弟不能断
索引列上少计算,范围之后全失效
LIKE百分写最右,覆盖索引不写 *
不等空值还有or,索引失效要少用
VAR引号不可丢 ,SQL高级也不难
感觉不算特别准确,补充自己的总结
explain select * from newslabel where name = 'CBA' and pid = 1; i dx(pid,name)
1.首先关于 select 后面的字段,如果建立的复合索引完全包含后面的,那么就是覆盖索引,
这里很多案例都不会失效,因为覆盖索引没有失效
2.where 后面的 条件,索引的第一个必须要有(pid),后面的随意,(即带头大哥不能死,中间兄弟无所谓)
可以不按照索引建立的顺序来书写,MySQL会优化,还是会用到索引,但是最好按序写查询条件
3.关于 order by 和 group by,必须严格按照索引建立时的顺序,即 idx(pid,name,age)前提下,必须写成
select * from newslabel where pid = 1 and name = 'CBA' order by age,
(这时就是带头大哥不能死,age 和 pid之间的中间兄弟不能断)
即age前面的被索引了的查询字段需为常量((where = ‘常量’ ),age前面的字段为常量,自然就不需要排序了),有了前面的准确位置,age才能使用index排序,不出现 filesort
或者如果不写 where 对 使age前面的列生效的话,就必须按序写成 order by pid,name,age
原因:可以参照 联合索引 BTree 的原理,因为创建树的时候就是通过第一列的值,在第一列的值相同的情况下,再对第二列进行排序放到 树中,
所以需要通过第一列的值去检索第二列的值,
一般性建议:
1.对于单键索引,尽量选择针对当前 query 过滤性更好的索引
2.在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好
3.在选择组合索引的时候,尽量选择可以包含当前query中的 where 字句中更多字段的索引
4.尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的