MySQL 索引相关知识
索引的选择
查询过程
普通索引:在查找满足条件的第一个记录后,查找下一个记录你,直到碰到不满足的条件的记录。
唯一索引:在查找第一个满足条件的记录后,就会停止继续检索。
更新过程
唯一索引的更新不能使用change buffer。而普通索引则可以。
索引的选择,两类索引在查询性能上没差别的,主要是考虑对更新的性能。推荐使用普通索引。
changebuffer
定义:当需要更新一个数据的时候,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB将会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入数据页了。在下次查询需要访问这个数据页的时候,将数据读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
作用:减少读磁盘,语句的执行速度会得到明显的提升 ,提高内存利用率。
change buffer的时使用场景:主要目的就是将记录的变更动作缓存下来,在一个数据页做merge之前,记录的越多,收益越大。对于写多读少的业务(例如:账单类、日志类)使用效果较好。但是对于写入之后马上会做查询的场景。由于更新之后马上会读取数据页,出发merge的过程,这样反而会增加change buffer的维护代价。
change buffer:是buffer poll里面的内存,可以通过innodb_change_buffer_max_size去设置。
changebuffer和 redo log的区别
redo log主要节省的是随机磁盘的IO消耗(转化顺序写),而change buffer主要节省的是随机读磁盘的IO的消耗。
MySQL索引的错误选择
优化器选择扫描行数、临时表,是否排序等因素综合找出一个最优的解决方案,用最小的代价去执行语句。
扫行行数:通过“区分度”来建立估算扫描行数,显然“基础”越大,索引的区分度越好。
通过show index from table 中cardinality属性可以得到区分度。
采用统计:InnoDB会默认选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到这个索引的基数。当变更行数超过1/M的时候,会自动触发重新做一次索引统计。
在MySQL中,有两种存储索引的统计方式,可通过innodb_stats_persistent的值来选择。
on:持久化存储。默认N是20,M是10。
off:内存。默认N是8,M是16。
索引选择异常和处理
1.采用force index强行选择索引。
2.修改语句,引导MySQL使用我们期望的索引。
3.在有些场景下,我们可以新建一个索引,提供给优化器做选择或者删除误用的索引。
字符串加索引
mysql> alter table SUser add index index1(email);
mysql> alter table SUser add index index2(email(6));
select id,name,email from SUser where email=’zhangssxyz@xxx.com’;
如果使用全索引
1.从index1索引树找到满足索引值”zhangssxyz”的这条记录,取得ID2的值
2.到主键查到主键值是ID2的行,判断email的值是否正确,将这行记录加入结果集
3.取index1索引树上刚刚查到的位置的下一条记录,发现不满足email=’zhangssxyz@xxx.com’的条件,循环结束。
使用部分索引
1.从index2 索引树找到满足索引值“zhangs”的记录,找到一个是ID!;
2.到主键查询主键值ID1的行,判断email的值不是“zhangsss@xxx.com”,丢弃。
3.取index2刚刚位置的下一条记录,发现仍然是“zhangs”,取出ID2,回表判断值是否正确,加入结果集
4.重复上述操作,直到在index2上取到的值不是“zhangs”时,循环结束
使用好前缀索引,定义好长度,就可以做好既节约空间,又不用额外增加太多的查询成本。
mysql> select
count(distinct left(email,4))as L4,
count(distinct left(email,5))as L5,
count(distinct left(email,6))as L6,
count(distinct left(email,7))as L7,
from SUser;
在L4-L7中,找出不小于L*95%的值。
使用前缀索引就用不上覆盖索引的查询性能的优化了。
字符串索引的劣势
对于区分度不高的场景,例如身份证前6位对于一个市、县区分度并不高的解决方案。
1.使用倒序存储
2.使用hash字段
hash字段和倒序存储的区别
1.倒序存储不消耗额外的空间,不需要新增hash字段。
2.自增hash字段的方式,倒序rerverse()相比hash函数的效率更高。
3.从查询效率上看,使用hash字段方式的查询性能相对稳定。
索引的失效
1.对索引字段做函数操作,可能会破环索引值的有序性,因此优化器就决定放弃走树搜索功能。
2.隐式的类型转换
3.隐式的字符编码转化