数据库之索引

目录

1.简介

2 索引类型

2.1、从数据结构角度

2.2、从物理存储角度

2.3、从逻辑角度

3 索引创建方式

4 索引的优化

5 索引结构

6 索引总结


1.简介

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树

在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

索引的重要性:当你的数据库的性能出现问题了,那么就重新优化你的索引吧,这能够解决80%的性能问题,由此可见索引的重要性,尤其在

MySQL数据库几个基本的索引类型:普通索引、唯一索引、主键索引、全文索引

索引又可分为聚簇索引非聚簇索引两种

1.索引加快数据库的检索速度

2.索引降低了插入、删除、修改等维护任务的速度

3.唯一索引可以确保每一行数据的唯一性

4.通过使用索引,可以在查询的过程中使用优化隐藏器,提高系统的性能

5.索引需要占物理和数据空间

数据量越来越大的时候,影响更加的明显,一个最优的索引能够轻易的将查询性能提高好几个数量级

索引的弊端和缺点:
1. 索引会占用一部分存储空间,尤其在数据量很大的时候占用的存储空间可是很客观的;
2. 一旦对数据进行了插入、删除、修改等操作,要对索引进行动态的维护。

但是总的来说利还是大于弊的,所以我们设计数据库的时候需要善于利用索引,善于优化索引。

索引是最好的提高查询解决方案吗?
答案: 不一定,只有当索引帮助存储引擎快速查找带来的好处大于其带来的额外开销时,索引才是有效的。
对于非常小的表,大部分情况下全表扫描更加有效
对于大中型的表,索引非常有效
对于特大型的表,建立和维护索引的代价特别大,索引就不是那么有效了,可以使用分区技术,来进行一组数据的查询(而不是一条一条的匹配),对于更大的TB级别的数据,经常会使用块级别的元数据技术来代替索引,例如Infobright

什么地方该用索引,什么地方应该避免使用索引?
使用索引:
1. 在数据量超过几百行之后就应该考虑建立索引,在主键上建立索引,保证数据的唯一性和组织表中的数据排列结构
2. 在经常使用到的查询列上建立索引,比如 where name = “wang” ,经常做这样的查询,那么name上就应该建立索引
3. 在经常进行范围查询的列上建立索引(可以建立聚簇索引,让索引的顺序和数据的物理存放顺序一致,这样大大的加快的查找的速度,变随机查找为顺序查找)
4. 在经常用在连接的列上,在连接字段列上建立索引,这些列主要是一些外键,可以加快连接的速度;
5. 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
不该使用索引
1. 数据量太小不要建立索引,因为维护的代价要高于建立索引之后优化的代价
2. 经常频繁更新的列不要建立索引,因为一旦更新,就要对索引也要随之更新,如果更新的代价比查询的代价高,那就不要建立索引
3. 不经常被引用、查询的列不要建立索引,因为没有必要
4. 对于那些列的取值很少(比如性别),或者text等类型的大文本字段不要建立索引,大文本字段的索引也会很长,影响查询

2 索引类型

索引的分类可以从多个角度进行,下面分别从数据结构,物理存储和业务逻辑三个维度进行划分。

2.1、从数据结构角度

(1)B+树索引(O(log(n)))

关于B+树索引,后面会深入解析

(2)hash索引

仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引只有Memory存储引擎显示支持hash索引(3)FULLTEXT索引

现在MyISAM和InnoDB引擎都支持了

(4)R-Tree索引

用于对GIS数据类型创建SPATIAL索引

2.2、从物理存储角度

(1)聚集索引(clustered index)

正文内容按照一个特定维度排序存储,这个特定的维度就是聚集索引;Innodb存储引擎中行记录就是按照聚集索引维度顺序存储的,Innodb的表也称为索引表;因为行记录只能按照一个维度进行排序,所以一张表只能有一个聚集索引。

(2)非聚集索引(non-clustered index)

索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。

非聚集索引索引项顺序存储,但索引项对应的内容却是随机存储的;举个例子说明下:

 

该表中主键id是该表的聚集索引、name为非聚集索引;表中的每行数据都是按照聚集索引id排序存储的;比如要查找name='Arla'和name='Arle'的两个同学,他们在name索引表中位置可能是相邻的,但是实际存储位置可能差的很远。name索引表节点按照name排序,检索的是每一行数据的主键。聚集索引表按照主键id排序,检索的是每一行数据的真实内容。

2.3、从逻辑角度

(1)主键索引

主键索引是一种特殊的唯一索引,不允许有空值

(2)普通索引或者单列索引

(3)多列索引(复合索引)

复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合

(4)唯一索引或者非唯一索引

(5)空间索引

空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。

MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建.

3 索引创建方式

参考菜鸟教程,创建索引

1、普通索引
这是最基本的索引,它没有任何限制,比如上文中为title字段创建的索引就是一个普通索引,MyIASM中默认的BTREE类型的索引,也是我们大多数情况下用到的索引。
创建方式:

  • 直接创建索引
CREATE INDEX index_name ON table(column(length))
  • 修改表结构的方式添加索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length))
  • 创建表的时候同时创建索引
CREATE TABLE `table` (
	`id` int(11) NOT NULL AUTO_INCREMENT ,
	`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
	`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
	`time` int(10) NULL DEFAULT NULL ,
	PRIMARY KEY (`id`),
	INDEX index_name (title(length))
)
  • 删除索引
DROP INDEX index_name ON table

2、唯一索引
与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须是唯一的,创建方法和普通索引类似。

  • 创建唯一索引
CREATE UNIQUE INDEX index_name ON table(column(length)) 
  • 修改表结构
ALTER TABLE table_name ADD UNIQUE INDEX index_name ON (column(length))
  • 创建表时同时创建索引
CREATE TABLE `table` (
	`id` int(11) NOT NULL AUTO_INCREMENT ,
	`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
	`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
	`time` int(10) NULL DEFAULT NULL ,
	PRIMARY KEY (`id`),
	UNIQUE indexName (title(length))
);

3、组合索引
平时用的SQL查询
语句一般都有比较多的限制条件,所以为了进一步榨取MySQL的效率,就要考虑建立组合索引。例如上表中针对title和time建立一个组合索引:

ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))

建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:

–title,time

–title

为什么没有time这样的组合索引呢?这是因为MySQL组合索引最左前缀”的结果。
简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:

  • 使用到上面的索引
SELECT * FROM article WHREE title='测试' AND time=1234567890;

SELECT * FROM article WHREE utitle='测试';
  • 未使用到上面的索引
SELECT * FROM article WHREE time=1234567890;

以上就是常用的三种索引类型及其创建使用的方法,当然还有其他的类型,这里我就列举我们平时最常用的几种,更详细和全面的索引相关资料请咨询度娘。

4 主键索引

它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引:

CREATE TABLE mytable(  
 
ID INT NOT NULL,   
 
username VARCHAR(16) NOT NULL,  
 
PRIMARY KEY(ID)  
 
);  

当然也可以用 ALTER 命令。记住:一个表只能有一个主键。

4 索引的优化

上面说了使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。下面是一些总结以及收藏的MySQL索引的注意事项和优化方法。

1. 何时使用聚集索引或非聚集索引?
在这里插入图片描述
事实上,我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如:返回某范围内的数据一项。比如您的某个表有一个时间列,恰好您把聚合索引建立在了该列,这时您查询2004年1月1日至2004年10月1日之间的全部数据时,这个速度就将是很快的,因为您的这本字典正文是按日期进行排序的,聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可;而不像非聚集索引,必须先查到目录中查到每一项数据对应的页码,然后再根据页码查到具体内容。

2. 索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

3. 使用短索引

对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

4. 索引列排序

MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

5. like语句操作

一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。

6. 不要在列上进行运算

例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:select * from users where adddate<’2007-01-01′。关于这一点可以围观:一个单引号引发的MYSQL性能损失。

最后总结一下,MySQL只对以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。
而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引会引起反作用,索引虽好用,可不要太迷恋噢。

5 索引结构

索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型的。MySQL目前提供了以下4种索引:

  • BTREE 索引 : 最常见的索引类型,大部分索引都支持 B 树索引。

  • HASH 索引:只有Memory引擎支持 , 使用场景简单 。

  • R-tree 索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。

  • Full-text (全文索引) :全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。

MyISAM、InnoDB、Memory三种存储引擎对各种索引类型的支持

索引InnoDB引擎MyISAM引擎Memory引擎
BTREE索引支持支持支持
HASH 索引不支持不支持支持
R-tree 索引不支持支持不支持
Full-text5.6版本之后支持支持不支持

我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引。

2.3.1 BTREE 结构

BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下:

  • 树中每个节点最多包含m个孩子。

  • 除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子。

  • 若根节点不是叶子节点,则至少有两个孩子。

  • 所有的叶子节点都在同一层。

  • 每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1] <= n <= m-1

以5叉BTree为例,key的数量:公式推导[ceil(m/2)-1] <= n <= m-1。所以 2 <= n <=4 。当n>4时,中间节点分裂到父节点,两边节点分裂。

插入 C N G A H E K Q M F W L T Z D P R X Y S 数据为例。

演变过程如下:

1). 插入前4个字母 C N G A

2). 插入H,n>4,中间元素G字母向上分裂到新的节点

3). 插入E,K,Q不需要分裂

4). 插入M,中间元素M字母向上分裂到父节点G

5). 插入F,W,L,T不需要分裂

6). 插入Z,中间元素T向上分裂到父节点中

7). 插入D,中间元素D向上分裂到父节点中。然后插入P,R,X,Y不需要分裂

8). 最后插入S,NPQR节点n>5,中间节点Q向上分裂,但分裂后父节点DGMT的n>5,中间节点M向上分裂

到此,该BTREE树就已经构建完成了, BTREE树 和 二叉树 相比, 查询数据的效率更高, 因为对于相同的数据量来说,BTREE的层级结构比二叉树小,因此搜索速度快。

2.3.3 B+TREE 结构

B+Tree为BTree的变种,B+Tree与BTree的区别为:

1). n叉B+Tree最多含有n个key,而BTree最多含有n-1个key。

2). B+Tree的叶子节点保存所有的key信息,依key大小顺序排列。

3). 所有的非叶子节点都可以看作是key的索引部分。

由于B+Tree只有叶子节点保存key信息,查询任何key都要从root走到叶子。所以B+Tree的查询效率更加稳定。

MySQL中的B+Tree

MySql索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能。

MySQL中的 B+Tree 索引结构示意图:

6 索引总结

索引查询是数据库中重要的记录查询方法,要不要进入索引以及在那些字段上建立索引都要和实际数据库系统的查询要求结合来考虑,下面给出实际中的一些通用的原则:

  1. 在经常用作过滤器的字段上建立索引;
  2. 在SQL语句中经常进行GROUP BY、ORDER BY的字段上建立索引;
  3. 在不同值较少的字段上不必要建立索引,如性别字段;
  4. 对于经常存取的列避免建立索引;
  5. 用于联接的列(主健/外健)上建立索引;
  6. 在经常存取的多个列上建立复合索引,但要注意复合索引的建立顺序要按照使用的频度来确定;
  7. 缺省情况下建立的是非簇集索引,但在以下情况下最好考虑簇集索引,如:含有有限数目(不是很少)唯一的列;进行大范围的查询;充分的利用索引可以减少表扫描I/0的次数,有效的避免对整表的搜索。
  8. 经常用在WHERE子句中的数据列;
  9. 经常出现在关键字order by、group by、distinct后面的字段,建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用;
  10. 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引;
  11. 对于定义为text、image和bit的数据类型的列不要建立索引;
  12. 限制表上的索引数目。对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个。索引虽说提高了访问速度,但太多索引会影响数据的更新操作。
  13. 对复合索引,按照字段在查询条件中出现的频度建立索引。在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。

1、组合多个索引

一个单独的索引扫描只能用于这样的条件子句:使用被索引字段和索引操作符类中的操作符, 并且这些条件以AND连接。

假设在(a, b)上有一个索引, 那么类似WHERE a = 5 AND b = 6的条件可以使用索引,但是像WHERE a = 5 OR b = 6的条件就不能直接使用索引。

一个类似WHERE x =42 OR x = 47 OR x = 53 OR x = 99 这样的查询可以分解成四个在x上的独立扫描,每个扫描使用一个条件, 最后将这些扫描的结果OR 在一起,生成最终结果。

另外一个例子是,如果我们在x 和y上有独立的索引,一个类似WHERE x = 5 AND y = 6 这样的查询可以分解为几个使用独立索引的子句,然后把这几个结果AND 在一起,生成最终结果。

索引失效有哪几种情况

如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)对于多列索引,不是使用的第一部分(第一个),则不会使用索引like查询是以%开头如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引如果mysql估计使用全表扫描要比使用索引快,则不使用索引1、联合索引失效的条件

联合索引又叫复合索引。两个或更多个列上的索引被称作复合索引。

对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c)。 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。

所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。

 

 

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值