索引优化应该是针对查询性能优化最有效的手段了。
索引基础
mysql只能高效的使用最左边的前缀列,创建一个包含两列的索引和创建两个只包含一列的索引是打不相同的:
ORM无法有效处理索引。
索引的类型
B-Tree索引
大多数索引使用的是此类型索引(innodb使用的B+Tree);
适用情况:全值匹配、匹配最左前缀、匹配列前缀、匹配范围值、精确匹配某一列并匹配另外一列、只访问索引的查询、前面order by的情况;
应用限制:无法索引最多列的查询、不能跳过索引列、如果某列是范围查询,则右边列无法使用索引优化查找。
哈希索引
通过计算列值的hash作索引,memory可显式支持哈希索引,如有重复值,链表存放。
索引结构紧凑,速度很快,但是也有限制:
> 因为只保存hash和行指针,所以必须要再读取行;
> 不是按索引值顺序存储,所以也无法用于排序;
> 无法支持部分查找;
> 只支持等值比较查询;
> 如果哈希冲突,则需遍历链表,冲突越多,代价越大。
如果有必要,可以创建自定义哈希索引,CRC32[FNV64]函数生成哈希保存(触发器更新更方便)SHA1和md5生成的字符串效率要低很多。
多么简单的一条语句:
select conv(right(md5(‘www.mysql.com’),16),16,10) as hash64
空间数据索引R-TREE
Myisam表支持空间索引,无需要前缀查询,但是支持不够完善。
全文索引
适用于匹配二非where,后续章节详细讨论。
其他索引
聚簇索引、覆盖索引等。
索引的优点
> 大大减少了服务器需要扫描的数据量;
> 帮助服务器避免排序和临时表;
> 将随机IO变为顺序IO。
太小的表:全盘扫描更高效;中大型表,索引很有效;超大型表,就要考虑代价了(分区技术、块级元数据等更好些)。
高性能的索引策略
独立的列
select * from table where field+1=5 无法使用索引
前缀索引和索引选择性
足够长的前缀保证较高的选择性,又不能太长(空间太大);
计算方法:select count(distinct left(city,3))/count() as c1,count(distinct left(city,4))/count() as c2 from table
优点:更小更快的索引;
缺点:无法order by和group by,也无法使用前缀索引做覆盖索引。
多列索引
> 多个索引做相互操作时,需要一个包含所有相关列的多列索引。
> 多个索引做联合操作时,通常会耗费大量CPU和内存资源在算法的缓存、排序和合并操作上。
选择合适的索引顺序
多列B-Tree索引,索引列的顺序意味着索引首先按照最左列排序,其次是第二列等等。多列索引顺序至关重要。
经验法则:不考虑排序和分组时,将选择性最高的列放到索引最前列。
聚簇索引
并不是索引类型,是一种数据存储方式。因为聚簇索引就是索引的表
myisam中主键索引与普通索引的区别就是唯一非空索引;innodb中,主键是聚簇索引,二级索引则不是。
顺序主键肯定是要比随机主键有更好的性能,但是在高并发情况下,可能导致auto_increment的争用。
覆盖索引
如果一个索引包含所有需要查询的值,我们就称之为覆盖索引;
只有b-tree索引可以,也不是所有的引擎都支持覆盖索引
使用索引扫描来做排序
如果一个索引即满足排序又满足查找行,这样是最好的;索引顺序和order by 完全一致时,才能够使用索引来做结果排序;关联多张表,第一张表order by才有效(常量条件也可以,但范围条件不行)。
压缩索引
myisam支持,通常是对字符串压缩。方法:第二个的值使用数字替换相同字符串表示。但是查找变慢,尤其是倒序扫描。create table时指定pack_keys时可指定压缩方式。
冗余和重复索引
(A,B)的索引包含(A)的索引,通常不需要在给A设置索引,但是为了适应更好的查询,有时可以有重复索引。
未使用的索引
使用工具分析:打开userstates变量分析使用频率来移除未使用的索引。
索引和锁
索引理论上可以减少锁的使用。
案例
支持多种过滤条件:通常把范围查询列放到索引的最后,使用in()来避免被略过的列而无法使用索引,但是in不应该太多。
避免多个范围条件:范围条件后即无法再使用索引了(尽可能将范围编程等值查询)mysql以后支持松散索引扫描的话则就不必在乎in的使用了。
优化排序:对于limit大慢的问题:用户无法看到很靠后的结果或者延迟关联(select cols from t inner join (select <primary key cols> from profiles where ..order.. limit 10000,10)as x using(primary key cols))
维护索引和表
myisam使用的精确计数;innodb使用的估算,在变化超过十六分之一时或插入20亿数据时会触发重新统计。
减少索引和磁盘的碎片
数据存储的碎片比索引更加复杂。行碎片、行间碎片、剩余空间碎片。
innodb因为会移动短小的行并重写到一个片段中所以不会出现短小的行碎片。
通常可以使用:optimize table 导出导入 删除索引创建索引。