MySQL实战第三篇

怎么给字符串字段加索引

一些基本的解决方法:

1.直接创建完整索引,这样可能比较占用空间;

2.创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引;

3.倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题;

4.创建 hash 字段索引,查询性能稳定,有额外的存储和计算消耗,跟第三种方式一样,都不支持范围扫描。

采用整个字符串作为索引. 在查询操作时, 执行顺序是怎样的?

若使用的是整个字符串作为索引,则从索引树找到满足索引值的这条记录,取得 ID1的值;到主键上查到主键值是 ID 1的行,判断值是正确的,将这行记录加入结果集;取索引树上刚刚查到的位置的下一条记录,发现已经不满足条件了,循环结束。这个过程中,只需要回主键索引取一次数据,所以系统认为只扫描了一行。

采用部分字段做索引, 在查询操作时, 执行顺序是怎样的?

若采用的是前缀索引,则从索引树找到满足索引值的记录,找到的第一个是 ID1;到主键上查到主键值是 ID1 的行,判断出值不是’xxx’,这行记录丢弃;取上刚刚查到的位置的下一条记录,发现仍然是’xxx’,取出 ID2,再到 ID 索引上取整行然后判断,这次值对了,将这行记录加入结果集;重复上一步,直到在上取到的值不是’xxx’时,循环结束。在这个过程中,要回主键索引取 4 次数据,也就是扫描了 4 行。

使用什么语句可以分析不同长度前缀的索引区分度是多少?

首先,你可以使用下面这个语句,算出这个列上有多少个不同的值:

mysql> select count(distinct email) as L from SUser;然后,依次选取不同长度的前缀来看这个值,比如我们要看一下 4~7 个字节的前缀索引,可以用这个语句:

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;

前缀索引相比较整个字段做索引有什么优势和劣势?

优势:只要保证前缀长度的值的区分度越高,那么既可以做到节省空间,又可以做到不用额外增加太多查询的成本。

劣势:使用了前缀索引就用不上覆盖索引对性能的优化了,就算你前缀索引对索引的定义的长度为这个字符串的长度,当通过索引查询到那行数据后,InnoDB还是得回到id索引在插叙一次,因为系统不确定前缀索引是否截断了完整的信息。

采用反序存储和hash字段作为索引有什么异同点?

相同点是:都不支持范围查询。倒序存储的字段上创建的索引是按照倒序字符串的方式排序的,已经没有办法利用索引方式查出身份证号码在[ID_X, ID_Y]的所有市民了。同样地,hash 字段的方式也只能支持等值查询。

不同点:主要体现在以下三个方面:从占用的额外空间来看,倒序存储方式在主键索引上,不会消耗额外的存储空间,而 hash 字段方法需要增加一个字段。当然,倒序存储方式使用 4 个字节的前缀长度应该是不够的,如果再长一点,这个消耗跟额外这个 hash 字段也差不多抵消了。在 CPU 消耗方面,倒序方式每次写和读的时候,都需要额外调用一次 reverse 函数,而 hash 字段的方式需要额外调用一次 crc32() 函数。如果只从这两个函数的计算复杂度来看的话,reverse 函数额外消耗的 CPU 资源会更小些。从查询效率上看,使用 hash 字段方式的查询性能相对更稳定一些。因为 crc32 算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近 1。而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。