概述

  索引是数据库优化中最常用的也是最重要的手段之一。该篇看看索引的分类,使用场景,不能使用的场景等。

索引分类

  索引是在mysql存储引擎中实现的,而不是在服务器层实现的。索引每种存储引擎的索引不一定相同。mysql支持4种索引:

  • B-tree索引:最常见索引,大部分引擎都支持B树索引。
  • full-text索引:全文索引。
  • hash索引:只有memory引擎支持。
  • R-Tree索引:空间索引是myisam的一种特殊索引,使用比较少。

衍生索引:主键,唯一索引,组合索引,前缀索引等。hash索引适合key-value查询(等值查询),不适合范围查询。

索引

MYISAM引擎

InnoDB引擎

Memory引擎

B-tree索引

支持

支持

支持

full-text索引

支持

-

-

hash索引

-

-

支持

R-tree索引

支持

-

-

使用索引的典型场景

1.匹配全值(match the full value)

对索引中所有列都指定具体值,即对索引中的所有列都有等值匹配的条件。

#设置组合索引(rental_date,inventory_id,customer_id)为唯一索引。
EXPLAIN SELECT * FROM rental 
WHERE rental_date='2005-05-25 17:22:10' 
  AND inventory_id=373 
  AND customer_id=343;

ck索引类型 merck索引_ck索引类型

2.匹配值的范围查询(match a range of values)

对索引值进行范围查找。

#设置索引idx_fk_customer_id(customer_id)
EXPLAIN SELECT * FROM rental WHERE customer_id >= 373 AND customer_id < 400;

ck索引类型 merck索引_索引优化_02

3.匹配最左前缀(match a leftmost prefix)

仅仅使用索引中的最左边列进行查询。比如组合索引(col1,col2,col3)能够被col1,col1+col2,col1+col2+col3的等值查询利用到的。

#创建索引idx_payment_date(payment_date,amount,last_update);

EXPLAIN SELECT * FROM payment WHERE payment_date='2006-02-14 15:16:03' AND last_update = '2006-02-15 22:12:32';

ck索引类型 merck索引_索引优化_03


从结果可以看出利用了索引,但又row为182行,所有只使用了部分索引。

EXPLAIN SELECT * FROM payment WHERE amount=3.98 AND last_update='2006-02-15';

ck索引类型 merck索引_mysql_04


从结果看出,这次查询没有利用索引,进行了全表查找。

4.仅对索引查询进行查询(index only query)

当查询列都在索引字段中。即select中的列都在索引中。

EXPLAIN SELECT last_update FROM payment WHERE payment_date='2005-08-19 21:21:47' AND amount=4.99;

ck索引类型 merck索引_索引优化_05


extra部分Using index,说明不需要通过索引回表,Using index就是平时说的覆盖索引扫描(即找到索引,就找到了要查询的结果,不用再回表查找了)。

5.匹配列前缀(match a column prefix)

仅仅使用索引的第一列,并且只包含索引第1列的开头部分进行查找。

#创建索引idx_title_desc_part(title(10),description(20));

EXPLAIN SELECT title FROM film_text WHERE title LIKE 'AFRICAN%';

ck索引类型 merck索引_存储引擎_06

6.索引部分等值匹配,部分范围匹配
EXPLAIN SELECT inventory_id FROM rental WHERE rental_date='2006-02-14 15:16:03' AND customer_id >= 300 AND customer_id <=400;

ck索引类型 merck索引_索引优化_07


type=ref,说明使用了索引。

7.列名是索引,column_name is null,使用索引
EXPLAIN SELECT * FROM payment WHERE rental_id IS NULL;

ck索引类型 merck索引_ck索引类型_08

索引存在但不能使用索引的典型场景

1.以%开头的like查询
EXPLAIN SELECT * FROM actor WHERE last_name LIKE '%NI%';

ck索引类型 merck索引_mysql_09

#优化
EXPLAIN SELECT * FROM (SELECT actor_id FROM actor WHERE last_name LIKE '%NI%')a,actor b WHERE a.actor_id=b.actor_id;

ck索引类型 merck索引_存储引擎_10

2.数据类型出现隐式转化,不会使用索引
EXPLAIN SELECT * FROM actor WHERE last_name=1;

ck索引类型 merck索引_ck索引类型_11

#使用索引
EXPLAIN SELECT * FROM actor WHERE last_name='1';

ck索引类型 merck索引_存储引擎_12

3.组合索引,不满足最左原则,不使用符合索引
EXPLAIN SELECT * FROM payment WHERE amount=3.98 AND last_update='2006-02-15 22:12:32';

ck索引类型 merck索引_存储引擎_13

4.估计使用索引比全表扫描还慢,则不要使用索引

如查询以“S”开头的标题的电影,返回记录比例比较大,mysql预估索引扫描还不如全表扫描。

EXPLAIN SELECT * FROM film_text WHERE title LIKE 'S%';

ck索引类型 merck索引_索引_14

5.用or分割条件,若or前后只要有一个列没有索引,就都不会用索引
EXPLAIN SELECT * FROM payment WHERE customer_id=203 OR amount=3.96;

ck索引类型 merck索引_存储引擎_15