(十二)MySQL中的索引


1、概述

  索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。可以将索引理解为一本书前面的目录,能加快数据的查询速度。
  对于没有索引的表,MySQL会遍历全部数据后选择符合条件的记录,因此单表查询可能几十万数据就是瓶颈,而通常大型网站单日就可能会产生几十万甚至几百万的数据,没有索引查询会变的非常缓慢,而有了相应的索引之后,MySQL会直接在索引中查找符合条件的选项,效率会大大提升。

  索引分为聚簇索引和非聚簇索引两种:

  1. 聚簇索引是按照数据存放的物理位置为顺序的,对于数据而言,通常来说物理顺序结构只有一种,因此每张数据表也只能有一个聚簇索引。在设置主键时,系统会默认为其加上聚簇索引,当然也可以使用其他字段作为索引,此时需要在设置主键之前先手动为待选字段添加上唯一的聚簇索引,然后再设置主键,就可以解决这一问题。
  • 非聚簇索引记录的物理顺序与逻辑顺序没有必然的联系,与数据的存储物理位置也没有关系;每张数据表对应的非聚簇索引可以有多个,根据不同列的约束可以建立不同要求的非聚簇索引。

  简单总结即,聚簇索引能提高多行检索的效率,而非聚簇索引对于单行的检索更有效。


2、索引的类型

普通索引

  普通索引是最基本的索引,它没有任何限制,是大多数情况下用到的索引。

直接创建索引
CREATE INDEX index_name ON tbl_name(col_name(length));
修改数据表结构时添加索引
ALTER TABLE tbl_name ADD INDEX index_name (col_name(length));
创建数据表时同时创建索引
CREATE TABLE tbl_name (
……
INDEX index_name (col_name(length))
)

唯一索引

  唯一索引与普通索引类似,不同之处是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。

直接创建索引
CREATE UNIQUE INDEX index_name ON tbl_name(col_name(length));
修改数据表结构时添加索引
ALTER TABLE tbl_name ADD UNIQUE index_name (col_name(length));
创建数据表时同时创建索引
CREATE TABLE tbl_name (
……
UNIQUE index_name (col_name(length))
)

全文索引

  全文索引仅可用于MyISAM数据表,对于较大的数据集而言,将资料输入进一个没有全文索引的数据表中,然后创建索引;其速度远比把资料输入现有全文索引的数据表中更快。不过对于大容量的数据表来说,生成全文索引是一个非常消耗时间及硬盘空间的做法。

直接创建索引
CREATE FULLTEXT INDEX index_name ON tbl_name(col_name(length));
修改数据表结构时添加索引
ALTER TABLE tbl_name ADD FULLTEXT index_name (col_name(length));
创建数据表时同时创建索引
CREATE TABLE tbl_name (
……
FULLTEXT index_name (col_name(length))
)

多列索引、单列索引

  单个多列索引与多个单列索引的查询效果不同。当使用多个单列索引并执行查询时,MySQL只会从多个索引中选择一个限制最为严格的索引,剩余的索引将起不到作用。在建立多列索引时,字段的顺序也是需要注意的,应该将严格的索引放在前面,这样筛选的力度会更大,效率更高。


组合索引(最左前缀)

  平时用的SQL查询语句一般都有比较多的限制条件,因此为了进一步提高MySQL的效率,就要考虑建立组合索引。例如上图中针对“last_name”和“first_name”建立一个组合索引:

INDEX name (last_name,first_name)

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

(last_name,first_name)
(last_name)

  之所以没有(first_name)这样的组合索引,是因为MySQL组合索引采取“最左前缀”的结果。简单的理解就是只从最左面的开始组合,组合索引的最左列一定选择好,否则无法起到索引的效果。如果查询时最左列不在查询条件中则该组合索引不会被使用。
  最左列一定是使用最频繁的列,然而并不是只要包含在组合索引中的列的查询都会用到该组合索引,例如以下形式的查询语句能够使用组合索引:

SELECT * FROM tbl_name WHERE last_name='Widenius';  
  
SELECT * FROM tbl_name WHERE last_name='Widenius' AND first_name='Michael';  
  
SELECT * FROM tbl_name WHERE last_name='Widenius' AND (first_name='Michael' OR first_name='Monty');  
  

  以下形式的查询语句不能使用组合索引:

SELECT * FROM tbl_name WHERE first_name='Michael';  
  
SELECT * FROM tbl_name WHERE last_name='Widenius' OR first_name='Michael';  

查看索引

SHOW INDEX FROM tbl_name;
SHOW KEYS FROM tbl_name;

删除索引

DORP INDEX index_name ON tbl_name;
ALTER TABLE tbl_name DROP INDEX index_name;


3、索引的缺点

  虽然索引极大提高了数据查询的速度,但同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELET时,MySQL不仅要保存数据,还要保存一下索引文件,这样就会降低数据的维护速度。
  建立索引会占用磁盘空间,一般而言这个问题不太严重,但如果在一个拥有大量数据的表上创建了多种组合索引,索引文件的会膨胀很快。
  索引只是提高效率的一个因素,如果有大数据量的表,就需要花费时间研究建立最优秀的索引组合,或优化查询语句,且随着数据量的增加,维护索引的成本也会增加。


4、使用索引的注意事项

如何选择聚簇索引或非聚簇索引

动作描述 使用聚簇索引 使用非聚簇索引
列经常被分组排序 使用 使用
返回某范围内的数据 使用 不使用
一个或极少不同值 不使用 不使用
少量的不同值 使用 不使用
大量的不同值 不使用 使用
频繁更新的列 不使用 使用
外键列 使用 使用
主键列 使用 使用
频繁修改索引列 不使用 使用

使用前缀长度

  对于CHAR和VARCHAR列,只用一列的一部分就可创建索引。创建索引时,使用col_name(length)语法,对前缀编制索引。前缀包括每列值的前length个字符。BLOB和TEXT列也可以编制索引,但是必须给出前缀长度。
  例如,有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引,而是CREATE INDEX index_name ON tbl_name(col_name(10))。
  使用短索引不仅可以提高查询速度,而且可以节省磁盘空间和I/O操作。

LIKE语句

  若LIKE语句是不以通配符开头的常量串,MySQL会使用索引。比如:

SELECT * FROM tbl_name WHERE key_col LIKE 'Patrick%'
或
SELECT * FROM tbl_name WHERE key_col LIKE 'Pat%_ck%'

  而以下情况无法使用索引:

//LIKE语句以通配符开头
SELECT * FROM tbl_name WHERE key_col LIKE '%Patrick%'
//LIKE语句不是常量串
SELECT * FROM tbl_name WHERE key_col LIKE other_col

WHERE子句

  1. 在WHERE子句的查询条件中进行运算会导致索引失效;
  2. 在WHERE子句的查询条件中使用了函数会导致索引失效;
  3. 在WHERE子句的查询条件中使用“or”来连接条件会导致索引失效;
  4. 在WHERE子句的查询条件中使用“!=”或“<>”操作符会导致索引失效。

多表连接

  如果数据表需要很多连接查询,首先应该确认两张数据表中连接的字段已经创建索引。这样,MySQL内部会启动优化连接的SQL语句的机制。
  除此之外,这些被用来连接的字段,应该是属于同一类型。例如,如果要把DECIMAL类型的字段和一个INT类型的字段连接在一起,MySQL就无法使用它们的索引。另外对于STRING类型,还需要有相同的字符集才行(两张数据表的字符集有可能不一样)。

避免使用“SELECT * ”

  从数据库里读出的数据越多,那么查询就会变得越慢。而且如果数据库服务器和WEB服务器是两台独立的服务器的话,还会增加网络传输的负担。因此,应该养成需要什么就查找什么的好习惯:

//不推荐使用
SELECT * FROM tbl_name WHERE id = 1;
//推荐使用
SELECT username FROM tbl_name WHERE id = 1;

为每张数据表设置一个ID字段

  应该为数据库里的每张表都设置一个ID做为其主键,且最好为INT类型的(推荐使用UNSIGNED),并设置上AUTO_INCREMENT。
  使用例如VARCHAR类型来当主键会使MySQL性能下降。而且,还有一些操作,例如集群、分区等需要使用主键,在这些情况下,主键的性能和设置变得非常重要。

尽可能的使用“NOT NULL”

  要尽可能地把字段定义为“NOT NULL”。即使该数据表无须保存“NULL”(没有值),也有许多表包含了可空列(Nullable Column),这仅仅因为它是默认选项。除非真的要保存“NULL”,否则就把字段定义为“NOT NULL”。
  MySQL难以优化引用了可空列的查询,它会使索引、索引统计和值更加复杂。可空列需要更多的储存空间,还需要在MySQL内部进行特殊处理。当可空列被索引的时候,每条记录都需要一个额外的字节,还可能导致MyISAM中固定大小的索引(例如一个整数字段上的索引)变成可变大小的索引。
  即使要在表中储存“没有值”的字段,还是有可能不使用“NULL”的。考虑使用0、特殊值或空字符串来代替它。


5、索引的SQL语句汇总

  • 普通索引
    直接创建索引
    CREATE INDEX index_name ON tbl_name(col_name(length));
    修改数据表结构时添加索引
    ALTER TABLE tbl_name ADD INDEX index_name (col_name(length));
    创建数据表时同时创建索引
    CREATE TABLE tbl_name (
    ……
    INDEX index_name (col_name(length))
    )

  • 唯一索引
    直接创建索引
    CREATE UNIQUE INDEX index_name ON tbl_name(col_name(length));
    修改数据表结构时添加索引
    ALTER TABLE tbl_name ADD UNIQUE index_name (col_name(length));
    创建数据表时同时创建索引
    CREATE TABLE tbl_name (
    ……
    UNIQUE index_name (col_name(length))
    )

  • 全文索引
    直接创建索引
    CREATE FULLTEXT INDEX index_name ON tbl_name(col_name(length));
    修改数据表结构时添加索引
    ALTER TABLE tbl_name ADD FULLTEXT index_name (col_name(length));
    创建数据表时同时创建索引
    CREATE TABLE tbl_name (
    ……
    FULLTEXT index_name (col_name(length))
    )

  • 查看索引
    SHOW INDEX FROM tbl_name;
    SHOW KEYS FROM tbl_name;

  • 删除索引
    DORP INDEX index_name ON tbl_name;
    ALTER TABLE tbl_name DROP INDEX index_name;


版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作!             ↓↓↓

你可能感兴趣的:((十二)MySQL中的索引)