btree索引:

如果没有特别指明类型,多半说的就是btree索引,它使用btree数据结构来存储数据,大多数mysql引擎都支持这种索引,archive引擎是一个例外,5.1之前这个引擎不支持任何索引,5.1开始才支持单列自增的索引。innodb使用b+tree=btree(btree已经不使用了)

存储引擎以不同的方式使用btree索引,性能也各不相同,各有优劣,如:myisam使用前缀压缩技术使得索引更小(但也可能导致连接表查询性能降低),但innodb则按照原数据格式进行存储,再如:myisam索引通过数据的物理位置来引用被索引的行,而innodb则根据主键来引用被索引的行。

btree通常意味着所有的值都是按照顺序存储的,并且每一个叶子页到根的距离相同

,下图是innodb索引工作示意图,myisam使用的结构有所不同,但基本思想类似:

图片来源于高性能mysql第三版

btree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始进行搜索,根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找,通过比较节点页的值和要查找的值可以找到合适的指针进入下一层子节点,这些指针实际上定义了子节点页中值的上限和下限,最终存储引擎要么是找到对应的值,要么是该记录不存在。

叶子节点比较特别,他们的指针指向的是被索引的数据,而不是其他的节点页(不同的引擎指针类型不同),其实在根节点与叶子节点之间可能有很多层节点页,树的深度和表的大小直接相关。

 

btree树索引列是顺序组织存储的,所以很适合查找范围数据,

有表:

create table people(last_name varchar(50) not null,first_name varchar(50) not null,dob date not null,gender enum(‘m’,’f’) not null,key(last_name,first_name,dob));

对于表中的每一行数据,索引中包含了last_name,first_name,dob列的值,下图显示了该索引是如何组织数据的存储的:

图片来源于高性能mysql第三版

注意:索引对多个值进行排序的依据是create table语句中定义索引时的列顺序,上图中,最后两个值的姓名都一样时,就按照出生日期来排序了。

 

可以使用btree索引的查询类型,btree索引使用用于全键值、键值范围、或者键前缀查找,其中键前缀查找只适合用于根据最左前缀的查找。前面示例中创建的多列索引对如下类型的查询有效:

A:全值匹配

全值匹配指的是和索引中的所有列进行匹配,即可用于查找姓名和出生日期

B:匹配最左前缀

如:只查找姓,即只使用索引的第一列

C:匹配列前缀

也可以只匹配某一列值的开头部分,如:匹配以J开头的姓的人,这里也只是使用了索引的第一列,且是第一列的一部分

D:匹配范围值

如查找姓在allen和barrymore之间的人,这里也只使用了索引的第一列

E:精确匹配某一列并范围匹配另外一列

如查找所有姓为allen,并且名字字母是K开头的,即,第一列last_name精确匹配,第二列first_name范围匹配

F:只访问索引的查询

btree通常可以支持只访问索引的查询,即查询只需要访问索引,而无需访问数据行,即,这个就是覆盖索引的概念。需要访问的数据直接从索引中取得。

 

因为索引树中的节点是有序的,所以除了按值查找之外,索引还可以用于查询中的order by操作,一般来说,如果btree可以按照某种方式查找的值,那么也可以按照这种方式用于排序,所以,如果order by子句满足前面列出的几种查询类型,则这个索引也可以满足对应的排序需求。

 

下面是关于btree索引的限制:

A:如果不是按照索引的最左列开始查找的,则无法使用索引(注意,这里不是指的where条件的顺序,即where条件中,不管条件顺序,只要where中出现的列在多列索引中能够从最左开始连贯起来就能使用到多列索引)

B:不能跳过索引中的列,如:查询条件为姓和出生日期,跳过了名字列,这样,多列索引就只能使用到姓这一列

C:如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查询,如:where last_name=xxx and first_name like ‘xxx%’ and dob=’xxx’;这样,first_name列可以使用索引,这列之后的dob列无法使用索引。

 

哈希索引:

基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列的值计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码不一样,哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。

 

在mysql中,只有memory引擎显式支持哈希索引,这也是memory引擎表的默认索引类型,memory也支持btree,值得一提的是,memory引擎是支持非唯一哈希索引的。在数据库世界里是比较与众不同,如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中。

示例:

mysql> create table testhash(fname varchar(50) not null,lname varchar(50) not null,key using hash(fname)) engine=memory;
Query OK, 0 rows affected (0.01 sec)
 
mysql> insert into testhash values('Arjen','Lentz'),('Baron','Schwartz'),('Peter','Zaitsev'),('Vadim','Tkachenko');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0
 
mysql> select * from testhash;
+-------+-----------+
| fname | lname     |
+-------+-----------+
| Arjen | Lentz     |
| Baron | Schwartz  |
| Peter | Zaitsev   |
| Vadim | Tkachenko |
+-------+-----------+
4 rows in set (0.00 sec)
 
假设索引使用假想的哈希函数f(),它返回下面的值:
f('Arjen')=2323
f('Baron')=7437
f('Peter')=8784
f('Vadim')=2458
 
则哈希索引的数据结构如下:
槽:        值:
2323        指向第1行的指针
2458        指向第4行的指针
7437        指向第2行的指针
8784        指向第3行的指针

每个槽的编号是顺序的,但是数据行不是顺序的。下面来看一句查询:

select lname from testhash where fname='Peter';

mysql先计算Peter的哈希值,并使用该值寻找对应的记录指针,因为f(‘Peter’)=8784,所以mysql在索引中查找8784,可以找到指向第三行的指针,最后一步是比较第三行的值是否为Peter,以确保就是要查找的行。因为索引自身只需要存储对应的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快,然而,哈希索引也有限制,如下:

A:哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行(即不能使用哈希索引来做覆盖索引扫描),不过,访问内存中的行的速度很快(因为memory引擎的数据都保存在内存里),所以大部分情况下这一点对性能的影响并不明显。

B:哈希索引数据并不是按照索引列的值顺序存储的,所以也就无法用于排序

C:哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引的全部列值内容来计算哈希值的。如:数据列(a,b)上建立哈希索引,如果只查询数据列a,则无法使用该索引。

D:哈希索引只支持等值比较查询,如:=,in(),<=>(注意,<>和<=>是不同的操作),不支持任何范围查询(必须给定具体的where条件值来计算hash值,所以不支持范围查询)。

E:访问哈希索引的数据非常快,除非有很多哈希冲突,当出现哈希冲突的时候,存储引擎必须遍历链表中所有的行指针,逐行进行比较,直到找到所有符合条件的行。

F:如果哈希冲突很多的话,一些索引维护操作的代价也很高,如:如果在某个选择性很低的列上建立哈希索引(即很多重复值的列),那么当从表中删除一行时,存储引擎需要遍历对应哈希值的链表中的每一行,找到并删除对应的引用,冲突越多,代价越大。

 

从上面描述可知,哈希索引只适合某些特定的场景,而一旦适合哈希索引,则它带来的性能提升非常明显,除了memory引擎外,NDB引擎也支持唯一哈希索引,且NDB存储引擎中作用非常特殊,但这里不讨论。

innodb引擎有一个特殊的功能叫做自适应哈希索引,当innodb注意到某些索引值被使用的非常频繁时,它会在内存中基于btree索引之上再创建一个哈希索引,这样就让btree索引也具有哈希索引的一些优点,比如:快速的哈希查找,这是一个全自动的,内部的行为,用户无法控制或者配置,不过如果有必要,可以选择关闭这个功能(innodb_adaptive_hash_index=OFF,默认为ON)。

mysql btree与hash索引的适用场景和限制的更多相关文章

  1. 【转载】Mysql中的Btree与Hash索引比较

    转载地址:http://www.jb51.net/article/62533.htm 这篇文章主要介绍了Mysql中的Btree与Hash索引比较,本文起讲解了B-Tree 索引特征.Hash 索引特 ...

  2. Mysql中的Btree与Hash索引

    B-Tree 索引特征 B-Tree索引可以被用在像=,>,>=,<,<=和BETWEEN这些比较操作符上.而且还可以用于LIKE操作符,只要它的查询条件是一个不以通配符开头的 ...

  3. Mysql的BTREE和HASH索引

    建议默认使用BTree索引,如果时间太长,可以尝试HAST索引,但限制如下: 不支持between and 只支持 = IN <> 不支持范围查询如between and和like. 无法 ...

  4. mysql触发器与hash索引

    url查询哈希值的维护 触发器 2.1 创建表 pseudohash. 2.2 创建触发器,当对表进行插入和更新时,触发 触发器 delimiter |create trigger pseudohas ...

  5. mysql中能够使用索引的典型场景

    mysql 演示数据库:http://downloads.mysql.com/docs/sakila-db.zip 匹配全值 explain select * from rental where re ...

  6. 数据库索引------B-Tree 索引和 Hash 索引的对比

    对于 B-tree 和 hash 数据结构的理解能够有助于预测不同存储引擎下使用不同索引的查询性能的差异,尤其是那些允许你选择 B-tree 或者 hash 索引的内存存储引擎. B-Tree 索引的 ...

  7. B-Tree 索引和 Hash 索引的对照

    对于 B-tree 和 hash 数据结构的理解可以有助于预測不同存储引擎下使用不同索引的查询性能的差异.尤其是那些同意你选择 B-tree 或者 hash 索引的内存存储引擎. B-Tree 索引的 ...

  8. mysql InnoDB引擎是否支持hash索引

    看一下mysql官方文档:https://dev.mysql.com/doc/refman/5.7/en/create-index.html , 从上面的图中可以得知,mysql 是支持hash索引的 ...

  9. BTREE与HASH的区别

    对于 B-tree 和 hash 数据结构的理解能够有助于预测不同存储引擎下使用不同索引的查询性能的差异,尤其是那些允许你选择 B-tree 或者 hash 索引的内存存储引擎. B-Tree 索引的 ...

随机推荐

  1. Vue.2.0.5-Render 函数

    基础 Vue 推荐使用在绝大多数情况下使用 template 来创建你的 HTML.然而在一些场景中,你真的需要 JavaScript 的完全编程的能力,这就是 render 函数,它比 templa ...

  2. iOS获取运营商的相关信息

    1.导入:CoreTelephony.framework 2.添加头文件 #import <CoreTelephony/CTTelephonyNetworkInfo.h> #import ...

  3. 【转】Tomcat7启动的总过程 (有时间自己写下tomcat8的)

    首先,说明tomcat8和tomcat7的启动过程不一样,这篇是针对tomcat7的. Tomcat启动的总过程 通过上面的介绍,我们总体上清楚了各个组件的生命周期的各个阶段具体都是如何运作的.接下来 ...

  4. (Protype Pattern)原型模式

    定义: 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象 适用性: 当我们系统中有一些类,在使用的时候都有同样需要大量的创建,而这样的创建是复杂的而且是浪费CPU,内存资源的 ...

  5. 超炫的3D HTML源代码

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  6. Rest服务

    资源:是网络上的一个实体,或者是网络上的一个具体信息,每一个资源对应一个特定的URI(统一资源定位符),要访问该资源,访问它的URI就可以了. 表现层:把资源的具体形式表现出来. 状态转化:每发出一个 ...

  7. 面向切面编程AOP:基于XML文件的配置

    除了使用AspectJ注解声明切面,Spring也支持在bean的配置文件中声明切面,这种声明是通过aop scheme中的XML元素完成的. 首先建立一个类: package com.sevenhu ...

  8. ACdream 1103 瑶瑶正式成为CEO(树链剖分+费用流)

    Problem Description 瑶瑶(tsyao)是某知名货运公司(顺丰)的老板,这个公司很大,货物运输量极大,因此公司修建了许多交通设施,掌控了一个国家的交通运输. 这个国家有n座城市,公司 ...

  9. paper 22:kl-divergence(KL散度)实现代码

    这个函数很重要: function KL = kldiv(varValue,pVect1,pVect2,varargin) %KLDIV Kullback-Leibler or Jensen-Shan ...

  10. Logstash学习1-logstash的简单例子

    如何安装ELK Redis插件 1. 安装好logstash后.2. 最简单的logstash.logstash -e 'input { stdin { } } output { stdout {} ...