高性能mysql之前缀索引
有时候需要索引很长的字符列,这会让索引变得大且慢。通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率。但这样也会降低索引的选择性。索引的选择性是指不重复的索引值(也称为基数,cardinality)和数据表的记录总数的比值,范围从1/#T到1之间。索引的选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
一般情况下某个前缀的选择性也是足够高的,足以满足查询性能。对于BLOB,TEXT,或者很长的VARCHAR类型的列,必须使用前缀索引,因为MySQL不允许索引这些列的完整长度。
诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)。前缀应该足够长,以使得前缀索引的选择性接近于索引的整个列。换句话说,前缀的”基数“应该接近于完整的列的”基数“。
为了决定前缀的合适长度,需要找到最常见的值的列表,然后和最常见的前缀列表进行比较。下面的示例是mysql官方提供的示例数据库
下载地址如下:
http://downloads.mysql.com/docs/sakila-db.zip
在示例数据库sakila中并没有合适的例子,所以从表city中生成一个示例表,这样就有足够数据进行演示:
mysql> select database(); +------------+ | database() | +------------+ | sakila | +------------+ 1 row in set (0.00 sec)mysql> create table city_demo (city varchar(50) not null); mysql> insert into city_demo (city) select city from city; --执行两次 Query OK, 600 rows affected (0.02 sec) Records: 600 Duplicates: 0 Warnings: 0
mysql> update city_demo set city = ( select city from city order by rand() limit 1); Query OK, 1198 rows affected (0.42 sec) Rows matched: 1200 Changed: 1198 Warnings: 0
注:因为上述sql语句使用了rand函数,所以每个人的执行结果可以都不一样!
首先找到最常见的城市列表:
mysql> select count(*) as cnt,city from city_demo group by city order by cnt desc limit 10; +-----+---------------+ | cnt | city | +-----+---------------+ | 8 | Dongying | | 7 | Omdurman | | 6 | Etawah | | 6 | Okara | | 6 | Tsuyama | | 6 | Brindisi | | 6 | Kuwana | | 6 | Grand Prairie | | 5 | Fuyu | | 5 | Siegen | +-----+---------------+ 10 rows in set (0.00 sec)
现在查找到频繁出现的城市前缀。先从3个前缀字母开始,然后4个,5个,6个:
mysql> select count(*) as cnt,left(city,3) as pref from city_demo group by pref order by cnt desc limit 10; +-----+------+ | cnt | pref | +-----+------+ | 23 | San | | 15 | Hal | | 14 | Cha | | 14 | al- | | 12 | Bat | | 12 | Kor | | 11 | Don | | 11 | Shi | | 10 | La | | 10 | El | +-----+------+ 10 rows in set (0.00 sec)
可以看到3字节检索到的结果与全文检索相差很大,继续增加到4个字节mysql> select count(*) as cnt,left(city,4) as pref from city_demo group by pref order by cnt desc limit 10; +-----+------+ | cnt | pref | +-----+------+ | 14 | San | | 8 | Dong | | 7 | Iwak | | 7 | al-Q | | 7 | Omdu | | 6 | Kuwa | | 6 | Tsuy | | 6 | Brin | | 6 | Etaw | | 6 | Okar | +-----+------+ 10 rows in set (0.00 sec)mysql> select count(*) as cnt,left(city,5) as pref from city_demo group by pref order by cnt desc limit 10; +-----+-------+ | cnt | pref | +-----+-------+ | 8 | Dongy | | 7 | al-Qa | | 7 | Omdur | | 6 | Okara | | 6 | Valle | | 6 | Grand | | 6 | Tsuya | | 6 | Etawa | | 6 | South | | 6 | Kuwan | +-----+-------+ 10 rows in set (0.00 sec)
mysql> select count(*) as cnt,left(city,6) as pref from city_demo group by pref order by cnt desc limit 10; +-----+--------+ | cnt | pref | +-----+--------+ | 8 | Dongyi | | 7 | Omdurm | | 6 | Okara | | 6 | Tsuyam | | 6 | Valle | | 6 | Grand | | 6 | Etawah | | 6 | Brindi | | 6 | Kuwana | | 5 | Haldia | +-----+--------+ 10 rows in set (0.01 sec)
通过上面改变不同前缀长度发现,当前缀长度为6时,这个前缀的选择性就接近完整咧的选择性了。
当然还有另外更方便的方法,那就是计算完整列的选择性,并使其前缀的选择性接近于完整列的选择性。下面显示如何计算完整列的选择性:
mysql> select count(distinct city)/count(*) from city_demo; +-------------------------------+ | count(distinct city)/count(*) | +-------------------------------+ | 0.4333 | +-------------------------------+ 1 row in set (0.00 sec)
可以在一个查询中针对不同前缀长度的选择性进行计算,这对于大表非常有用,下面给出如何在同一个查询中计算不同前缀长度的选择性:
mysql> select count(distinct left(city,3))/count(*) as sel3,count(distinct left(city,4))/count(*) as sel4,count(distinct left(city,5))/count(*) as sel5, count(distinct left(city,6))/count(*) as sel6 from city_demo; +--------+--------+--------+--------+ | sel3 | sel4 | sel5 | sel6 | +--------+--------+--------+--------+ | 0.3408 | 0.4100 | 0.4225 | 0.4300 | +--------+--------+--------+--------+ 1 row in set (0.00 sec)
可以看见当索引前缀为6时的基数是0.4300,已经接近完整列选择性0.4333。
下面根据找到的索引前缀长度创建前缀索引:
mysql> alter table city_demo add key (city(6)); Query OK, 0 rows affected (0.19 sec) Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from city_demo where city like 'Jin%' \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: city_demo partitions: NULL type: range possible_keys: city key: city key_len: 8 ref: NULL rows: 4 filtered: 100.00 Extra: Using where 1 row in set, 1 warning (0.00 sec)
可以看见正确使用刚创建的索引。
优点:前缀索引是一种能使索引更小,更快的有效办法
缺点:mysql无法使用其前缀索引做ORDER BY和GROUP BY,也无法使用前缀索引做覆盖扫描。
高性能mysql之前缀索引相关推荐
- 读薄《高性能MySql》(三)索引优化
读薄<高性能MySql>(一)MySql基本知识 读薄<高性能MySql>(二)Scheme与数据优化 读薄<高性能MySql>(三)索引优化 读薄<高性能M ...
- 高性能mysql学习笔记--索引
高性能mysql 五:索引 1,B-Tree索引 全值匹配:匹配所有列. 匹配最左前缀:只使用索引的第一列. 匹配列前缀:只使用索引的第一列. 匹配范围值:只使用索引的第一列. 精确匹配某一列并范围匹 ...
- MySQL的前缀索引及Oracle的类似实现
MySQL有一个很有意思的索引类型,叫做前缀索引,它可以给某个文本字段的前面部分单独做索引,从而降低索引的大小. 其实,Oracle也有类似的实现,对于文本,它可以通过substr的函数索引,实现同样 ...
- MySQL字符串前缀索引详解
MySQL字符串前缀索引详解 1. 前缀索引与全部索引概念 2. 前缀索引与全部索引数据结构 3. 前缀索引与全部索引引执行流程 4. 前缀索引长度如何取舍 5. 前缀索引对覆盖索引的影响 6. 其他 ...
- mysql 建前缀索引_MySQL_前缀索引_建立
-- 查看出现频率 select count(*) as cnt,city from sakila.city_demo group by city order by cnt desc limit 10 ...
- mysql创建前缀索引
ALTER table 表名 add index title_pre(列名(100)) 列名后面的数字代表前缀的长度,前缀长度并不是越长越好,这里涉及到一个选择性问题, select count(di ...
- 高性能mysql:创建高性能的索引
2019独角兽企业重金招聘Python工程师标准>>> 索引是存储引擎用于快速找到记录的一种数据结构. 索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对性能的影响愈 ...
- 高性能MySQL(3)——创建高性能索引
索引对于良好的性能非常关键.尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要. 一.索引的类型 在MySQL中,索引是在存储引擎层而不是服务器层实现的.所以没用统一的索引标准,不同存储引擎的索 ...
- mysql第五章项目二_高性能MySQL笔记 第5章 创建高性能的索引
索引(index),在MySQL中也被叫做键(key),是存储引擎用于快速找到记录的一种数据结构.索引优化是对查询性能优化最有效的手段. 5.1 索引基础 索引的类型 索引是在存储引擎层而不是服务器层 ...
- 【数据库笔记】高性能MySQL:chapter 5 创建高性能的索引
文章目录 前置知识 5.0 引言 5.1 索引基础 1. 索引的类型 B-Tree 索引 哈希索引 空间数据索引(R-Tree) 全文索引 5.2 索引基础 5.3 高性能的索引策略 1. 独立的列 ...
最新文章
- [LeetCode] Add Digits
- 皮一皮:大自然的力量你无法想象...
- Java-CentoOS 7安装JDK8 (rpm格式 和 tar.gz格式) 多JDK设置默认的Java 版本
- mysql查看表的两列_MySQL查询来计算表列中的0和1的数量,并在两列中显示?
- Imageready(IR)动画介绍
- 对javascript中的匿名函数的理解
- Qt文档阅读笔记-Q_ASSERT的另外一总用法(大佬用法)
- WebAssembly 开启微服务新时代
- winform倒计时
- 数据太大的时候,R语言如何读取?
- Algorithm:数学建模大赛(CUMCM/NPMCM)之建模历年题目类型、数据分析及官方评阅要点之详细攻略
- 从小学算术的速算与二进制速算,分析基础与窍门的关系:
- ArcGIS Runtime for Android天地图底图及TPK数据包放大后数据不显示问题
- java实现微博九宫格图片切分
- Android - xml动画,识别手势动作,代码抽取,获取手机SIM卡串号,获取联系人数据,开机广播,发送/解析短信,报警音乐
- PMP第八节:项目质量管理
- 如何旋转在Visio中的文字(或文本)
- 微信聊天语音怎么转发?轻松易懂,快速学会
- Axure无法同时打开多个.rp文件
- 笨方法学python 习题37