为什么需要索引(Why is it needed)?

当数据保存在磁盘类存储介质上时,它是作为数据块存放。这些数据块是被当作一个整体来访问的,这样可以保证操作的原子性(原子性是指一个完整的事务程序,要么成功,要么失败回滚)。硬盘数据块存储结构类似于链表,都包含数据部分,以及一个指向下一个节点(或数据块)的指针,不需要连续存储。

记录集只能在某个关键字段上进行排序,所以如果需要在一个无序字段上进行搜索,就要执行一个线性搜索(Linear Search)的过程,平均需要访问N/2的数据块,N是表所占据的数据块数目。如果这个字段是一个非主键字段(也就是说,不包含唯一的访问入口),那么需要在N个数据块上搜索整个表格空间。

但是对于一个有序字段,可以运用二分查找(Binary Search),这样只要访问log2 (N)的数据块。这就是为什么性能能得到本质上的提高。

什么是索引(What is indexing)?

索引是对记录集的多个字段进行排序的方法。在一张表中为一个字段创建一个索引,将创建另外一个数据结构,包含字段数值以及指向相关记录的指针,然后对这个索引结构进行排序,允许在该数据上进行二分法查找。

二分法排序详解可查看此连接http://blog.csdn.net/zimuxin/article/details/78475719

副作用是索引需要额外的磁盘空间,对于MyISAM引擎而言,这些索引是被统一保存在一张表中的,如果很多字段都建立了索引的话,这个文件将很快到达底层文件系统所能够支持的大小限制。

索引如何工作(How does it work?)

首先,我们建立一个示范数据库表:

字段名       数据类型     大小
id (Primary key) Unsigned INT   4 bytes
firstName        Char(50)      50 bytes
lastName         Char(50)      50 bytes
emailAddress     Char(100)     100 bytes
注意:使用char是为了指定准确的磁盘占用大小。这个示范数据库包含500万行,而且没有索引。我们将分析一些查询语句的性能,一个是使用主键id(有序)查询,一个是使用firstName(非关键无序字段)。

例1

我们的示范数据库有r=5,000,000条记录,每条记录长度R=204字节而且使用MyISAM引擎存储(默认数据块大小为B=1024字节),这张表的块因子(blocking factor)会是bfr = (B/R) = 1024/204 = 5条记录每磁盘数据块。保存这张表所需要的磁盘块为N = (r/bfr) = 5000000/5 =1,000,000 blocks。

在id字段上的线性搜索平均需要N/2 = 500,000块访问来找到一条记录假设id字段是查询关键值,不过既然id字段是有序的,可以执行一个二分查询,这样平均只需要访问log2 (1000000)= 19.93 = 20 个数据块。我们马上就看到了极大的提高。

现在firstName字段既不是有序的,无法执行二分搜索,数值也不具有唯一性,所以对这张表的查找必须到最后一个记录即全表扫描N = 1,000,000个数据块访问。这就是索引用来改进的地方。

假如索引记录只包含一个索引列以及一个指向原记录数据的指针,那么它显而易见会比原记录(多列)要小。所以索引本身所需要的磁盘块要更少,扫描数目也少。firstName索引表结构如下:

Field name       Data type     Size on disk
firstName        Char(50)      50 bytes
(record pointer) Special       4 bytes
注意:MySQL里的指针按表大小的不同分别可能是 2, 3, 4 或5 个字节。

例2

假设我们的数据库有r = 5,000,000 条记录,建立了一个长R = 54字节的索引,并且使用默认磁盘块大小为1,024字节。那么该索引的块因子为bfr = (B/R) = 1024/54 = 18条记录每磁盘块。容纳这个索引表总共需要的磁盘块为N = (r/bfr) = 5000000/18 =277,778 块。

现在使用FirstName字段来进行搜索就可以利用索引来提高性能。这允许使用一个二分查找,平均log2(277778) = 18.08 -> 19次数据块访问。找到实际记录的地址,这需要进一步的块读取,这样总数达到19 + 1 = 20次数据块访问,这和非索引表的数据块访问次数有天壤之别。

什么时候使用索引(When should it be used?)

鉴于创建索引需要额外的磁盘空间(上面的例子需要额外的277778个磁盘块),以及太多的索引会导致文件系统大小限制所产生的问题,所以对哪些字段建立索引,什么情况下使用索引,需要审慎考虑。

比如唯一性太差的字段不用加,比如SEX

还有字段经常改变的,也不太建议加

由于索引只是用来加速数据查询,那么显然对只是用来输出的字段建立索引会浪费磁盘空间以及发生插入、删除操作时的处理时间,所以这种情况下应该尽量避免。此外鉴于二分搜索的特性,数据的基数或独立性是很重要的。在基数为2的字段上建立索引,将把数据分割一半,而基数为1000则将返回大约1000条记录。低基数的二分查找效率将降低为一个线性排序,而且查询优化器可能会在基数小于记录数某个比例时(如30%)的情况下将避免使用索引而直接查询原表,所以这种情况下的索引浪费了空间。

索引方式区别

目前索引有两种方法

btree索引和hash索引

1.HASH 索引

Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash索引的查询效率要远高于 B-Tree索引。可能很多人又有疑问了,既然 Hash索引的效率要比 B-Tree高很多,为什么大家不都用 Hash索引而还要使用 B-Tree索引呢?任何事物都是有两面性的,Hash索引也一样,虽然 Hash索引效率高,但是 Hash索引本身由于其特殊性也带来了很多限制和弊端,主要有以下这些。
(1)Hash索引仅仅能满足'=','IN'和'<=>'查询,不能使用范围查询。

(<=>解释

和=号的相同点

像常规的=运算符一样,两个值进行比较,结果是0(不等于)或1(相等);换句话说:'A'<=>'B'得0和'a'<=>'a‘得1。

2.和=号的不同点

和=运算符不同的是,NULL的值是没有任何意义的。所以=号运算符不能把NULL作为有效的结果。所以:请使用<=>,

'a' <=> NULL 得0  NULL<=> NULL得出1。和=运算符正相反,=号运算符规则是 'a'=NULL 结果是NULL 甚至NULL = NULL 结果也是NULL。顺便说一句,mysql上几乎所有的操作符和函数都是这样工作的,因为和NULL比较基本上都没有意义。

除了 <=> ,还有两个其他的操作符用来处理某个值和NULL做比较,也就是IS NULL and IS NOT NULL。他们是ANSI标准中的一部分,因此也可以用在其他数据库中。而<=>只能在mysql中使用。

你可以把<=>当作mysql中的方言。

?

1

2

'a' IS NULL   ==> 'a' <=> NULL

'a' IS NOT NULL ==> NOT('a' <=> NULL)

据此,你可以把这个查询语句段改的更具移植性一点:
WHERE p.name ISNULL)

由于 Hash索引比较的是进行 Hash运算之后的 Hash值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样。
(2)Hash索引无法被用来避免数据的排序操作。
由于 Hash索引中存放的是经过 Hash计算之后的 Hash值,而且Hash值的大小关系并不一定和 Hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;
(3)Hash索引不能利用部分索引键查询。
对于组合索引,Hash索引在计算 Hash值的时候是组合索引键合并后再一起计算 Hash值,而不是单独计算 Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用。
(4)Hash索引在任何时候都不能避免表扫描。
前面已经知道,Hash索引是将索引键通过 Hash运算之后,将 Hash运算结果的 Hash值和所对应的行指针信息存放于一个 Hash表中,由于不同索引键存在相同 Hash值,所以即使取满足某个 Hash键值的数据的记录条数,也无法从 Hash索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。
(5)Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。
对于选择性比较低的索引键,如果创建 Hash索引,那么将会存在大量记录指针信息存于同一个 Hash值相关联。这样要定位 某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下,这里就是我上面说的SEX字段

2. B-Tree索引

B-Tree 索引是 MySQL数据库中使用最为频繁的索引类型,除了 Archive( 从archive单词的解释我们大概可以明白这个存储引擎的用途,这个存储引擎基本上用于数据归档;它的压缩比非常的高,存储空间大概是innodb的10-15分之一所以它用来存储历史数据非常的适合,由于它不支持索引同时也不能缓存索引和数据,所以它不适合作为并发访问表的存储引擎。Archivec存储引擎使用行锁来实现高并发插入操作,但是它不支持事务,其设计目标只是提供高速的插入和压缩功能。)存储引擎之外的其他所有的存储引擎都支持 B-Tree 索引。不仅仅在 MySQL中是如此,实际上在其他的很多数据库管理系统中B-Tree索引也同样是作为最主要的索引类型,这主要是因为 B-Tree索引的存储结构在数据库的数据检索中有非常优异的表现。
一般来说, MySQL中的 B-Tree索引的物理文件大多都是以 Balance Tree(平衡树)的结构来存储的,也就是所有实际需要的数据都存放于 Tree的 Leaf Node(叶节点),而且到任何一个 Leaf Node的最短路径的长度都是完全相同的,所以我们大家都称之为 B-Tree索引当然,可能各种数据库(或 MySQL的各种存储引擎)在存放自己的 B-Tree索引的时候会对存储结构稍作改造。如 Innodb存储引擎的 B-Tree索引实际使用的存储结构实际上是B+Tree,也就是在B-Tree数据结构的基础上做了很小的改造,在每一个
Leaf Node 上面出了存放索引键的相关信息之外,还存储了指向与该Leaf Node相邻的后一个LeafNode的指针信息,这主要是为了加快检索多个相邻Leaf Node的效率考虑。
在 Innodb存储引擎中,存在两种不同形式的索引,一种是 Cluster(集群)形式的主键索引( Primary Key ),另外一种则是和其他存储引擎(如 MyISAM存储引擎)存放形式基本相同的普通 B-Tree索引,这种索引在 Innodb存储引擎中被称为 Secondary Index(辅助索引)。下面我们通过图示来针对这两种索引的存放
形式做一个比较。

X


图示中左边为 Clustered形式存放的 Primary Key,右侧则为普通的 B-Tree索引。两种 Root Node(根节点)和 Branch Nodes(分支节点)方面都还是完全一样的。而 Leaf Nodes就出现差异了。在 Prim中, Leaf Nodes存放的是表的实际数据,不仅仅包括主键字段的数据,还包括其他字段的数据据以主键值有序的排列。而 Secondary Index则和其他普通的 B-Tree索引没有太大的差异,Leaf Nodes出了存放索引键的相关信息外,还存放了 Innodb的主键值。
所以,在 Innodb中如果通过主键来访问数据效率是非常高的,而如果是通过 Secondary Index来访问数据的话,Innodb首先通过 Secondary Index的相关信息,通过相应的索引键检索到Leaf Node之后,需要再通过Leaf Node中存放的主键值再通过主键索引来获取相应的数据行。MyISAM存储引擎的主键索引和非主键索引差别很小,只不过是主键索引的索引键是一个唯一且非空的键而已。而且 MyISAM存储引擎的索引和 Innodb的 Secondary Index的存储结构也基本相同,主要的区别只是 MyISAM存储引擎在 Leaf Nodes上面出了存放索引键信息之外,再存放能直接定位到 MyISAM数据文件中相应的数据行的信息(如 Row Number(行数)),但并不会存放主键的键值信息

mysql 索引左向

以该表的(name,cid)复合索引为例,它内部结构简单说就是下面这样排列的:

mysql创建复合索引的规则是首先会对复合索引的最左边的,也就是第一个name字段的数据进行排序,在第一个字段的排序基础上,然后再对后面第二个的cid字段进行排序。

其实就相当于实现了类似 order by name cid这样一种排序规则。

所以:第一个name字段是绝对有序的,而第二字段就是无序的了。

所以通常情况下,直接使用第二个cid字段进行条件判断是用不到索引的,当然,可能会出现使用index类型的索引。

这就是所谓的mysql为什么要强调最左前缀原则的原因

MYSQL 索引相关相关推荐

  1. Mysql数据库(四)——mysql索引相关知识

    Mysql数据库(四)--mysql索引相关知识 一.索引的概念 二.索引的优缺点 1.优点 2.缺点 三.创建索引的原则 四.索引的分类和创建方法 1.普通索引 ①.直接创建索引 ②.修改表方式创建 ...

  2. MySQL索引相关知识整理学习

    MySQL索引相关知识整理学习 前言 一.MySQL索引 哈希索引 B+树索引 B+树的优点 聚簇索引 非聚簇索引 聚簇索引和非聚簇索引的特点及区别: 二.特殊类型的索引 1.覆盖索引 2.联合索引 ...

  3. 一文整理14道MySQL索引相关面试题

    精心整理14道MySQL索引相关面试题(珍藏版) 如果仅仅是死记硬背MySQL索引相关面试题一定是相当枯燥的,不容易记却容易忘,这里循序渐进的讲解有关索引有关知识点,让大家在理解的基础上记住一些面试常 ...

  4. MySQL索引相关的数据结构和算法

    索引相关的数据结构和算法 通常我们所说的索引是指B-Tree索引,它是目前关系型数据库中查找数据最为常用和有效的索引,大多数存储引擎都支持这种索引.使用B-Tree这个术语,是因为MySQL在CREA ...

  5. 几道MySQL索引相关的重点面试题

    MySQL 索引你真的懂吗?这几道题带你了解索引的几个重要知识点 1. 什么是最左前缀原则? 以下回答全部是基于MySQL的InnoDB引擎 例如对于下面这一张表 如果我们按照 name 字段来建立索 ...

  6. MySQL索引相关知识

    MySQl索引创建   一.什么是索引? 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直 ...

  7. 了解mysql文章_一篇文章带你深入了解MySQL 索引相关

    基础知识 一张数据表中具有百万级的数据时,如何精确且快速的拿出其中某一条或多条记录成为了人们思考的问题. InnoDB 存储引擎的出现让这个问题得到了很好的解决, InnoDB 存储引擎是以索引来进行 ...

  8. MySQL 索引相关知识

    今天又手贱,路边走的时候顺手拽一片叶子下来.不得不说,不知是那叶子漂亮,还是单身久了看片叶子都眉清目秀的.就把它夹在了书里,做个标本.等我第二天去观察标本好了没,哦,找不到了,我就一张一张的翻过书页, ...

  9. mysql索引相关面试题

    mysql桶 存储引擎分类有哪些以及使用场景? 创建索引的原则? 索引失效情况? ==校验SQL语句是否使用了索引方式为:在SQL语句前面使用explain关键字== 索引分类? linux添加索引 ...

最新文章

  1. python运维开发之第十一天(RabbitMQ,redis)
  2. Navicat Monitor v1.7的新功能说明
  3. PostgreSQL消息乱码的解决
  4. 使用myeclipse建立maven项目(重要)
  5. php表格怎么合并单元格格式化,table标签的结构与合并单元格的实现方法
  6. swift inheritace 继承
  7. docker镜像创建与优化
  8. linux C总结篇(进程)
  9. NumPy入门攻略:手把手带你玩转这款强大的数据分析和计算工具
  10. android中的add方法,Android中Fragment怎么addView?
  11. Java io流小技巧_选择用流的小规律(java)基本的io流
  12. 【英语学习】【WOTD】encroach 释义/词源/示例
  13. TStringGrid - 重绘时RECT解决一块空白区域
  14. 美国下注15亿美元重点搞芯片!电子复兴5年计划首批入围项目曝光
  15. 如何实现百万TPS?详解JMQ4的存储设计
  16. ajax后台重定向会返回什么_处理jquery ajax重定向
  17. 赶紧收藏!这些思维导图软件,手机上也能用
  18. [置顶] 我也来学习nodejs 没有就自己来 色色实现迷你 MVC
  19. PUBWIN密码攻防战 打造永攻不破的密码!(转)
  20. Dockerfile指令详解镜像构建实例说明

热门文章

  1. 一次向svn中增加所有新增文件 svn add all new files【转】
  2. 链表——PowerShell版
  3. MVC ScriptBundle自定义排序。
  4. postfix+mysql+dovecot
  5. 远程登录的机器不是域控制器的方法
  6. springboot配置spring.profiles.active多环境支持
  7. 个人代码库のC#千千静听 - 桌面歌词 (功能模拟)
  8. Spring @EventListener 异步中使用condition的问题
  9. Qt5.3.2openglVS2010_QSqlField_字段类型
  10. 淘宝——移动端页面终端适配