索引概念

B+树索引分为聚集索引和非聚集索引(辅助索引),但是两者的数据结构都和B+树一样,区别是存放的内容。

可以说数据库必须有索引,没有索引则检索过程变成了顺序查找,O(n)的时间复杂度几乎是不能忍受的。我们非常容易想象出一个只有单关键字组成的表如何使用B+树进行索引,只要将关键字存储到树的节点即可。当数据库一条记录里包含多个字段时,一棵B+树就只能存储主键,如果检索的是非主键字段,则主键索引失去作用,又变成顺序查找了。这时应该在第二个要检索的列上建立第二套索引。 这个索引由独立的B+树来组织。有两种常见的方法可以解决多个B+树访问同一套表数据的问题,一种叫做聚簇索引(clustered index ),一种叫做非聚簇索引(secondary index)。这两个名字虽然都叫做索引,但这并不是一种单独的索引类型,而是一种数据存储方式。对于聚簇索引存储来说,行数据和主键B+树存储在一起,辅助键B+树只存储辅助键和主键,主键和非主键B+树几乎是两种类型的树。对于非聚簇索引存储来说,主键B+树在叶子节点存储是指向真正数据行的指针,并且辅助B+树在叶子节点存储也是指向真正数据行的指针,而非主键B+树。

InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id = 14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。

InnoDB存储引擎是索引组织表,也就是说数据文件本身就是按照B+树方式存放数据的。Innodb 聚集索引是按照主键(primary key)进行聚集,被索引的列其实是主键列,如果没定义主键,Innodb会试着使用唯一非空索引Unique Index来代替,如果还找不到,Innodb就会自动创建一个6字节作为隐藏主键然后在上面进行索引聚集。除了主键的聚集索引,其他索引(辅助索引)中不会保存行的物理位置,而是保存主键的值,所以通过"二级索引"进行查找是先找到主键,再找到行,要进行二次索引查找。在InnoDB存储引擎中,将B+树索引分为聚集索引和非聚集索引(辅助索引),但是两者的数据结构都和B+树一样,区别是存放的内容。无论是何种索引,每个页的大小都是16KB,且不能改变。

MyISM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

图示清晰的显示了聚簇索引和非聚簇索引的差异。

Cardinality

并不是所有在查询条件中出现的列都需要添加索引,对于什么时候添加B+树索引,一般的检验是,在访问表中很少一部分行是使用B+树索引才有意义。查看索引是否是高选择性的,可以通过SHOW INDEX语句中的Cardinality列来观察。Cardinality是一个估计值,在实际中,Cardinality/n_rows_in_table应尽可能接近1,如果非常小,那么需要考虑是否还要建这个索引。

InnoDB中如何统计Cardinality值,索引的更新可能非常平凡,如果每次更新操作时就统计Cardinality值,那么对数据库会带来很大负担。InnoDB存储引擎中,Cardinality统计发生在INSERT和UPDATE操作中,不过并不会每次都去统计,它的策略是:

  • 表中的1/16的数据已发生变化。
  • stat_modified_counter > 2000000000。

stat_modified_counter是数据库发生INSERT和UPDATE操作的计数器,如果每次对表中的一行数据更新操作,表中的数据几乎不会有变化,那么第一种策略就无法试用。所以计数器用来统计操作的次数,如果满足条件,也会统计Cardinality值。

InnoDB存储引擎只对8个叶节点进行采样。采样的过程为:

  1. 取得B+树索引中叶节点的数量,即为A。
  2. 随机取B+树索引中的8个节点。统计每页中不同的记录的个数,即为P1,P2,...,P8。
  3. 根据采样的信息给出Cardinality值预估值:Cardinality = (P1+P2+...+P8)* A / 8。

注意:如果表足够小,表的叶节点小于或等于8个,这时即使随机采样,也总是采取到这些页,因此每次的Cardinality值都是一样的。

B+树索引的使用

不同应用中B+树索引的使用

数据库存在两种类型的应用:OLTP和OLAP应用。OLTP是传统关系型数据库的主要应用,其主要面向基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。

在OLTP应用中,查询操作一般只从数据库中取得一小部分数据,在这种情况下,建立B+树索引后,优化器就会使用索引。对于OLAP应用,一般需要访问表中的大量数据,并根据这些数据来产生查询的结果,而这些查询多是分析的查询,目的是为决策者提供支持。但是对于LOAP中的复杂查询,需要涉及多表之间的联接操作,这是索引的添加是有意义的,但是联接操作使用Hash Join,那么索引可能又变得不是非常重要。不过在OLAP应用中,通常需要对时间字段进行索引,这是因为大多数统计需要根据时间维度来进行判断。

联合索引

联合索引是指对表上的多个列进行索引,又叫复合索引。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c)。可以支持a | a,b | a,b,c 3种组合进行查找,但不支持b,c进行查找。当最左侧字段是常量引用时,索引就十分有效。查询使用索引的条件不同一般组合索引需要按照“最左前缀”来执行查询,并不是每个列都需要覆盖,只是从左边的列开始组合。在选择组合索引的时候,当前Query 中过滤性最好的字段在索引字段顺序中排列越靠前越好。

例如有索引key(a,b,c)

  • where a=xx and b=xx and c=xxx 此语句可以用到索引
  • where b=xx and a=xx and c=xxx 同上,顺序没有关系,同样能用到索引
  • where a=xx and b=xx 可以用到索引
  • where a=xx and c=xx 可以用到索引
  • where b=xx and c=xx 用不到索引
  • where b=xx 用不到索引
  • where c=xx 用不到索引

覆盖索引

InnoDB存储引擎支持覆盖索引,即从辅助索引就可以得到查询的记录,而不需要查询聚集索引中的记录。使用覆盖索引的好处是辅助索引不包含整行记录的所有信息,故其大小要远小于聚集索引,因此可以减小大量的IO操作。

对于InnoDb存储引擎的辅助索引而言,由于其中包含了主键信息,因此其叶子节点放的数据为(primary key1, primary key2,..., key1, key2,...)。对于下面的可以仅用一次辅助联合索引来完成查询。

  • SELECT key2 FROM table key1 = xxx;
  • SELECT primary key1, key2 FROM table WHERE key1 = xxx;
  • SELECT primary key1, primary key2, key2 FROM table WHERE key1 = xxx;

简单的说,如果查询的列,正好是我们设置的主键或者键(建立聚合索引的键),如上图展示的,辅助索引的叶子节点的值就是所要查询的内容,就不必取到键值后再去聚合索引进行二次查找。可以想到如果想要更多的使用覆盖索引这一特性,需要将我们需要的列,都建立联合索引。

联合索引和覆盖索引有很大的区别:

覆盖索引是查询的列可以直接通过索引提取,比如只查询主键的列!或者查询联合索引的所有列或者左边开始的部分列(注意有顺序的)!

而联合索引并不一定只从索引中能获取到所有的数据,这个取决于你所查询的列。比如select * from table where ××××××;的方式就不太可能是覆盖索引。因此如果你查询的列能用到联合索引,且你查询的列都能通过联合索引获取,比如你只查询联合索引所在的列或者左边开始的部分列,这就相当于覆盖索引了。通常为了让查询能用到覆盖索引,就将要查询的多列数据设置成联合索引。

优化器不使用(辅助)索引的情况

在某些情况下,优化器并没有选择辅助索引去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据。

SELECT * FROM orderdetails WHERE orderid>10000 and orderid<102000;

通过SHOW INDEX FROM orderdetails可以看到可以使用的索引包括PRIMARY、OrderID、OrderOrder_Details三个索引,正常情况下,应该选择OrderID辅助索引开始查询,但是优化器直接选择PRIMARY聚集索引。

原因在于我们要选取的数据是整行信息,而OrderID索引不能覆盖到我们要查询的信息(覆盖索引),因此在对OrderID索引进行查询到指定数据的操作后,还需要进行一次书签访问来查找整行信息。虽然在辅助索引中数据是顺序存放的,但是再一次的书签查找数据是无序的,因此变为了磁盘上的离散读取操作。如果要访问的数据量很小,那么优化器还是会选择辅助索引,但是当访问的数据占整个表中数据的很大一部分时(一般是20%左右),优化器会选择通过聚集索引来查找数据。

INDEX HINT

MYSQL数据库支持INDEX HINT(索引提示),显示的告诉优化器使用哪个索引,在以下情况下可能需要用到INDEX HINT:

  • MYSQL数据库的优化器错误的选择了某个索引,导致MYSQL语句运行很慢,情况少数。
  • 某SQL语句可以选择的索引非常多,这时优化器选择执行计划时间的开销就可能会大于SQL语言本身。通过INDEX HINT可以强制优化器使用某个索引,直接执行选择指定的索引来完成索引。
USE INDEX

SELECT * FROM t USE INDEX(a) WHERE a=1 AND b=2;

使用USE INDEX可以告诉优化器可以选择该索引,但是不是强制使用该索引。实际的使用优化器还是会根据自己的判断进行选择。

FORCE INDEX

SELECT * FROM t FORCE INDEX(a) WHERE a=1 AND b=2;

使用FORCE INDEX可以指定优化器选择某个索引进行查询。

T树索引

对于MYSQL数据库的NDB CLuster内存存储引擎,在使用它时可将其视为内存数据库。在内存数据库中,一般使用T树作为其索引的数据结构。T树是有平衡二叉树和B树发展而来。T树的好处是节点不存放数据,只存放指针,这样能减少内存的使用,这对内存数据库来说是很重要的。同时T树也是一棵平衡二叉树,以此保证查找的性能。

哈希索引

当前MYSQL数据库中,Memory存储引擎支持哈希索引。InnoDB存储引擎支持自适应哈希索引,用户仅能开启该特性,不能对其进行人工干预。通过参数innodb_adaptive_hash_index来禁用或启动此特性,默认为开启。

MySql索引总结的更多相关文章

  1. 深入MySQL索引

    MySQL索引作为数据库优化的常用手段之一在项目优化中经常会被用到, 但是如何建立高效索引,有效的使用索引以及索引优化的背后到底是什么原理?这次我们深入数据库索引,从索引的数据结构开始说起. 索引原理 ...

  2. MySQL 索引

    MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是 ...

  3. MYSQL索引结构原理、性能分析与优化

    [转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...

  4. MySQL索引原理及慢查询优化

    原文:http://tech.meituan.com/mysql-index.html 一个慢查询引发的思考 select count(*) from task where status=2 and ...

  5. 【转】MySQL索引背后的数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  6. [转]MySQL索引背后的数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  7. MySQL索引类型总结和使用技巧以及注意事项

    索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型 在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytable ...

  8. MySQL索引背后的数据结构及算法原理【转】

    本文来自:张洋的MySQL索引背后的数据结构及算法原理 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持 ...

  9. mysql索引总结----mysql 索引类型以及创建

    文章归属:http://feiyan.info/16.html,我想自己去写了,但是发现此君总结的非常详细.直接搬过来了 关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基 ...

  10. Mysql 索引实现原理. 聚集索引, 非聚集索引

    Mysql索引实现: B-tree,B是balance,一般用于数据库的索引.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.而B+tree是B-tree的一个变种,My ...

随机推荐

  1. Android开发学习之路-Git的极简教程?

    Git是一个代码版本管理工具,也就是允许我们的一个项目拥有多个版本,这样我们可以随心所欲的修改我们的代码,如果出现问题,可以回退到某一个提交点.如果你还在用一堆堆注释来更新你的代码,那么可以尝试一下G ...

  2. [转]Linux下g++编译与使用静态库(.a)和动态库(.os) (+修正与解释)

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库 ...

  3. 环境搭建系列-系统安装之centos 6.5安装与配置

    按照国际惯例,系列目录先奉上: 系列一:系统安装之centos 6.5安装与配置 系列二:准备工作之Java环境安装 系列三:数据为先之MySQL读写集群搭建 系列四:谈分布式之RabbitMQ集群搭 ...

  4. 【WCF】自定义地址头的筛选器

    前面的文章中,老周已向大伙伴们介绍了如何在终结点上使用地址头,只要服务是沿着该终结点调用的,那么每一次调用都会自动把地址头插入到SOAP消息的Header列表中. 而通过前一篇文章中的示例,大家也看到 ...

  5. seajs的使用

    写在前面 seajs是什么? Seajs是一个js文件加载器. 遵循 CMD 规范模块化开发,依赖的自动加载.配置的简洁清晰. 用于Web开发的模块加载工具,提供简单.极致的模块化体验 一:使用 文件 ...

  6. 文本比较算法:Needleman/Wunsch算法

    本文介绍基于最长公共子序列的文本比较算法——Needleman/Wunsch算法.还是以实例说明:字符串A=kitten,字符串B=sitting那他们的最长公共子序列为ittn(注:最长公共子序列不 ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(31)-MVC使用RDL报表

    系列目录 这次我们来演示MVC3怎么显示RDL报表,坑爹的微软把MVC升级到5都木有良好的支持报表,让MVC在某些领域趋于短板 我们只能通过一些方式来使用rdl报表. Razor视图不支持asp.ne ...

  8. Android自定义控件之自定义属性

    前言: 上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性.本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解.有关原理知识请参考Android自定义控 ...

  9. iOS开发之浅谈MVVM的架构设计与团队协作

    今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  10. 学习SpringMVC——国际化+上传+下载

    每个星期一道菜,这个星期也不例外~~~ 一个软件,一个产品,都是一点点开发并完善起来的,功能越来越多,性能越来越强,用户体验越来越好……这每个指标的提高都需要切切实实的做点东西出来,好比,你的这个产品 ...