• MySQL 通过多个示例学习索引


      最近在准备面试,关于索引这一块,发现很多以前忽略的点,这里好好整理一下

      

    首先为什么要建立索引

      一本书,有章、节、段、行这种单位。

      如果现在需要找一个内容:第9章>第2节>第3段>第4行>第5个字。

      如果没有索引(目录),那么,就必须从第一页开始,按照这个顺序:第1章>第1节>第1段>第1行>第1个字开始,顺序查找,也就是说,如果运气足够坏,那么,找到目标的时候,已经将整本书都差不多扫了一遍。

      但是现在,如果建立了索引(目录),只是建立了 “章” 的索引:每一章的第一页,那么,我们开始查找的时候,并不是从第1章开始,我们可以根据目录,查找到第9章的页数,然后直接翻到第9章的那章内容,初始就是第9章>第1节>第1段>第1行>第1个字,然后仍旧开始顺序查找,那么这个时候,虽然仍然有点慢,但是已经快了很多很多。

      现在,如果建立(章-节)的索引,记录每一章的每一个小节的第1页,那么我们开始查找的时候,可以通过读一下索引,直接找到第9章的第2小节,然后从这1小节的第1段的第1行的第1个字开始查找。仍旧顺序查找。

      很好,你会想,可以建立(章-节-段)的索引,那么,一开始就可以直接定位到第9章>第2小节>第3段,然后从这段的第1行的第1个字开始顺序查找。

      那么,有没有必要建立(章-节-段-行)的索引呢?可以根据情况而定。

    索引类型

      有很多中索引,比如:

      1、普通索引:最基本的索引,没有任何约束限制

      2、唯一索引:与主键索引类似,但是不允许出现相同的值(唯一性约束)。

      3、主键索引:特殊的唯一索引,不允许有空值。

      4、复盖索引(组合索引):将多个列组合在一起创建索引,可以覆盖多个列,比如“章-节-段”建立索引

      5、外键索引:只有Innodb支持,保证数据一致性、完整性,实现级联操作。

      6、全文索引:只有MyISAM引擎支持,并且只支持对英文进行全文检索。

    建立索引

      假设有一个user表(用户表)

    mysql> desc user;
    +-------+----------+------+-----+---------+----------------+
    | Field | Type     | Null | Key | Default | Extra          |
    +-------+----------+------+-----+---------+----------------+
    | uid   | int(11)  | NO   | PRI | NULL    | auto_increment |
    | uname | char(20) | NO   | MUL | NULL    |                |
    | addr  | char(20) | NO   |     | NULL    |                |
    | token | char(20) | NO   |     | NULL    |                |
    +-------+----------+------+-----+---------+----------------+
    5 rows in set (0.05 sec)

      uid因为是主键,所以已经默认创建了主键索引  

      为uname字段建立一个唯一索引,为addr字段建立普通索引;

      token字段不建立索引

    mysql> create unique index uname_index on user(uname);
    mysql> create index addr_index on user(addr);
    

      

    查看索引

    mysql> show index from user;
    *************************** 1. row ***************************
            Table: user
       Non_unique: 0
         Key_name: PRIMARY
     Seq_in_index: 1
      Column_name: uid
        Collation: A
      Cardinality: 0
         Sub_part: NULL
           Packed: NULL
             Null:
       Index_type: BTREE
          Comment:
    Index_comment:
    *************************** 2. row ***************************
            Table: user
       Non_unique: 0
         Key_name: uname_index
     Seq_in_index: 1
      Column_name: uname
        Collation: A
      Cardinality: 0
         Sub_part: NULL
           Packed: NULL
             Null:
       Index_type: BTREE
          Comment:
    Index_comment:
    *************************** 3. row ***************************
            Table: user
       Non_unique: 1
         Key_name: addr_index
     Seq_in_index: 1
      Column_name: addr
        Collation: A
      Cardinality: NULL
         Sub_part: NULL
           Packed: NULL
             Null:
       Index_type: BTREE
          Comment:
    Index_comment:
    

      

    插入数据

      使用pdo循环插入10000条记录,各个字段除了uid自增之外,都是随机值。

    <?php
        $pdo = new PDO("mysql:host=127.0.0.1;dbname=MyDb;charset=utf8", "root", "root");
    
        $stmt = $pdo->prepare("insert into user (uname, addr, token) values (?, ?, ?)");
    
        $str = "abcdefghijklmnopqrstuvwxzy";
    
        for ($j = 0; $j < 10000; $j++) {
            $name = "";
            $addr = "";
            $token = "";
            for ($i = 0; $i < 7; $i++) {
                $name .= $str[mt_rand(0, 25)];
                $addr .= $str[mt_rand(0, 25)];
                $token .= $str[mt_rand(0, 25)];
            }
            $stmt->execute(array($name, $addr, $token));
        }
    
    ?>
    

      

    是否会使用索引?

      示例1:

    mysql> explain select count(*) from user;
    +----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                        |
    +----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
    |  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Select tables optimized away |
    +----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
    1 row in set (0.00 sec)
    

      未使用索引,因为没有使用where子句,索引是在查找的时候(有where的时候才使用索引)。

      示例2:

    mysql> explain select * from user where uname='outalwa';
    +----+-------------+-------+-------+---------------+-------------+---------+-------+------+-------+
    | id | select_type | table | type  | possible_keys | key         | key_len | ref   | rows | Extra |
    +----+-------------+-------+-------+---------------+-------------+---------+-------+------+-------+
    |  1 | SIMPLE      | user  | const | uname_index   | uname_index | 60      | const |    1 |       |
    +----+-------------+-------+-------+---------------+-------------+---------+-------+------+-------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname!='outalwa';
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | uname_index   | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname<>'outalwa';
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | uname_index   | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    1 row in set (0.00 sec)

      对于一个建了索引的列来说,如果使用=、!=、<>来判断字段值是否与一个值相等的时候,只有使用=的时候会使用索引,而!=和<>不会使用索引。

      示例3:

    mysql> explain select * from user where uid='9999' and uname='muqehaq';                              
    +----+-------------+-------+-------+---------------------+---------+---------+-------+------+-------+
    | id | select_type | table | type  | possible_keys       | key     | key_len | ref   | rows | Extra |
    +----+-------------+-------+-------+---------------------+---------+---------+-------+------+-------+
    |  1 | SIMPLE      | user  | const | PRIMARY,uname_index | PRIMARY | 4       | const |    1 |       |
    +----+-------------+-------+-------+---------------------+---------+---------+-------+------+-------+
    1 row in set (0.06 sec)                                                                              
    

      因为uid建立了主键索引,uname建立了唯一索引,使用and表示(并且)的关系时,会使用各自的索引。只扫描了1行数据就找到了

      

      示例4:

    mysql> explain select * from user where uid='9999' or uname='muqehaq';
    +----+-------------+-------+-------------+---------------------+---------------------+---------+------+------+-----------------------------------------------+
    | id | select_type | table | type        | possible_keys       | key                 | key_len | ref  | rows | Extra                                         |
    +----+-------------+-------+-------------+---------------------+---------------------+---------+------+------+-----------------------------------------------+
    |  1 | SIMPLE      | user  | index_merge | PRIMARY,uname_index | PRIMARY,uname_index | 4,60    | NULL |    2 | Using union(PRIMARY,uname_index); Using where |
    +----+-------------+-------+-------------+---------------------+---------------------+---------+------+------+-----------------------------------------------+
    1 row in set (0.00 sec)
    

      因为uid建立了主键索引,uname建立了唯一索引,使用or表示(或)的关系时,使用了索引。

      示例5

    mysql> explain select * from user where uid='9999' and token='dakghzz';
    +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
    +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
    |  1 | SIMPLE      | user  | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
    +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
    

      uid有主键索引,token没有建立索引,使用and来连接条件,可以使用索引。

      如果条件是token='dakghzz' and uid=9999 ,同样会使用索引。

      示例6

    mysql> explain select * from user where uid='9999' or token='dakghzz';
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | PRIMARY       | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    1 row in set (0.00 sec)
    

      uid有主键索引,但是token没有建立索引,使用or来连接的时候,可以看到,查询并没有使用索引。

      示例7

    mysql> explain select count(*) from user where uid < 1000;
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    |  1 | SIMPLE      | user  | range | PRIMARY       | PRIMARY | 4       | NULL | 1401 | Using where; Using index |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select count(*) from user where uid between 10 and 1000;
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    |  1 | SIMPLE      | user  | range | PRIMARY       | PRIMARY | 4       | NULL | 1388 | Using where; Using index |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select count(*) from user where uid >10 and uid < 1000;
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    |  1 | SIMPLE      | user  | range | PRIMARY       | PRIMARY | 4       | NULL | 1386 | Using where; Using index |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
    1 row in set (0.00 sec)
    

      如果存储引擎是innodb的话,对于主键索引列,使用 大于、小于、大于等于、小于等于、between and 作为筛选条件,都会使用索引。

      如果存储引擎是MyISAM的话,即使是索引列,使用是大于、小于、大于等于、小于等于、between and作为筛选条件,都不会使用索引。

      无论是哪种存储引擎,即使某一列创建了索引,如果使用大于、小于、大于等于、小于等于、between and作为筛选条件,都不会使用索引。

      示例8

    mysql> explain select * from user where uname=null;
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
    |  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname!=null;
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
    |  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname is null;
    +----+-------------+-------+------+---------------+------+---------+------+------+------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra            |
    +----+-------------+-------+------+---------------+------+---------+------+------+------------------+
    |  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE |
    +----+-------------+-------+------+---------------+------+---------+------+------+------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname is not null;
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | uname_index   | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    1 row in set (0.00 sec)
    

        对于一个建立了索引的列来说,判断字段是否为0时,使用=,!=,is null,is not null这几种方式都不会使用索引。

      示例9

    mysql> explain select * from user where uname like '%wolwgrc';
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname like '%wolwgrc%';
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    
    mysql> explain select * from user where uname like 'wolwgrc';
    +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
    |  1 | SIMPLE      | user  | range | uname_index   | uname_index | 60      | NULL |    1 | Using where |
    +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where uname like 'wolwgrc%';
    +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
    |  1 | SIMPLE      | user  | range | uname_index   | uname_index | 60      | NULL |    1 | Using where |
    +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
    1 row in set (0.00 sec)
    

      对一个已经建立了索引的列使用模式匹配的时候,%keyword、%keyword%不会使用索引,而keyword和keyword%会使用索引。

    普通索引的注意事项

      1、 对于一个没有where的查询,不会使用索引,所以,在创建索引的时候,应该以where子句的字段为准,而不是select后面的字段为准。

      2、对于一个建了索引的列来说,如果使用=、!=、<>来判断字段值是否与一个值相等的时候,只有使用=的时候会使用索引,而!=和<>不会使用索引。

      3、where包含多个字段,如果每个字段都建了索引,那么使用and和or连接的时候,查询会使用索引。

      4、where包含多个字段,如果一部分字段建立了索引,而有一部分字段没有建立索引,那么使用and连接的时候,查询的时候,建立了索引的字段会使用索引,而没有建立索引的字段不会使用索引。

      5、where包含多个字段,如果一部分字段建立了索引,而有一部分字段没有建立索引,那么使用or连接的时候,查询的时候,不会使用索引。

      6、如果存储引擎是innodb的话,对于主键索引列,使用 大于、小于、大于等于、小于等于、between and 作为筛选条件,都会使用索引。

      7、如果存储引擎是MyISAM的话,即使是索引列,使用 大于、小于、大于等于、小于等于、between and作为筛选条件,都不会使用索引。

      8、无论是哪种存储引擎,即使某一列创建了索引,如果使用大于、小于、大于等于、小于等于、between and作为筛选条件,都不会使用索引。

      9、对于一个建立了索引的列来说,判断字段是否为0时,使用=,!=,is null,is not nulll这几种方式都不会使用索引。

      10、对一个已经建立了索引的列使用模式匹配的时候,%keyword、%keyword%不会使用索引,而keyword和keyword%会使用索引。

    复合索引

      复合索引有前缀原则,后面示例会解释。

      删除之前为uname字段和addr字段创建的索引。

      创建一个复合索引,包含uname、addr、token,命令如下:

    mysql> drop index uname_index on user;                                                                                                                               
    Query OK, 10000 rows affected (0.27 sec)                                                                                                                             
    Records: 10000  Duplicates: 0  Warnings: 0                                                                                                                           
                                                                                                                                                                         
    mysql> drop index addr_index on user;                                                                                                                                
    Query OK, 10000 rows affected (0.24 sec)                                                                                                                             
    Records: 10000  Duplicates: 0  Warnings: 0                                                                                                                           
                                                                                                                                                                         
    mysql> create index three_fields_index on user(uname, addr, token);                                                                                                  
    Query OK, 10000 rows affected (0.25 sec)                                                                                                                             
    Records: 10000  Duplicates: 0  Warnings: 0                                                                                                                           
                                                                                                                                                                         
    mysql> show index from user;                                                                                                                                         
    +-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
    | Table | Non_unique | Key_name           | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
    +-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
    | user  |          0 | PRIMARY            |            1 | uid         | A         |       10000 |     NULL | NULL   |      | BTREE      |         |               | 
    | user  |          1 | three_fields_index |            1 | uname       | A         |       10000 |     NULL | NULL   |      | BTREE      |         |               | 
    | user  |          1 | three_fields_index |            2 | addr        | A         |       10000 |     NULL | NULL   |      | BTREE      |         |               | 
    | user  |          1 | three_fields_index |            3 | token       | A         |       10000 |     NULL | NULL   |      | BTREE      |         |               | 
    +-------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
    

      可以从上面索引查询结果中看出,uname、addr、token都包含在一个索引中(Key_name相同)。

    覆盖索引的使用示例

      下面的实例,简化一下,创建的索引是key(uname, addr, token),那么对应key(A, B, C)

      示例1

    mysql> explain select * from user where uname='muqehaq' and addr='hgommlp' and token='dakghzz';
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------------+------+-------------+
    | id | select_type | table | type | possible_keys      | key                | key_len | ref               | rows | Extra       |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------------+------+-------------+
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 180     | const,const,const |    1 | Using where |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where addr='hgommlp' and token='dakghzz' and uname='muqehaq';
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------------+------+-------------+
    | id | select_type | table | type | possible_keys      | key                | key_len | ref               | rows | Extra       |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------------+------+-------------+
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 180     | const,const,const |    1 | Using where |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------------+------+-------------+
    1 row in set (0.00 sec)

      因为建立了uname-addr-token的联合索引,在where中,三个字段都出现了(和建立索引时使用的字段列相同时),此时,和每个字段的顺序无关,都会使用索引。

      结论:where A='xx' and B='xx' and 或者where C='xx'  and B='xx' and A='xx'会使用索引。

      示例2

    mysql> explain select * from user where uname='muqehaq' and addr='hgommlp';
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------+------+-------------+
    | id | select_type | table | type | possible_keys      | key                | key_len | ref         | rows | Extra       |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------+------+-------------+
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 120     | const,const |    1 | Using where |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where addr='hgommlp' and uname='muqehaq' ;
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------+------+-------------+
    | id | select_type | table | type | possible_keys      | key                | key_len | ref         | rows | Extra       |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------+------+-------------+
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 120     | const,const |    1 | Using where |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------------+------+-------------+
    1 row in set (0.00 sec)

      示例:where A='xx' and B='xx' 或者 where B='xx' and A='xx'

      结论:会使用索引,使用复合索引中的前两个字段的索引。

      示例3:

    mysql> explain select * from user where uname='muqehaq' and token='dakghzz';
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+
    | id | select_type | table | type | possible_keys      | key                | key_len | ref   | rows | Extra       |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 60      | const |    1 | Using where |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from user where token='dakghzz' and uname='muqehaq';
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+
    | id | select_type | table | type | possible_keys      | key                | key_len | ref   | rows | Extra       |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 60      | const |    1 | Using where |
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+
    1 row in set (0.00 sec)

      示例:where A='xxx' and C='xx'   或者 where C='xx' and A='xxx'

      结论:查询A字段的时候,会使用复合索引中的A那一部分,但是查询C字段的时候,并不会使用复合索引。

      原因:因为没有使用复合索引中的B字段。

      示例4

    mysql> explain select * from user where addr='hgommlp' and token='dakghzz';
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    |  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
    1 row in set (0.00 sec)
    

      示例:where B='xxx' and C='xxx' 

      结论:不会使用索引。

      原因:没有使用复合索引中B前面的A字段索引。

      示例5

    mysql> explain select * from user where uname='muqehaq';                                                              
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+  
    | id | select_type | table | type | possible_keys      | key                | key_len | ref   | rows | Extra       |  
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+  
    |  1 | SIMPLE      | user  | ref  | three_fields_index | three_fields_index | 60      | const |    1 | Using where |  
    +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-------------+  
    1 row in set (0.00 sec)                                                                                               
                                                                                                     
    mysql> explain select * from user where addr='hgommlp';                                                               
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+                     
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |                     
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+                     
    |  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000 | Using where |                     
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+                     
    1 row in set (0.00 sec)                                                                                               
                                                                                                                          
    mysql> explain select * from user where token='dakghzz';                                                              
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+                     
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra       |                     
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+                     
    |  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000 | Using where |                     
    +----+-------------+-------+------+---------------+------+---------+------+-------+-------------+                     
    

      示例:where A='xxx'    结论:会使用索引。

      示例:where B='xxx'    结论:不会使用索引。

      示例:where C='xxx'    结论:不会使用索引。

    复合索引的使用总结

      假设创建了key(a,b,c)复合索引,那么:

      where a = 1 and b = 2  and  c = 3;       会使用索引

      where a = 1 and c = 3 and b = 2;   会使用索引

      where a = 1 and b = 2 ;      会使用索引

      where b = 2 and a = 1;      注意,这也是会使用复合索引的ab

      where a = 1;会使用索引

      where a = 1 and c = 3;   不会使用索引,因为c前面的b没有使用

      where b = 2 and c = 3;   不会使用索引,因为b前面的a没有使用

  • 相关阅读:
    spring boot 扫描不到自定义Controller
    SpringBoot+Maven多模块项目(创建、依赖、打包可执行jar包部署测试)完整流程
    spring boot 中使用 jpa以及jpa介绍
    java8 快速实现List转map 、分组、过滤等操作
    Mysql 创建函数出现This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA
    Spring mvc @initBinder 类型转化器的使用
    @RequestMapping 和@ResponseBody 和 @RequestBody和@PathVariable 注解 注解用法
    ssm的自动类型转换器
    如果将get请求转换成post请求
    如何将post请求转换成put和delete请求
  • 原文地址:https://www.cnblogs.com/-beyond/p/9574636.html
Copyright © 2020-2023  润新知