mysql 索引的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang_referee/article/details/83215770

这里主要内容有如下:

  1. 索引的使用场景
  2. 索引的使用原则

1.索引的使用场景

       在索引基础篇(https://blog.csdn.net/zhang_referee/article/details/83045903)说过,索引能极大加快访问速度,这里说下索引的主要使用场景。

   首先看一下,案例表索引情况:

    

mysql> show index from dye_production_schedules;
+--------------------------+------------+--------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table                    | Non_unique | Key_name                 | Seq_in_index | Column_name         | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------------------+------------+--------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| dye_production_schedules |          0 | PRIMARY                  |            1 | id                  | A         |     1371967 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | order_id_order_detail_id |            1 | order_id            | A         |       19625 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | order_id_order_detail_id |            2 | order_detail_id     | A         |     1521058 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | dye_factory_id           |            1 | dye_factory_id      | A         |       29238 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | dye_code                 |            1 | dye_code            | A         |     1521058 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | order_detail_id          |            1 | order_detail_id     | A         |      192921 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | order_id_batch_num       |            1 | order_id            | A         |       18622 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | order_id_batch_num       |            2 | batch_num           | A         |     1521058 |     NULL | NULL   |      | BTREE      |         |               |
| dye_production_schedules |          1 | customer_color_name      |            1 | customer_color_name | NULL      |     1521058 |     NULL | NULL   |      | FULLTEXT   |         |               |
+--------------------------+------------+--------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

  1.1 索引检索

              

mysql> explain select sql_no_cache id ,dye_factory_id ,order_id ,order_detail_id ,dye_code,product_id,batch_num ,customer_color_name from dye_production_schedules where order_id = 4538 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: dye_production_schedules
   partitions: NULL
         type: ref
possible_keys: order_id_order_detail_id,order_id_batch_num
          key: order_id_order_detail_id
      key_len: 4
          ref: const
         rows: 213
     filtered: 100.00
        Extra: NULL

  通过 explain 分析可得知,数据访问方式使用了 索引访问( type:ref ),explain 可参考:https://blog.csdn.net/zhang_referee/article/details/83041301

       1.2 索引排序

     这里我们假设在order_detail_id 字段上进行排序

              

mysql> explain select sql_no_cache id ,dye_factory_id,order_id ,order_detail_id ,dye_code ,batch_num,customer_color_name from dye_production_schedules order by order_detail_id desc limit 10;
+----+-------------+--------------------------+------------+-------+---------------+-----------------+---------+------+------+----------+-------+
| id | select_type | table                    | partitions | type  | possible_keys | key             | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------------------------+------------+-------+---------------+-----------------+---------+------+------+----------+-------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | index | NULL          | order_detail_id | 4       | NULL |   10 |   100.00 | NULL  |
+----+-------------+--------------------------+------------+-------+---------------+-----------------+---------+------+------+----------+-------+

 之前在索引基础篇(https://blog.csdn.net/zhang_referee/article/details/83045903),举栗子的时候,可以看到,当没有在order_detail_id 这个字段上建立索引同样的查询,explain 会在extra 列上提示:Using filesort ,表示查询使用了文件排序。而同样的sql 加上索引后,能省去这一步骤(说省去也不准确,因为还是做了排序--索引排序,不过却没有显示在extra 列)。

  1.3 索引覆盖

           所谓索引覆盖,指的是索引的内容包含了查询所需全部数据,在explain 中 ,extra 列上提示Using index ,表示使用到了索引覆盖。

   

mysql> explain select order_id,batch_num from  dye_production_schedules ;
+----+-------------+--------------------------+------------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type  | possible_keys | key                | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+-------+---------------+--------------------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | index | NULL          | order_id_batch_num | 198     | NULL | 1521058 |   100.00 | Using index |
+----+-------------+--------------------------+------------+-------+---------------+--------------------+---------+------+---------+----------+-------------+

   

2.索引的使用原则

  2.1 列独立

           

mysql> explain select id,dye_factory_id,order_id ,order_detail_id ,customer_color_name from  dye_production_schedules where order_detail_id = 10000 ;
+----+-------------+--------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table                    | partitions | type | possible_keys   | key             | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ref  | order_detail_id | order_detail_id | 4       | const |   18 |   100.00 | NULL  |
+----+-------------+--------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.08 sec)

mysql> explain select id,dye_factory_id,order_id ,order_detail_id ,customer_color_name from  dye_production_schedules where order_detail_id = 10000 - 1 ;
+----+-------------+--------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table                    | partitions | type | possible_keys   | key             | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ref  | order_detail_id | order_detail_id | 4       | const |   16 |   100.00 | NULL  |
+----+-------------+--------------------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)

mysql> explain select id,dye_factory_id,order_id ,order_detail_id ,customer_color_name from  dye_production_schedules where order_detail_id - 1 = 10000 ;
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1581424 |   100.00 | Using where |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.02 sec)

mysql> 

可以看到第三条查询使用了全表扫描,没有用到索引。在查询中我们应该养成简化where 条件的习惯,始终将索引列单独放在比较符号的一侧。

   2.2 左原则

    Like:匹配模式必须要左边确定不能以通配符开头

     

mysql> explain select id,order_id,dye_code ,customer_color_name from  dye_production_schedules where dye_code like 'b8ff%';
+----+-------------+--------------------------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table                    | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+--------------------------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | range | dye_code      | dye_code | 194     | NULL |   33 |   100.00 | Using index condition |
+----+-------------+--------------------------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select id,order_id,dye_code ,customer_color_name from  dye_production_schedules where dye_code like '%b8ff';
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1581424 |    11.11 | Using where |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select id,order_id,dye_code ,customer_color_name from  dye_production_schedules where dye_code like '%b8ff%';
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1581424 |    11.11 | Using where |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

通过explain 语句,可以看到第二条和第三条查询,由于索引列字段左边不确定,因此没能使用到索引。在项目中,出现双百分号的查询一般使用全文索引来加快数据访问速度!

  2.3 复合索引

    复合索引仅仅针对左边第一个索引有效。

    在这个表中,`order_id_batch_num` (`order_id`,`batch_num`) 是一个复合索引,其中第一个索引是order_id。

    

mysql> explain select * from dye_production_schedules where order_id = 8780;
+----+-------------+--------------------------+------------+------+---------------------------------------------+--------------------------+---------+-------+------+----------+-------+
| id | select_type | table                    | partitions | type | possible_keys                               | key                      | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------------------+------------+------+---------------------------------------------+--------------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ref  | order_id_order_detail_id,order_id_batch_num | order_id_order_detail_id | 4       | const |  205 |   100.00 | NULL  |
+----+-------------+--------------------------+------------+------+---------------------------------------------+--------------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from dye_production_schedules where batch_num like '5c5e9534d%';
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1581424 |    11.11 | Using where |
+----+-------------+--------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from dye_production_schedules where  order_id = 8780 and  batch_num like '5c5e9534d%';
+----+-------------+--------------------------+------------+-------+---------------------------------------------+--------------------+---------+------+------+----------+-----------------------+
| id | select_type | table                    | partitions | type  | possible_keys                               | key                | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+--------------------------+------------+-------+---------------------------------------------+--------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | range | order_id_order_detail_id,order_id_batch_num | order_id_batch_num | 198     | NULL |    1 |   100.00 | Using index condition |
+----+-------------+--------------------------+------------+-------+---------------------------------------------+--------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.06 sec)

通过上面栗子explain 的分析可以看到,检索条件只有batch_num时,索引无效。

         2.4 OR 原则

         在查询中使用到了 or 语句时,必须确保 or 两端都能使用到索引才能使用索引,否则索引无效。

  

mysql> explain select * from dye_production_schedules where  order_id = 8780 or  dye_code like 'b8ff%';
+----+-------------+--------------------------+------------+-------------+------------------------------------------------------+-----------------------------------+---------+------+------+----------+------------------------------------------------------------------+
| id | select_type | table                    | partitions | type        | possible_keys                                        | key                               | key_len | ref  | rows | filtered | Extra                                                            |
+----+-------------+--------------------------+------------+-------------+------------------------------------------------------+-----------------------------------+---------+------+------+----------+------------------------------------------------------------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | index_merge | order_id_order_detail_id,dye_code,order_id_batch_num | order_id_order_detail_id,dye_code | 4,194   | NULL |  238 |   100.00 | Using sort_union(order_id_order_detail_id,dye_code); Using where |
+----+-------------+--------------------------+------------+-------------+------------------------------------------------------+-----------------------------------+---------+------+------+----------+------------------------------------------------------------------+

    在上面的查询中,order_id 和 dye_code 列上均有索引,且索引有效,所以可以使用到索引。

mysql> explain select * from dye_production_schedules where  order_id = 8780 or  dye_code like '%b8ff%';
+----+-------------+--------------------------+------------+------+---------------------------------------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys                               | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+---------------------------------------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | order_id_order_detail_id,order_id_batch_num | NULL | NULL    | NULL | 1581424 |    11.11 | Using where |
+----+-------------+--------------------------+------------+------+---------------------------------------------+------+---------+------+---------+----------+-------------+

在同样的列上,由于dye_code 无法使用到索引(不满足左原则),导致整个查询均无法使用到索引(key 列值为 NULL)。

上面是主要原则,有时候,我们即使建立了索引,满足了上述所有条件。然而查询条件不同,mysql 也会自动选择弃用索引。

 

mysql> explain select * from dye_production_schedules where order_detail_id > 30000;
+----+-------------+--------------------------+------------+------+-----------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys   | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+-----------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | order_detail_id | NULL | NULL    | NULL | 1581424 |    50.00 | Using where |
+----+-------------+--------------------------+------------+------+-----------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from dye_production_schedules where order_detail_id< 30000;
+----+-------------+--------------------------+------------+------+-----------------+------+---------+------+---------+----------+-------------+
| id | select_type | table                    | partitions | type | possible_keys   | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------------------------+------------+------+-----------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | ALL  | order_detail_id | NULL | NULL    | NULL | 1581424 |    50.00 | Using where |
+----+-------------+--------------------------+------------+------+-----------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.04 sec)

mysql> explain select * from dye_production_schedules where order_detail_id< 3000;
+----+-------------+--------------------------+------------+-------+-----------------+-----------------+---------+------+--------+----------+-----------------------+
| id | select_type | table                    | partitions | type  | possible_keys   | key             | key_len | ref  | rows   | filtered | Extra                 |
+----+-------------+--------------------------+------------+-------+-----------------+-----------------+---------+------+--------+----------+-----------------------+
|  1 | SIMPLE      | dye_production_schedules | NULL       | range | order_detail_id | order_detail_id | 4       | NULL | 125092 |   100.00 | Using index condition |
+----+-------------+--------------------------+------------+-------+-----------------+-----------------+---------+------+--------+----------+-----------------------+

可以看到mysql 会根据条件,会智能地启用或弃用可选索引。这让我想起,建立索引时,尽量不要建在标识性很低的列上,例如性别,是否删除(is_delete 两个值0或1)等列上,即便建了索引,mysql 也会弃用索引,采用扫表的方式(顺序IO)访问数据。

猜你喜欢

转载自blog.csdn.net/zhang_referee/article/details/83215770