唯一索引对更新操作来说都要先判断这个操作是否违反唯一性约束。而这个操作须要将数据页读入内存才能判断。如果到内存的话 直接更新会更快。所以唯一索引的更新就不需要使用change buffer ,实际上只有普通索引才需要。
写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时change buffer的使用效果最好。反过来读取频率高的话,每次写入之后立马要访问这个数据,会触发merge操作,这样随机访问io的次数并不会减少,反而会增加change buffer的维护代价。 但还是建议一般选择普通索引
merge的执行流程是这样的:
-
从磁盘读入数据页到内存(老版本的数据页);
-
从change buffer里找出这个数据页的change buffer 记录(可能有多个),依次应用,得到新版数据页;
-
写redo log。这个redo log包含了数据的变更和change buffer的变更。
redo log 主要节省的是随机写磁盘的IO消耗(转成顺序写),而change buffer主要节省的则是随机读磁盘的IO消耗。
10讲
MySQL在真正开始执行语句之前,并不能精确地知道满足这个条件的记录有多少条,而只能根据统计信息来估算记录数。这个统计信息就是索引的“区分度”。
显然,一个索引上不同的值越多,这个索引的区分度就越好。而一个索引上不同的值的个数,我们称之为“基数”(cardinality)。也就是说,这个基数越大,索引的区分度越好。
在MySQL中,有两种存储索引统计的方式,可以通过设置参数innodb_stats_persistent的值来选择:
- 设置为on的时候,表示统计信息会持久化存储。这时,默认的N是20,M是10。
- 设置为off的时候,表示统计信息只存储在内存中。这时,默认的N是8,M是16。
由于是采样统计,所以不管N是20还是8,这个基数都是很容易不准的。当变更的数据行数超过1/M的时候,会自动触发重新做一次索引统计。
对于由于索引统计信息不准确导致的问题,你可以用analyze table来解决。
索引选择异常和处理
- 采用force index强行选择一个索引。
- 可以考虑修改语句,引导MySQL使用我们期望的索引。
- 在有些场景下,我们可以新建一个更合适的索引,来提供给优化器做选择,或删掉误用的索引。
11讲
使用前缀索引(定义字符串的一部分作为索引),定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本。
前缀的区分度不够好的情况时,我们要怎么办呢
-
第一种方式是使用倒序存储。如果你存储身份证号的时候把它倒过来存。
select field_list from t where id_card = reverse('input_id_card_string'); 创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引; -
第二种方式是使用hash字段。你可以在表上再创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引。
alter table t add id_card_crc int unsigned, add index(id_card_crc);
然后每次插入新记录的时候,都同时用crc32()这个函数得到校验码填到这个新字段。
优劣:
- 倒序方式每次写和读的时候,都需要额外调用一次reverse函数,而hash字段的方式需要额外调用一次crc32()函数。如果只从这两个函数的计算复杂度来看的话,reverse函数额外消耗的CPU资源会更小些。
- 从查询效率上看,使用hash字段方式的查询性能相对更稳定一些。因为crc32算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近1。而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。
- 他们都不支持范围查询 , hash字段的方式也只能支持等值查询。