索引的存储分类

MySQL 中索引的存储类型目前只有两种(BTREE 和 HASH),具体和表的存储引擎相关: MyISAM 和 InnoDB 存储引擎都只支持 BTREE 索引;MEMORY/HEAP 存储引擎可以支持 HASH 和 BTREE 索引。

MySQL 索引的使用

我们可以利用explain关键字来分析SQL语句的性能

1. 使用索引和不使用索引的区别

没有加索引的情况(主要关注type和rows两个字段,type是表面连接使用了哪种类别,有无使用索引 , row是执行查询时必须检查的行数 )
MySQL的索引优化

加索引的情况 使用了ind_email索引后的情况
MySQL的索引优化

2. 使用索引

对于创建了多列索引, 只要查询的条件中使用了最左边的列,索引就会被使用 。

首先按 name,class_id的顺序创建一个复合索引, 具体如下:

mysql> create index ind_name_classid on emp(`name`, `class_id`);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

按照name来查询,可以发现即便 where 条件中不是用的nameclass_id的组合条件,索引仍然能用到,这就是索引的前缀特性。

mysql> explain select * from emp where name='fan'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ref
possible_keys: ind_name_classid
          key: ind_name_classid
      key_len: 195
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

但是如果只按 class_id条件查询表,那么索引就不会被用到。

mysql> explain select * from emp where class_id = 100\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 10.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)
(2) 对于like的查询,只有号不在第一个字符 , 才会使用索引
mysql> explain select * from emp where email like 'fa%'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: range
possible_keys: ind_email
          key: ind_email
      key_len: 99
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from emp where email like '%[email protected]'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 11.11
        Extra: Using where
1 row in set, 1 warning (0.00 sec)
(3) 如果对大的文本进行搜索,使用全文索引而不用使用 like ‘%…%’。
(4) 如果列名是索引,使用 column_name is null 将使用索引。
mysql> explain select * from emp where name is null\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ref
possible_keys: ind_name_classid
          key: ind_name_classid
      key_len: 195
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
3. 存在索引但不使用索引的情况

(1) 如果 MySQL 估计使用索引比全表扫描更慢,则不使用索引

(2) 用 or 分割开的条件, 如果 or 前的条件中的列有索引, 而后面的列中没有索引, 那么涉及到的索引都不会被用到(name字段有索引, 但是并没有被用到)

mysql> explain select * from emp where name = 'fan' or salary = 1000\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ALL
possible_keys: ind_name_classid
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 19.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

(4) 对于复合索引,只有索引第一列才会被mysql使用(上文name和class_id是复合索引,下文是使用不是第一列的class_id)

mysql> explain select * from emp where class_id = 123 or salary = 1000\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 19.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

(5) 如果列类型是字符串,那么一定记得在 where 条件中把字符常量值用引号引起来

mysql> select * from emp where name = 666;
+-----+------+---------------+---------+----------+
| id  | name | email         | salary  | class_id |
+-----+------+---------------+---------+----------+
| 779 | 666  | [email protected]284.com | 6868052 |      932 |
+-----+------+---------------+---------+----------+
1 row in set, 997 warnings (0.00 sec

# 分析使用数字的情况
mysql> explain select * from emp where name = 666\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ALL
possible_keys: ind_name_classid
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
     filtered: 10.00
        Extra: Using where
1 row in set, 3 warnings (0.00 sec)

# 使用字符串的情况
mysql> explain select * from emp where name = '666'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ref
possible_keys: ind_name_classid
          key: ind_name_classid
      key_len: 195
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

相关文章: