mysql怎么前缀索引 mysql前缀索引 排序( 二 )


2.前缀索引的创建规则为: alter table table T add index idx_email2( email(6) )
当然第一索引包含是的整个字符串,第二个是该字段前6个字节(注意是字节)
对于这2中索引,B+树怎么存储呢?
INSERT INTO T (email) VALUES ('瞎子','zhangsh1234@163.com'), ('剑圣','lisi1998883@163.com'), ('露娜','zhangssxyz@163.com'), ('李白','zhangsy1998@163.com'), ('韩信','zhaq5481993@163.com'), ('百里玄策','hhaq5481993@163.com');
【谁还不是个野王啊】
普通索引存储为:
是的你没看错,前缀索引那颗树上的存储的是email的前6位字节,也就是你创建前缀索引时指定的前缀字节长度 。2种树相比,前缀索引存储了更少的数据,那么他所耗费的空间也就相比较少,这正是他的一个优点 。同样的也就相对的增加了扫描行数 。
什么增加了扫描行数???? 这是为什么呢?
那么小朋友咱们一起来看下吧 。
假设SQL如此这般: select id,name,email from T where email = 'zhangsh1234@163.com'
那么这2个SQL,应该怎么操作呢 。
idx_email1:
2.到主键上查到主键为ID1的,判断email值是否正确【为什么判断呢,其实我理解是为了二次判断保证数据一致性吧 , 比较官方的解释尚未找到】,正确放入结果集
3.取 idx_email1 索引树上刚刚查到的位置的下一条记录,如此往复 。
循环过程中,需要回主键取1次数据 , 所以系统可以认为只扫描了一行【1次是数第一棵树数出来的】
idx_email2:
1.从 索引数上找到满足索引值为 'zhangs'的该记录 , 取得 ID1的值
2.到主键上查到主键值是 ID1 的行 , 判断出 email 的值是’ zhangsh1234@xxx.com ’,这行记录放入结果集【不是要的值,丢弃 , 进行下一步】
3.取 idx_email2 上刚刚查到的位置的下一条记录,重复以上步骤
在这个过程中,要回主键索引取 3 次数据,也就是扫描了 3 行 。通过这个对比,你很容易就可以发现,使用前缀索引后,可能会导致查询语句读数据的次数变多 。
但是,对于这个查询语句来说,如果你定义的 idx_email2 不是 email(6) 而是 email(8),也就是说取 email 字段的前 8 个字节来构建索引的话,即满足前缀’zhangsh’的记录只有一个,也能够直接查到 ID1,只扫描一行就结束了 。也就是说使用前缀索引 , 定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本 。
那么问题来了,到底定义多长才算是合理呢?
一般的定义原则是 count(distinct(columnName))/count(*) ,当前缀索引【count(distinct(columnName(length))),length是你想要创建列的前缀字节长度】越接近此值越好,当有多个前缀字节都一样且都等于这个值时怎么选择呢,当然是 字节越少越好了哈,字节越少越省空间 。索引选取的越长,占用的磁盘空间就越大 , 相同的数据页能放下的索引值就越少 , 搜索的效率也就会越低 。
count(distinct(columnName(length)))翻译到SQL 为: count(dictinct(left(colunmName, length)))
【mysql怎么前缀索引 mysql前缀索引 排序】 前面我们说了使用前缀索引可能会增加扫描行数,这会影响到性能 。其实,前缀索引的影响不止如此 , 我们再看一下另外一个场景 。
来呀,上SQL: select id,email from T where email='zhangsh1234@163.com'
如果按照email全字段索引,那么此SQL 是不需要回表的【为什么不需要回表?兄嘚,这个相当于覆盖索引了哈】
那么如果按照前缀索引是否需要回表呢?答案是的 。
因为当判断前6个字节相等后,需要拿到id 回表拿到email的全部内容进行比较,如果不相同,丢弃这行,否则加入结果集 。

推荐阅读