创建索引

1、单列索引

单列索引是最基础的索引,是一种建立在表中特定列上的索引。

1.1语法规则

ALTER TABLE <table> 
			ADD PRIMARY KEY [index-name] (<column>);

ALTER TABLE <table> 
			ADD [UNIQUE] KEY | INDEX [index-name]
			(<column>);

注意:创建非主键索引时,KEY和INDEX关键字可以互换,但创建主键索引时只能使用KEY关键字。

1.2利用索引限制查询读取的行数

如果一个表没有索引,则当进行查询时,会扫描整张表,为了提高查询速度,我们可以通过创建索引来避免每次都扫描整张表。观察表的QEP,如果type属性为NULL,或key=NULL,则可以判断这条查询扫描了整张表。

eg:表结构

SHOW CREATE TABLE user100;

CREATE TABLE `user100` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(10) NOT NULL,
  `last_name` varchar(10) NOT NULL,
  `sex` varchar(5) NOT NULL,
  `score` int(11) NOT NULL,
  `copy_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000002 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

EXPLAIN,观察是否使用索引,type属性或key属性


EXPLAIN SELECT id,first_name,last_name 
FROM user100
WHERE score > 95;

+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | user100 | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 942200 |    33.33 | Using where

直接进行查询,所需要的时间:

SELECT id,first_name,last_name 
FROM user100
WHERE score > 95
> OK
> Time: 0.628s

添加索引,并查看QEP

ALTER TABLE user100 ADD INDEX(score);

EXPLAIN SELECT id,first_name,last_name FROM user100 WHERE score > 95;

1	SIMPLE	user100		range	score	score	4		123056	100.00	Using index condition

注意:MySQL不会限制一个表上的索引的数目,甚至可以创建重复的索引。用户不需要指定索引的名称,MySQL会根据索引所在的首列的名称自动为索引命名,并添加可选的附加信息。

再次进行查询:(每次结果不确定)

SELECT id,first_name,last_name FROM user100 WHERE score > 95
> OK
> Time: 0.199s

1.3使用索引连接表

提高关系表连接操作的性能,通过将连接属性设置为索引,这样表就不会执行全表查询。

1.4索引的基数

当一个表中的索引不止有一条时,MySQL必须在possible_keys列出的索引中选择,优化器会根据工作量最少的估算来选择索引,索引基数就是用来判断如何选择的。

mysql> SHOW INDEX FROM user100;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
| user100 |          0 | PRIMARY  |            1 | id          | A         |      942200 |     NULL |   NULL |      | BTREE      |         |               | YES     |
| user100 |          1 | score    |            1 | score       | A         |          61 |     NULL |   NULL |      | BTREE      |         |               | YES     |
| user100 |          1 | copy_id  |            1 | copy_id     | A         |      942200 |     NULL |   NULL |      | BTREE      |         |               | YES

上表中,可以通过Cardinality属性来看出,索引为PRIMARY ,SCORE,COPY_ID的索引基数分别为922200,61,942200.

索引基数越高,证明该列的唯一值的数量越多,这样可以使用更少的读操作来找到需要的记录,反之,越少,意味着唯一值少,重复的多,则在进行查询时,需要更进一步的属性来进行筛选。

注意,索引基数只是一个参考,真正的抉择在于索引基数值和索引中的总行数的比较,最好的关系是1:1,即每一个值都是一个非空唯一值。

1.5使用索引进行模式匹配

可以通过索引来做模式匹配的工作,注意如果查找的词的开头以通配符开头,则MySQL是不会使用索引。MySQL也不支持基于索引的函数。

1.6唯一索引

唯一索引即列中的值都只出现一次,其次,告诉优化器对给定的记录最多只能有一行结果返回。当使用唯一索引的时候,最多只能返回一行数据,但找到一个匹配结果之后就不需要继续扫描了。

1.7结果排序

索引可以对查询结果进行排序,如果没有使用索引,则MySQL会使用内部文件排序算法对返回的行按照指定顺序进行排序。

2.多列索引

2.1语法规则

ALTER TABLE <table> 
			ADD PRIMARY KEY [index-name]
			(<column>,<column2>...);

ALTER TABLE <table> 
			ADD [UNIQUE] KEY | INDEX [index-name] 
			(<column>,<column2>...);

注意:创建多列索引的时候,尽可能合并索引,这样会获得更高的效率。创建索引是一个非常耗时的工作,并且会阻塞其他操作。

2.2创建索引

ALTER TABLE user100 ADD INDEX U12 (score,first_name);
ALTER TABLE user100 ADD INDEX U21 (first_name,score);

注意,顺序不同的索引其查询时不一样的,交换顺序有可能会创建出更好的索引。

2.3合并WHERE 和 ORDER BY 语句

我们可以创建一个同时满足WHERE 语句和 ORDER BY语句的索引,优化器也可能为WHERE 条件和ORDER BY语句使用一个索引,

注:MySQL可以在WHERE,ORDER BY,GROUP BY列中使用索引,但是,一般来说,MySQL在一个表上只选择一个索引,从MySQL5.0开始,在个别情况下,MySQL使用一个以上的索引,最常见的索引合并就是操作时两个索引取并集,也可以取交集。

3.创建更好的索引

3.1覆盖索引

覆盖索引满足查询中给定表用到的所有的列,创建一个覆盖索引,这个索引必须包含指定列表上包括的WHERE语句,ORDER BY 语句,GROUP BY语句以及SELECT 语句中的所有列。在InnoDB中,主键的值会被附加到非主键索引的每个对应记录后面,因此没有必要在非主键索引中指定主键,即意味着,InnoDB引擎中所有非主键索引都隐含主键列了。

在生茶环境中,覆盖索引有可能不是理想的索引。由于数据集大小有限,随着数据列长度的增加,为一个大型列创建索引可能会对系统整体性能有影响,覆盖索引适合那些使用了很多较小长度的主键和外键约束的表。

3.2局部索引

即创建更紧凑的索引,可以减少索引占用的空间,降低更少的磁盘I/O开销,意味着更快的访问到需要访问的行。

 

 

参考《Effective MySQL之SQL语句最优化》     建议亲自阅读本书,加深理解。