索引概念

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. Chrome调试手机页面

    新开发的网页需要在手机或是模拟机上运行测试,如果手头事件比加紧,那么可以借助 Chrome提供的手机网页预览程序进行简单调试.查看 制作的网页是否能够适合各种手机型号使用. 下面所以下如何使用Chro ...

  2. Unicode和UTF-8的关系

    Unicode和UTF-8都是表示编码,这个我一直都知道,但是这两个实际上是干什么用的,到底是怎么编码的,为什么有了Unicode还要UTF-8,它们之间有什么联系又有什么区别呢?这个问题一直困扰着我 ...

  3. Web中的XHRHttpRequest

    1.提出者:Jesse James Garrett   2.IE中,XHR是通过ActiveX对象实现的.涉及浏览器的兼容性写法.   3.使用 <1>open("请求方式&qu ...

  4. 欢迎使用 MWeb

    首先介绍一下 MWeb 是什么,MWeb 是专业的 Markdown 写作.记笔记.静态博客生成软件.MWeb 使用的是 Github Flavored Markdown 语法,在使用 MWeb 前, ...

  5. -Android -线程池 批量上传图片 -附php接收代码

    (出处:http://www.cnblogs.com/linguanh/) 目录: 1,前序 2,类特点 3,用法 4,java代码 5,php代码 1,前序 还是源于重构,看着之前为赶时间写着的碎片 ...

  6. android 视频录制 混淆打包 之native层 异常的解决

    原文地址:http://www.cnblogs.com/linguanh/    (滑至文章末,直接看解决方法) 问题起因: 前5天,因为项目里面有个类似 仿微信 视频录制的功能, 先是上网找了个 开 ...

  7. Vertica 业务用户指定资源池加载数据

    之前在"Vertica 安装,建库,新建测试用户并授予权限,建表,入库"这篇文章也简单介绍过入库部分的内容. 但之前测试用例若用于生产环境有明显的局限性: 1.是用dbadmin管 ...

  8. 安装nodejs express框架时express命令行无效

    我也是看了这篇才明白.http://jingyan.baidu.com/article/922554468a3466851648f419.html 最近在看一本书,nodejs开发指南.至于出现这个问 ...

  9. Apache Hadoop2.x 边安装边入门

    完整PDF版本:<Apache Hadoop2.x边安装边入门> 目录 第一部分:Linux环境安装 第一步.配置Vmware NAT网络 一. Vmware网络模式介绍 二. NAT模式 ...

  10. C# listview 单击列头实现排序 <二>

    单击列头实现排序,首先在羡慕中添加下面的帮助实现的类:具体的代码: using System; using System.Collections; using System.Windows.Forms ...