《高性能MySQL》读书笔记之创建高性能的索引
索引是存储引擎用于快速找到记录的一种数据结构。索引优化是对查询性能优化的最有效手段。索引能够轻易将查询性能提高几个数量级。创建一个最优的索引经常需要重写查询。
5.1 索引基础
在MySQL中,存储引擎首先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行。
索引可以包含一个或多个列的值。如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效地使用索引的最左前缀列。
5.1.1 索引的类型
索引有很多类型,可以为不同的场景提供更好的性能。在MySQL中,索引是在储存引擎层而不是服务器层实现的。
B-Tree索引:B-Tree通常意味着所有的值都是按顺序储存的,并且每一个叶子页到根的距离相同。
储存引擎以不同的方式使用B-Tree索引,性能也各有不同,各有优劣。MyISAM使用前缀压缩技术使得索引更小,但InnoDB则按照原数据格式进行储存。MyISAM索引通过数据的物理位置引用被索引的行,而InnoDB则根据主键引用被索引的行。
B-Tree对索引是顺序组织存储的,所以很适合查找范围数据。
B-Tree索引适用于全键值、键值范围或键前缀查找。其中键前缀查找只适用于根据最左前缀的查找。
可以使用B-Tree索引的查询类型:
全值匹配:指的是和索引中所有的列进行匹配。
匹配最左前缀:只使用索引的第一列。
匹配列前缀:也可以匹配某一列的开头部分。
匹配范围值:也只使用了索引的第一列。
精确匹配某一列并范围匹配另外一列:即第一列全匹配,第二列范围匹配。
只访问索引的查询:即查询只需要访问索引,而无须访问数据行。
因为索引树中的节点是有序的,所以除了按值查找之外,还可以用于查询中的ORDER BY操作。
下面是一些关于B-Tree索引的限制:
如果不是按照索引的最左列进行查找,则无法使用索引。
不能跳过索引中的列。
如果查询中有某个列的范围查找,则其右边所有列都无法使用索引优化查找。
所以索引列的顺序非常重要,在优化性能的时候,可能需要使用相同的列但顺序不同的索引来满足不同类型的查询需求。
哈希索引(hash index): 基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个较小的值,并且不同键值的行计算出的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。
在MySQL中,只有Memory引擎显式支持哈希索引。如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中。
因为哈希索引只需要存储对应的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快。
哈希索引的限制:
哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。
哈希索引无法用于排序。
哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容计算哈希值的。例如在数据列 (A,B)上建立哈希索引,如果查询只有数据列A,则无法使用该索引。
哈希索引只支持等值比较查询,包括 =, IN(), <=>(注意<>和<=>是不同的操作)。也不支持任何范围查询。
访问哈希索引的数据非常快,除非有很多哈希冲突(不同的索引列却有相同的哈希值)。
如果哈希冲突很多的话,一些索引维护操作的代价也会很高。
因为这些限制,哈希索引只适用于某些特定的场合。而一旦适合哈希索引,则它带来的性能提升将非常显著。
创建自定义哈希索引:如果存储引擎不支持哈希索引,则可以创建自定义的哈希索引。
思路很简单:在B-Tree上创建一个伪哈希索引。这和真正的哈希索引不是一回事,因为还是使用B-Tree进行查找,但是它使用哈希值而不是键本身进行索引查找。需要做的就是在查询的WHERE子句中手动指定使用哈希函数,可以使用CRC32做哈希,不要使用SHA1()和MD5()作为哈希函数(因为这两个函数计算出来的哈希值是非常长的字符串,会浪费大量空间,比较时也会比较慢)。
如果数据表非常大,CRC32()会出现大量的哈希冲突(当索引有93000条记录时出现冲突的概率是1%),则可以考虑自己实现一个简单的64位哈希函数,对这个函数的要求是返回整数。一个简单的办法是可以使用MD5()函数返回值的一部分作为自定义哈希函数,还可以使用如FNV64()函数作为哈希函数,这是移植自Percona Server 的函数,可以以插件的方式在任何MySQL版本中使用,生成的哈希值是64位,速度快,且冲突比CRC32()要少得多。
处理哈希冲突:当使用哈希索引进行查询时,必须在WHERE子句中包含常量值,例如:
mysql>SELECt id FROM url WHERE url_ctc = CRC32("http://www.mysql.com") AND url="http://www.mysql.com";
5.2 索引的优点
最常见的B-Tree索引,按照顺序存储数据,所以MySQL可以用来做ORDER BY和GROUP BY操作。因为数据是有序的,所以B-Tree也就会将相关的列值都存储在一起。最后,因为索引中存储了实际列的值,所以某些查询只使用索引就能够完成全部查询。
三大优点:
1. 索引大大减少了服务器需要扫描的数据量
2. 索引可以帮助服务器避免排序和临时表
3. 索引可以将随机I/O变为顺序I/O
总的来说,只有当索引帮助存储引擎快速地找到记录带来的好处大于其带来的额外工作时,索引才是有效的。对于非常小的表,大部分情况下简单的全表扫描更高效。对于中到大型的表,索引就非常有效。但对于特大型的表,建立和使用索引的代价将随之增长。
5.3 高性能的索引策略
5.3.1 独立的列
如果查询中的列不是独立的,则MySQL就不会使用索引。“独立的列”是指索引的列不能是表达式的一部分,也不是函数的参数。
mysql>SELECT actor_id FROM sakila.actor WHERE actor_id + 1 =5;
mysql>SELECt ... WHERE TO_DAYS(CURRENT_DATE) - TO_DAY(date_col) <= 10;
5.3.2 前缀索引和索引选择性
有时候需要索引很长的字符列,这会让索引变得大且慢。一个策略是前面提到过的模拟哈希索引。但有时候这样做还不够,通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率,但这样会降低索引的选择性。索引的选择性是指,不重复的索引值(也称为基数,cardinality)和数据表的记录总数(#T)的比值,范围从1/#T到1之间。索引的选择性越高则查询效率越高。唯一索引的选择性是1,这是最好的索引选择性,性能是最好的。
5.3.3 多列索引
一个常见错误就是,为每个列创建独立索引,或者按照错误的顺序创建多列索引。
在多个列上创建索引大部分情况下并不能提高MySQL的查询性能。
例如,表film_actor在字段film_id和actor_id上各有一个单列索引。但对于下面的查询,这两个单列索引都不是好的选择:
mysql>SELECT film_id,actor_id FROM sakila.film_actor
->WHERE actor_id = 1 OR film_id = 1;
在MySQL 5.0 和更新的版本中,查询能同时使用这两个单列索引进行扫描,并将结果进行合并。这种算法有三个变种:OR条件的联合(union),AND条件的相交(intersection),组合前两种情况的联合和相交。通过EXPLAIN中的Extra可以看到这一点:
mysql>EXPLAIN SELECT film_id,actor_id FROM sakila.film_actor
->WHERE actor_id = 1 OR film_id = 1\G;
********************1. row****************************
...
...
Extra: Using union(PRIMARY,idx_fk_film_id),Using where
索引合并策略有时候是一种优化的结果,但实际上更多时候说明表上的索引建得很糟糕。
当出现服务器对多个索引做相交操作时(通常有多个AND条件),通常意味着需要一个包含所有相关列的多列索引,而不是多个独立的单列索引。
当服务器需要多个索引做联合操作时(通常有多个OR操作),通常需要耗费大量的CPU和内存资源在算法的缓存、排序和合并操作上。
(未完待续)
如果您觉得阅读本文对您有帮助,欢迎转载本文,但是转载文章之后必须在文章页面明显位置保留此段声明,否则保留追究法律责任的权利。
作 者:blog.jpdou.top
《高性能MySQL》读书笔记之创建高性能的索引的更多相关文章
- 高性能MySQL --- 读书笔记(1) - 2016/8/2
此书不但帮助MySQL初学者提高使用技巧,更为有经验的MySQL DBA指出了开发高性能MySQL应用的途径.全书包括14章,内容覆盖MySQL系统架构.设计应用技巧.SQL语句优化.服务器性能调优. ...
- 高性能MySQL --- 读书笔记(2) - 2016/8/2
第1章 MySQL架构 MySQL架构与其他数据库服务器大不相同,这使它能够适应广泛的应用.MySQL足够灵活,能适应高要求架构.例如Web应用,同时还适用于嵌入式应用.数据仓库.内容索引和分发软件. ...
- 高性能mysql读书笔记(一):Schema与数据类型优化
4.5 加快ALTER TABLE 操作的速度 原理: MySQL 的ALTER TABLE 操作的性能对大表来说是个大问题. MySQL 执行大部分修改表结构操作的方法是用新的结构创建一个空表,从旧 ...
- Spring读书笔记——bean创建(下)
有关Spring加载bean系列,今天这是最后一篇了,主要接上篇对于从Spring容器中获取Bean的一些细节实现的补充. <Spring读书笔记--bean加载>--Spring如何加载 ...
- mysql笔记02 创建高性能的索引
创建高性能的索引 1. 索引(在MySQL中也叫做"键(key)")是存储引擎用于快速找到记录的一种数据结构. 2. 索引可以包含一个或多个列的值.如果索引包含多个列,那么列的顺序 ...
- 高性能mysql学习笔记
此文已由作者朱笑天授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 笔者在工作之余阅读了一下高性能mysql,以下的内容对mysql的介绍以及书中涉及一些概念的总结归纳. 1. ...
- 《高性能MySQL》笔记——MySQL建表数据类型的选择
前段时间看了<高性能MySQL>中的选择优化的数据类型,这里主要是做一下笔记. 首先数据选择有几个简单原则: 更小的通常更好.一般情况下,应该尽量使用可以正确存储数据的最小数据类型.例如只 ...
- 高性能mysql 第5章 创建高可用的索引
b-tree索引 一定程度上说,mysql只有b-tree索引.他没有bitmap索引.还有一个叫hash索引的,只在Memory存储引擎中才有. b-tree索引跟oracle中的大同小异. mys ...
- 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么
看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...
随机推荐
- BZOJ_3781_小B的询问_莫队
BZOJ_3781_小B的询问_莫队 Description 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值 ...
- Win32编程点滴3 - 简单ActiveX控件的使用
虽然这里一片的.net气氛,到处充斥着像MVC.WPF.WorkFlow.LINQ等各种niubility的术语.但我们使用的Windows还是由COM技术主宰着:我们在选择日常使用的软件时,也会避免 ...
- 增加,删除GMS包
1. device/hiteq/vtab_1050_standard/httek.mk BUILD_GMS:=yes GMS_VARIANT:=mini 2. rm out/target/produc ...
- compileSdkVersion, minSdkVersion 和 targetSdkVersion详解
API level API level是一个整数,它指的是我们使用的框架(Framework)的版本,也就是我们使用的sdk中的各个平台下的android.jar. 但是这个API level又和An ...
- mysql : mysql 5.6.13 免安装版配置
前言:真正用到mysql是在公司的第二个项目下,具体的一些在之前的博客文章(http://www.cnblogs.com/zhengzeze/p/5623440.html)中也提到了,其中涉及到,免安 ...
- idea2018.2.5版本使用之背景色
idea 背景色: 写代码区换眼色豆沙色:
- Linux编写Shell脚本入门
一. 一般编写shell需要分3个步骤 1. 新建一个脚本文件,并编写程序 vi hello.sh #!/bin/bash #注释 #输出 printf '%s\n' "Hello Worl ...
- 2.7 HBase架构深入剖析
一. 1.client 整个HBase集群的访问入口: 使用HBase RPC机制与HMaster和HRegionServer进行通信: 与HMaster进行通信进行管理类操作: 与HRegionSe ...
- Numpy学习笔记<1>
1 numpy的ndarray:一种多维数组 a:创建ndarry 注意:np.array会尝试为新建的数组一个合适的数据类型 保存在dtype中 b:嵌套序列转换为一个多维数组 c:输出数据类型 ...
- lightoj1063【求割点】
题意不懂啊...... 只知道求割点. #include <bits/stdc++.h> using namespace std; typedef long long LL; typede ...