索引和查询优化
添加索引的三种方法
一、Alter table 表名 add 键类型 (列列表)
键类型:primary key/unique key/fulltext index/index(普通索引可以在index后接索引名)
二、建表时在列名 类型 后加索引类型
三、建表时在所有列名后面加索引类型(列列表)
(全文索引是为了解决like%这种效率低的查询方式提出的查询优化)
索引的原理
索引的存在就是为了加快查询速度的。每个行记录按照主键大小顺序排列在一个页中,形成一个单链表,每个页都有一个页面目录,页面目录把记录分成多组记录每组的末尾地址,这样在页中查找记录时就可以采用二分法的方式。页与页之间按照主键顺序形成一个双向链表,非叶子节点的页每条记录是页编号和页最小主键值,同一层次的页也按照主键排列形成双向链表,这就是一颗B+树,也就是主键索引生成的树称为聚簇索引,叶子节点记录着完整的信息。如果表中有个列叫score,想按照分数建立索引就会生成一颗二级索引,记录按照分数大小排列,树叶子节点记录分数值、主键值,非页节点记录分数、主键、页号,查询时先根据分数的范围查到主键值,然后根据主键值回表去聚簇索引查完整的记录。Innodb索引就是这样的,二级索引都需要回表,完整的记录在聚簇索引中,而myISAM索引不是,myISAM数据都存在一个文件里,按照插入顺序排列,索引另外存在其他文件,主键索引文件叶子节点保存的是数据的主键值和行号,然后根据行号再去数据文件里寻找对应的记录,相当于所有的索引都需要回表,所有的索引都是二级索引。
使用索引的技巧
1、命中索引:全值匹配(可以不按顺序)、最左前缀(把能过滤重复值较多的放在前面)、前缀匹配、不将列放入函数中、不带表达式
2、自动生成主键索引和唯一键索引:按它们查效率高
3、在二级索引中查到主键值是顺序IO,回表是随机IO,效率低,尽量降低回表数,或者干脆查二级索引叶子节点的信息(覆盖索引),这样就不用回表了。增加限制条件如limit限制回表数否则索引会失效,查询优化器会用全表扫描。
4、列的类型尽量选择小的,尤其是主键和索引列,内存中会存多份
5、避免重复索引和冗余索引。重复索引是有主键或唯一键索引又重复建立或建立两次索引,冗余索引是建立了联合索引没有必要建立联合索引的最左部分的索引。
(索引不是越多越好,索引增加会降低update、delete和insert的效率)
查询优化
单表查询的几种级别:const(主键或唯一键等值条件)、ref(普通索引等值条件)、ref-or-null、range(索引范围搜索)、index(覆盖索引)、all(全表扫描)
用explain来查看查询执行的方法,单表查询的方法不能是all,至少要优化到range。
1、命中索引
2、判断条件不加null,因为null值是不受限制的,不会用二分法加速查询过程,导致放弃索引(这个观点是错的,where中主键加null是自动优化为false的,非主键加null条件会自动搜索列中最小的位置寻找null)
3、慎用一些低效的符号,or,in,not in
4、用exists子查询代替in子查询可能命中索引
优化手段是因地制宜的,自动选择查询方案是mysql的特性,不同的情况很多定律也不那么适用。
Limit a b分页语句的执行速度很慢,原因在于它是读a+b个数据,然后取最后b个这样的查找方式,改进方法有以下几个:
1、加order by id limit a,b 利用索引,id也可以换成其他索引
2、先找到第一个数据然后用where条件筛选末尾跟limit b,这样只读b条数据
3、尽量使用覆盖索引,只查二级索引的内容,不回表