zoukankan      html  css  js  c++  java
  • 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没有使用

  • 相关阅读:
    Azure HPC Pack Cluster添加辅助节点
    Azure HPC Pack 辅助节点模板配置
    Azure HPC Pack配置管理系列(PART6)
    Windows HPC Pack 2012 R2配置
    Azure HPC Pack 节点提升成域控制器
    Azure HPC Pack VM 节点创建和配置
    Azure HPC Pack 部署必要条件准备
    Azure HPC Pack 基础拓扑概述
    Azure VM 性能计数器配置
    Maven私仓配置
  • 原文地址:https://www.cnblogs.com/-beyond/p/9574636.html
Copyright © 2011-2022 走看看