1、概述
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。可以将索引理解为一本书前面的目录,能加快数据的查询速度。
对于没有索引的表,MySQL会遍历全部数据后选择符合条件的记录,因此单表查询可能几十万数据就是瓶颈,而通常大型网站单日就可能会产生几十万甚至几百万的数据,没有索引查询会变的非常缓慢,而有了相应的索引之后,MySQL会直接在索引中查找符合条件的选项,效率会大大提升。
索引分为聚簇索引和非聚簇索引两种:
- 聚簇索引是按照数据存放的物理位置为顺序的,对于数据而言,通常来说物理顺序结构只有一种,因此每张数据表也只能有一个聚簇索引。在设置主键时,系统会默认为其加上聚簇索引,当然也可以使用其他字段作为索引,此时需要在设置主键之前先手动为待选字段添加上唯一的聚簇索引,然后再设置主键,就可以解决这一问题。
- 非聚簇索引记录的物理顺序与逻辑顺序没有必然的联系,与数据的存储物理位置也没有关系;每张数据表对应的非聚簇索引可以有多个,根据不同列的约束可以建立不同要求的非聚簇索引。
简单总结即,聚簇索引能提高多行检索的效率,而非聚簇索引对于单行的检索更有效。
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子句
- 在WHERE子句的查询条件中进行运算会导致索引失效;
- 在WHERE子句的查询条件中使用了函数会导致索引失效;
- 在WHERE子句的查询条件中使用“or”来连接条件会导致索引失效;
- 在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;
版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作! ↓↓↓