MySQL的索引

概述:mysql

  索引(Index)是帮助MySQL高效获取数据的数据结构。算法

  索引是以表列为基础的数据库对象,它保存着表中排序的索引列,而且记录了索引列在数据表中的物理存储位置,实现了表中数据的逻辑排序,sql

  其主要目的是提升数据库系统的性能,加快数据的查询速度和减小系统的响应时间。数据库

  在MySQL中,索引是在存储引擎层而不是服务器层实现的。因此每种存储引擎的索引都不必定彻底相同。服务器

 

 

MYSQL目前提供了一下4种索引:数据结构

  B-Tree 索引:最多见的索引类型,大部分引擎都支持B树索引。Innodb 存储引擎的 B-Tree 索引实际使用的存储结构其实是 B+树。
  HASH 索引:只有Memory引擎支持,使用场景简单。
  R-Tree 索引(空间索引):空间索引是MyISAM的一种特殊索引类型,主要用于地理空间数据类型。
  Full-text (全文索引):全文索引也是MyISAM的一种特殊索引类型,主要用于全文检索,InnoDB从MYSQL5.6版本提供对全文索引的支持。oracle

 

B-Tree索引:函数

  也就是一般所指的索引。性能

  InnoDB使用B+Tree这种数据结构。优化

  B+Tree:每个叶子节点都包含指向下一个叶子节点的指针,从而方便叶子节点的范围遍历。

  适合查找范围数据。好比:找出全部以I到K开头的名字。

 

B-Tree索引具体又可分为:

普通索引:

  最基本的索引类型。

–直接建立索引
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

 

 

惟一索引:

  索引列的值必须惟一,但容许有空值(注意和主键不一样)。若是是组合索引,则列值的组合必须惟一。

–建立惟一索引
CREATE UNIQUE INDEX indexName ON table(column(length))

–修改表结构
ALTER TABLE table_name ADD UNIQUE indexName 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))
);

 

主键索引:

  它是一种特殊的惟一索引,不容许有空值。通常是在建表的时候同时建立主键索引。

  也能够用 ALTER 命令,但不能用CREATE INDEX语句建立主键索引。

  每一个表只能有一个主键。 (主键至关于聚合索引,是查找最快的索引)

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

 

 

 

多列索引(组合索引):

  ALTER  TABLE  table_name  ADD  INDEX  indexName( name, address ) ; 

  对于多列组合的索引,若是删除其中的某列,则该列也会从索引中删除。若是删除组成索引的全部列,则整个索引将被删除。

 

根据数据的存储方式的不一样,B-Tree索引又可分为汇集索引和非汇集索引

汇集索引:

  CREATE CLUSTERED INDEX indexName ON mytable(mycolumn)

  InnoDB的汇集索引其实是在同一个结构中保存了B-Tree索引和数据行。

  由于没法同时把数据行存放在两个不一样的地方,因此一个表只能有一个汇集索引。

  表数据按照索引的顺序来存储的,也就是说索引项的顺序与表中记录的物理顺序一致。

  对于汇集索引, 叶子结点即存储了真实的数据行,再也不有另外单独的数据页 

 

非汇集索引 : 

  CREATE UNCLUSTERED INDEX indexName ON mytable(mycolumn)

  表数据存储顺序与索引顺序无关。

  对于非汇集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与数据表行数据量一致。

 

可使用B-Tree索引的查询类型,以多列索引key(last_name, first_name, dob)为例:

  • 全值匹配:指定查询的人的fitst_name, last_name和dob;
  • 匹配最左前缀:查找指定了last_name的记录;
  • 匹配列前缀:匹配某一列的值的开头部分,好比last_name以J开头;
  • 精确匹配某一列并范围匹配另外一列:查找last_name为Allen,而且first_name以k开头的;
  • 只访问索引的查询:B-Tree一般能够支持只访问索引的查询,即查询只须要访问索引,而无需访问数据行。

 

B-Tree的一些限制:

  1. 若是不是按照从最左列开始查找,则没法使用索引。例如没法查找只指定了first_name或者dob的记录;
  2. 不能跳过索引中的列:不能在查找的时候只指定了last_name和dob,那么dob不会使用索引。
  3. 若是查询的时候有某个列的查询范围,则其右边的全部列都没法使用索引优化查找。好比对last_name使用了like,那么first_name和dob将不会使用索引。

 

哈希索引:

  基于哈希表实现,只有精确匹配索引全部列的查询才有效。

  由于它对每行中的全部索引列计算出一个哈希码,做为哈希表的键(原理是基于拉链法的解决碰撞的策略)。

  在MySQL中只有Memory引擎显式地支持哈希索引,Memory引擎同时也支持B-Tree索引。

  InnoDB中的自适应哈希索引:某些索引值使用很是频繁时,会在内存中基于B-Tree索引只上再建立一个hash索引。

 

哈希索引的一些限制:

  1. 哈希索引只包含哈希值和行指针,而不存储字段值,因此不能用索引中的值来避免读取行
  2. 哈希索引数据并非按照索引值顺序存储的,因此也就没法用于排序
  3. 哈希索引不支持部分列匹配查找,由于它用全部索引列来计算获得哈希值。
  4. 索引列只支持等值查询,理由同上;
  5. 哈希索引数据查找很是快,除非有不少哈希冲突;
  6. 若是哈希冲突比较高,一些索引维护操做的代价也会很高。好比性别字段,冲突会很高。

 

空间数据索引(R-Tree):

  ALTER  TABLE  table_name  ADD  SPATIAL  INDEX  indexName( line ) ; 

  MyISAM表支持空间索引,能够用做地理数据存储。

  空间索引会从全部维度来索引数据,能够有效地使用任意维度来进行组合查询。

  必须使用 GIS 相关的函数来维护数据。

 

全文索引:

  它查找的是文本中的关键词,而不是直接比较索引中的值。

  使用 MATCH AGAINST,而不是普通的 WHERE。

–直接建立索引
CREATE FULLTEXT INDEX index_content ON article(content)

 –修改表结构添加全文索引
 ALTER TABLE article ADD FULLTEXT index_content(content)

 

 

 索引的优势:

  建立惟一性索引,保证数据库表中每一行数据的惟一性
  大大加快数据的检索速度,这也是建立索引的最主要的缘由
  加速表和表之间的链接,特别是在实现数据的参考完整性方面特别有意义。
  在使用分组和排序子句进行数据检索时,一样能够显著减小查询中分组和排序的时间。
  经过使用索引,能够在查询的过程当中使用优化隐藏器,提升系统的性能。

 


索引的缺点 :
  建立索引和维护索引要耗费时间,这种时间随着数据量的增长而增长
  索引须要占物理空间,除了数据表占数据空间以外,每个索引还要占必定的物理空间,若是要创建聚簇索引,那么须要的空间就会更大
  当对表中的数据进行增长、删除和修改的时候,索引也要动态的维护,下降了数据的维护速度

 

应该在这些列上建立索引:

  在常常须要搜索的列上,能够加快搜索的速度; 
  在做为主键的列上,强制该列的惟一性和组织表中数据的排列结构; 
  在常常用在链接的列上,这些列主要是一些外键,能够加快链接的速度; 
  在常常须要根据范围进行搜索的列上建立索引,由于索引已经排序,其指定的范围是连续的; 
  在常常须要排序的列上建立索引,由于索引已经排序,这样查询能够利用索引的排序,加快排序查询时间; 
  在常用在WHERE子句中的列上面建立索引,加快条件的判断速度。

 

不该该建立索引的的这些列具备下列特色:

  第一,对于那些在查询中不多使用或者参考的列不该该建立索引。这是由于,既然这些列不多使用到,所以有索引或者无索引,并不能提升查询速度。相反,因为增长了索引,反而下降了系统的维护速度和增大了空间需求。 
  第二,对于那些只有不多数据值的列也不该该增长索引。这是由于,因为这些列的取值不多,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即须要在表中搜索的数据行的比例很大。增长索引,并不能明显加快检索速度。 
  第三,对于那些定义为text, image和bit数据类型的列不该该增长索引。这是由于,这些列的数据量要么至关大,要么取值不多。 
  第四,当修改性能远远大于检索性能时,不该该建立索引。这是由于,修改性能和检索性能是互相矛盾的。当增长索引时,会提升检索性能,可是会下降修改性能。当减小索引时,会提升修改性能,下降检索性能。所以,当修改性能远远大于检索性能时,不该该建立索引。

 

索引选择原则:

  较频繁的做为查询条件的字段应该建立索引

  定义有主键的数据列必定要创建索引。由于主键能够加速定位到表中的某一行。 

  定义有外键的数据列必定要创建索引。外键列一般用于表与表之间的链接,在其上建立索引能够加快表间的链接。

  惟一性太差的字段不适合单首创建索引,即便频繁做为查询条件,好比性别只有男,女

  更新很是频繁的字段不适合建立索引

  不会出如今 WHERE 子句中的字段不应建立索引

  表记录比较少,例如一两千条甚至只有几百条记录的表,不必建索引,让查询作全表扫描就行了;

  对于定义为text、image和bit数据类型的列不要创建索引。

  能够考虑使用索引的主要有 两种类型的列:在where子句中出现的列,在join子句中出现的列,而不是在SELECT关键字后选择列表的列;

  使用短索引,若是对字符串列进行索引,应该指定一个前缀长度,可节省大量索引空间,提高查询速度;好比很长的字符串,对前10个或者20个字符进行索引可以节省大量索引空间,也可能会使查询更快。

  利用最左前缀:Mysql会一直向右查找直到遇到范围操做(>,<,like、between)就中止匹配。好比a=1 and b=2 and c>3 and d=6;此时若是创建了(a,b,c,d)索引,那么后面的d索引是彻底没有用到,当换成了(a,b,d,c)就能够用到。

  MySQL只对一下操做符才使用索引:<,<=,=,>,>=,between,in, 以及某些时候的like(不以通配符%或_开头的情形)。

  不要过分索引,只保持所需的索引。每一个额外的索引都要占用额外的磁盘空间,并下降写操做的性能。 在修改表的内容时,索引必须进行更新,有时可能须要重构,所以,索引越多,所花的时间越长。

 

惟一索引与主键索引的比较:

惟一索引:
  惟一索引不容许两行具备相同的索引值。
主键索引:
  主键索引是惟一索引的特殊类型。
  数据库表一般有一列或列组合,其值用来惟一标识表中的每一行。该列称为表的主键。
  在数据库关系图中为表定义一个主键将自动建立主键索引,主键索引是惟一索引的特殊类型。主键索引要求主键中的每一个值是惟一的。当在查询中使用主键索引时,它还容许快速访问数据。
 
它们的一些比较:
  (1)对于主健/unique constraint , oracle/sql server/mysql等都会自动创建惟一索引;
  (2)主键不必定只包含一个字段,因此若是你在主键的其中一个字段建惟一索引仍是必要的;
  (3)主健可做外健,惟一索引不可;
  (4)主健不可为空,惟一索引可;(惟一索引还能够有多个NULL值)
  (5)主健也但是多个字段的组合;
  (6)主键与惟一索引不一样的是:
    a.有not null属性;
    b.每一个表只能有一个。
 
索引失效:
  1. 若是条件中有or,即便其中有条件带索引也不会使用(这也是为何尽可能少用or的缘由。要想使用or,又想让索引生效,只能将or条件中的每一个列都加上索引)
  2. 对于多列索引,不是使用的第一部分,则不会使用索引
  3. like查询是以%开头
  4. 若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引

 

Hash索引和btree索引的区别:

Hash 索引结构的特殊性,其检索效率很是高,索引的检索能够一次定位,不像B-Tree 索引须要从根节点到枝节点,最后才能访问到页节点这样屡次的IO访问,因此 Hash 索引的查询效率要远高于 B-Tree 索引。
(1)Hash 索引仅仅能知足"=","IN"和"<=>"查询,不能使用范围查询。
  因为 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 值相关联。这样要定位某一条记录时就会很是麻烦,会浪费屡次表数据的访问,而形成总体性能低下。
 
 
  若是存储的数据重复度很低(也就是说基数很大),对该列数据以等值查询为主,没有范围查询、没有排序的时候,特别适合采用哈希索引
相关文章
相关标签/搜索