目录

  • 什么是前缀索引
  • 什么是索引选择性
  • 创建前缀索引
    • 数据库脚本
    • 获取前缀长度 `prefix_length`
    • 创建前缀索引
  • 前缀索引测试
  • 前缀索引与覆盖索引
  • 小结

什么是前缀索引

所谓前缀索引:说白了就是对文本的前几个字符建立索引(具体是几个字符在建立索引时指定),这样建立起来的索引更小,所以查询更快。这有点类似于 Oracle 中对字段使用 Left 函数来建立函数索引,只不过 MySQL 的这个前缀索引在查询时是内部自动完成匹配的,并不需要使用 Left 函数

那么为什么不对整个字段建立索引呢?一般来说使用前缀索引,可能都是因为整个字段的数据量太大,没有必要针对整个字段建立索引,前缀索引仅仅是选择一个字段的部分字符作为索引,这样一方面可以节约索引空间,另一方面则可以提高索引效率,当然很明显,这种方式也会降低索引的选择性

这里又涉及到一个概念,什么是索引选择性?

什么是索引选择性

关于索引的选择性,它是指不重复的索引值和数据表的记录总数的比值,取值范围在 [0,1] 之间。索引的选择性越高则查询效率越高,因为选择性高的索引可以让 MySQL 在查找时过滤掉更多的行

那是不是选择性越高的索引越好呢?当然不是!索引选择性最高为 1,如果索引选择性为 1,就是唯一索引了,搜索的时候就能直接通过搜索条件定位到具体一行记录!这个时候虽然性能最好,但是也是最费空间的,这不符合我们创建前缀索引的初衷

我们一开始之所以要创建前缀索引而不是唯一索引,就是希望能够在索引的性能和空间之间找到一个平衡,我们希望能够选择足够长的前缀以保证较高的选择性(这样在查询的过程中就不需要扫描很多行),但是又希望索引不要太过于占用存储空间

那么我们该如何选择一个合适的索引选择性呢?索引前缀应该足够长,以便前缀索引的选择性接近于索引的整个列,即前缀的基数应该接近于完整列的基数

  • 首先可过如下 SQL 得到全列选择性
SELECT COUNT(DISTINCT column_name) / COUNT(*) FROM table_name;
  • 然后再通过如下 SQL 得到某一长度 prefix_length
SELECT COUNT(DISTINCT LEFT(column_name, prefix_length)) / COUNT(*) FROM table_name;

在上面这条 SQL 执行的时候,我们要注意选择合适的 prefix_length,直至计算结果最接近于全列选择性的时候,就是最佳结果了,然后使用这个 prefix_length 就可以创建前缀索引了

创建前缀索引

数据库脚本

数据库脚本我们使用的是 mysql 官方提供的示例数据库,下载地址如下:http://downloads.mysql.com/docs/sakila-db.zip,下载解压如下所示


我们选择 city 表作为测试表(此处我将 city 表名改为了 city_demo),表结构及数据分别在上面的 sql 文件中,并选择 city 列来创建前缀索引

获取前缀长度 prefix_length

  • 首先我们通过如下 SQL 来获取一下 city 全列的索引选择性,结果如下
SELECT COUNT(DISTINCT city) / COUNT(*) FROM city_demo;


可以看到,结果为 0.9983。全列选择性为 0.9983 说明这一列的值还是有重复的

  • 接下来我们获取前缀长度 prefix_length,这里一共测试了 8 个不同的 prefix_length,来看看各自的选择性
SELECT COUNT(DISTINCT LEFT(city,7))/COUNT(*) AS pref7,COUNT(DISTINCT LEFT(city,8))/COUNT(*) AS pref8,COUNT(DISTINCT LEFT(city,9))/COUNT(*) AS pref9,COUNT(DISTINCT LEFT(city,10))/COUNT(*) AS pref10,COUNT(DISTINCT LEFT(city,11))/COUNT(*) AS pref11,COUNT(DISTINCT LEFT(city,12))/COUNT(*) AS pref12,COUNT(DISTINCT LEFT(city,13))/COUNT(*) AS pref13,COUNT(DISTINCT LEFT(city,14))/COUNT(*) AS pref14
FROM city_demo;


很明显,这里的前缀长度 prefix_length14,接下来创建前缀索引

创建前缀索引

alter table city_demo add index city_index(city(14));

前缀索引测试

使用如下 SQL 查看其执行计划,结果如下

EXPLAIN select * from city_demo where city = 'Kamjanets-Podilskyi';


可以看到,这个前缀索引已经用上了,具体搜索流程是这样

  • city_index 索引中找到第一个值为 Kamjanets-Podi 的记录(city 的前 14 个字符)

  • 由于 city_index 是普通索引,叶子结点保存的是主键值,所以此时拿到了主键值,如 ID1

  • 到主键索引树上查到 ID1 这一行,判断 city 的值满不满足 where 后的条件,不满足这一行丢弃

  • 继续回到 city_index 这个索引树上查下一条记录,发现如果还是 Kamjanets-Podi,取出 ID2,再回到主键索引树上进行判断,如果值正确,将结果返回结果集中

  • 重复执行以上流程,直到从 city_index 索引树上取出的数据不是 Kamjanets-Podi,循环结束

如果我们建立了前缀索引并且前缀索引的选择性为 1,那么就不需要第 5 步了,如果前缀索引选择性小于 1,就需要第 5 步。既节省了空间,又提高了搜索效率

前缀索引与覆盖索引

使用了前缀索引后,我们来看一个查询 SQL

EXPLAIN select city from city_demo where city = 'Kamjanets-Podilskyi';

  • 如上的 SQL 查询的列是 city,在前缀索引中 B+Tree 里保存的根本就不是完整的 city 字段的值,必须要回表才能拿到需要的数据。所以,用了前缀索引,就用不了覆盖索引了

小结

  • 前缀索引是一种能使索引占用空间更小,查询速度更快的有效办法,但另一方面也有其缺点:mysql 无法使用其前缀索引做 ORDER BYGROUP BY,用了前缀索引,就用不了覆盖索引了
  • 要明确使用前缀索引的目的与优势
    • 大大节约索引的占用空间,从而提高索引效率
    • 对于 BOLB 、TEXT 或者很长的 VARCHAR 类型的列,必须使用前缀索引,因为 MySQL 不允许索引这些列的完整长度
  • 真正的难点在于:要选择足够长的前缀以保证较高的选择性,同时又不能太长, 前缀的长度应该使前缀索引的选择性接近索引整个列,即前缀的基数应该接近于完整列的基数

参考:https://blog.csdn.net/qq_43672652/article/details/106156353
参考:https://blog.csdn.net/dhrome/article/details/72853153

mysql之前缀索引相关推荐

  1. MySQL的前缀索引及Oracle的类似实现

    MySQL有一个很有意思的索引类型,叫做前缀索引,它可以给某个文本字段的前面部分单独做索引,从而降低索引的大小. 其实,Oracle也有类似的实现,对于文本,它可以通过substr的函数索引,实现同样 ...

  2. MySQL字符串前缀索引详解

    MySQL字符串前缀索引详解 1. 前缀索引与全部索引概念 2. 前缀索引与全部索引数据结构 3. 前缀索引与全部索引引执行流程 4. 前缀索引长度如何取舍 5. 前缀索引对覆盖索引的影响 6. 其他 ...

  3. mysql 建前缀索引_MySQL_前缀索引_建立

    -- 查看出现频率 select count(*) as cnt,city from sakila.city_demo group by city order by cnt desc limit 10 ...

  4. mysql创建前缀索引

    ALTER table 表名 add index title_pre(列名(100)) 列名后面的数字代表前缀的长度,前缀长度并不是越长越好,这里涉及到一个选择性问题, select count(di ...

  5. mysql优化之前缀索引--带案例分析

    为什么要有前缀索引 有时候需要索引很长的字符串,这会让索引变的大且慢,通常情况下可以使用某个列开始的部分字符串,这样大大的节约索引空间,从而提高索引效率,但这会降低索引的选择性,索引的选择性是指不重复 ...

  6. MySQL性能调优与设计——MySQL中的索引

    MySQL中的索引 InnoDB存储引擎支持以下几种常见索引:B+树索引.全文索引.哈希索引,其中比较关键的是B+树索引. B+树索引 InnoDB中的索引自然也是按照B+树来组织的,B+树的叶子节点 ...

  7. 【mysql】--高性能索引策略(359)

    如何高效的使用索引: 1 独立的列-->将单独列放在比较符号的一侧: where acrot_id + 1 = 5: error 2 索引的选择性: 不重复的索引值 : 数据表记录总数 ,唯一索 ...

  8. 高性能Mysql——创建高性能索引详解

    索引(在MySQL中也叫做"键(key)")是存储引擎用于快速找到记录的一种数据结构.这是索引的基本功能,除此之外,本章还将讨论索引其他一些方面有用的属性. 索引对于良好的性能非常 ...

  9. mysql to days 索引_高性能mysql优化二之索引篇

    前言 为什么要使用索引?索引有什么用途呢?我的亲身经历,一个几千万数据的项目,我写了一条查询,没有用到索引,由于访问量比较大,瞬间网站就跪了,从此以后我写的每一条sql都会explain解析看是否用到 ...

  10. 一文搞懂 MySQL 中的索引

    1. 什么是索引 MySQL 官方对索引的定义为:索引(Index)是帮助 MySQL 高效获取数据的数据结构.可以得到索引的本质:索引是数据结构. 举一个例子,平时看任何一本书,首先看到的都是目录, ...

最新文章

  1. python类的调用关系_JAVA 查找类的所有引用关系(python实现)
  2. 微信小程序,实现 watch 属性,监听数据变化
  3. js和css实现手机横竖屏预览思路整理
  4. Python 爬虫学习 系列教程
  5. c语言string函数的用法_同一个函数的五六个版本,C++string insert函数详解
  6. (3)vue.js安装
  7. php获取表单元素的值,PHP如何获取表单提交的数据
  8. mysql完备_mysql简单完备脚本
  9. vue设置video图片_vue video和vue-video-player实现视频铺满教程
  10. layabox位移和旋转动画
  11. KGB知识图谱通过知识校验完成企业的风险审核
  12. 微信公众号开发(一)--开发模式与编辑模式
  13. 新旭完成总金额达美金4,000万元C轮融资;波士顿科学两款创新产品同时进入创新医疗器械特别审查程序 | 医药健闻...
  14. Oracle11g密码忘记
  15. (JAVA)获取支付宝二维码 带参数
  16. AXI(Advanced eXtensible Interface)协议规范
  17. Codeforces 940E - Cashback
  18. 论文笔记—LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain
  19. linux root添加账户,Linux系统添加管理员root角色账户
  20. ASP.NET 对路径的访问被拒绝

热门文章

  1. ROC曲线及AUC值
  2. ad如何计算电路板的pin数量_PCB厂一到八层电路板的叠层设计方式
  3. 现代通信原理3.3:两个重要的信号处理模块-乘法器与滤波器
  4. 均方根误差RMSE 均方根值(RMS)+ 均方根误差(RMSE)+标准差(Standard Deviation)
  5. linux常见命令用法之(二)
  6. mysql query profiler_Using the New MySQL Query Profiler
  7. 自动化遍历-appcrawler
  8. Python说文解字_杂谈07
  9. JavaScript篇 深入理解JavaScript函数
  10. 哈希查找 C语言版