zoukankan      html  css  js  c++  java
  • 面试题: MySQL 索引失效的10大原因

    个人博客网:https://wushaopei.github.io/    (你想要这里多有)

    1、建表:

    CREATE TABLE staffs (
      id INT PRIMARY KEY AUTO_INCREMENT,
      NAME VARCHAR (24) NOT NULL DEFAULT '' COMMENT '姓名',
      age INT NOT NULL DEFAULT 0 COMMENT '年龄',
      pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '职位',
      add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间') CHARSET utf8 COMMENT '员工记录表' ;  
    )

    2、插入数据

    INSERT INTO staffs(NAME,age,pos,add_time) VALUES('z3',22,'manager',NOW());
    INSERT INTO staffs(NAME,age,pos,add_time) VALUES('July',23,'dev',NOW());  

    3、创建索引

    ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(NAME, age, pos);  

    基本表信息:

    mysql> desc staffs;
    +----------+-------------+------+-----+-------------------+-------------------+
    | Field    | Type        | Null | Key | Default           | Extra             |
    +----------+-------------+------+-----+-------------------+-------------------+
    | id       | int(11)     | NO   | PRI | NULL              | auto_increment    |
    | NAME     | varchar(24) | NO   | MUL |                   |                   |
    | age      | int(11)     | NO   |     | 0                 |                   |
    | pos      | varchar(20) | NO   |     |                   |                   |
    | add_time | timestamp   | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
    +----------+-------------+------+-----+-------------------+-------------------+
    5 rows in set
    mysql> select * from staffs;
    +----+------+-----+---------+---------------------+
    | id | NAME | age | pos     | add_time            |
    +----+------+-----+---------+---------------------+
    |  1 | z3   |  22 | manager | 2020-01-22 21:46:31 |
    |  2 | July |  23 | dev     | 2020-01-22 21:46:31 |
    |  3 | h4   |  22 | manager | 2020-01-22 21:57:38 |
    |  4 | Juue |  43 | dev     | 2020-01-22 21:57:38 |
    |  ................. |
    +----+------+-----+---------+---------------------+
    198 rows in set
    
    show index from staffs;
    +--------+------------+-----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
    | Table  | Non_unique | Key_name              | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
    +--------+------------+-----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
    | staffs |          0 | PRIMARY               |            1 | id          | A         |           2 | NULL     | NULL   |      | BTREE      |         |               | YES     | NULL       |
    | staffs |          1 | idx_staffs_nameAgePos |            1 | NAME        | A         |           2 | NULL     | NULL   |      | BTREE      |         |               | YES     | NULL       |
    | staffs |          1 | idx_staffs_nameAgePos |            2 | age         | A         |           2 | NULL     | NULL   |      | BTREE      |         |               | YES     | NULL       |
    | staffs |          1 | idx_staffs_nameAgePos |            3 | pos         | A         |           2 | NULL     | NULL   |      | BTREE      |         |               | YES     | NULL       |
    +--------+------------+-----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
    4 rows in set
    

    1、全值匹配我最爱

    2、最佳左前缀法则

    • 如果索引了多列,要遵守此规则,指的是从索引最左前列开始并且不跳过索引中的列
    • 带头大哥不能死,中间兄弟不能断
    mysql>  explain select * from staffs where age=28 and pos='managerment';
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  198 |        1 | Using where |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set , 1 warning (0.001 sec) 

    3、不在索引列上做任何操作

    • 计算、函数、(自动或手动)类型转换,会导致索引失效而转向全表扫描
    mysql> explain select * from staffs where name= 'hu';
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys         | key                   | key_len | ref   | rows | filtered | Extra |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | staffs | NULL       | ref  | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 74      | const |    1 |      100 | NULL  |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-------+
    1 row in set , 1 warning (0.00 sec)
    mysql> explain select * from st
    affs where left(name,4)= 'hu';
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  198 |      100 | Using where |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set , 1 warning (0.00 sec)

    4、存储引擎不能使用索引中范围条件右边的列

    • 范围之后全失效
    mysql>  explain select * from staffs where name
    ='hu' and age=28;
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys         | key                   | key_len | ref         | rows | filtered | Extra |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------+------+----------+-------+
    |  1 | SIMPLE      | staffs | NULL       | ref  | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 78      | const,const |    1 |      100 | NULL  |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------+------+----------+-------+
    1 row in set
    
    mysql>  explain select * from staffs where name='hu' and
     age=28 and pos='managerment';
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys         | key                   | key_len | ref               | rows | filtered | Extra |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------+
    |  1 | SIMPLE      | staffs | NULL       | ref  | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 140     | const,const,const |    1 |      100 | NULL  |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------+
    1 row in set

    5、尽量使用覆盖索引(只访问索引的查询(索引列和查询列一直)),减少select *

    mysql>  explain select * from staffs where name='hu' and
     age=28 and pos='managerment';
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys         | key                   | key_len | ref               | rows | filtered | Extra |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------+
    |  1 | SIMPLE      | staffs | NULL       | ref  | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 140     | const,const,const |    1 |      100 | NULL  |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------+
    1 row in set
    mysql>  explain select name,age,pos
     from staffs where name='hu' and age=28 and pos='managerment';
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys         | key                   | key_len | ref               | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ref  | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 140     | const,const,const |    1 |      100 | Using index |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------------------+------+----------+-------------+
    1 row in set

    6、mysql在使用不等于(!=或<>)时候,无法使用索引导致全表扫描

    mysql>  explain select * from staffs where name='hu' 
    ;
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys         | key                   | key_len | ref   | rows | filtered | Extra |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | staffs | NULL       | ref  | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 74      | const |    1 |      100 | NULL  |
    +----+-------------+--------+------------+------+-----------------------+-----------------------+---------+-------+------+----------+-------+
    1 row in set
    mysql>  explain select * from staffs where name!='hu' ;
    +----+-------------+--------+------------+------+-----------------------+------+---------+------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys         | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+-----------------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | idx_staffs_nameAgePos | NULL | NULL    | NULL |  198 |    99.49 | Using where |
    +----+-------------+--------+------------+------+-----------------------+------+---------+------+------+----------+-------------+
    1 row in set
    
    mysql>  explain select * from staffs where name<>'hu' ;
    +----+-------------+--------+------------+------+-----------------------+------+---------+------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys         | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+-----------------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | idx_staffs_nameAgePos | NULL | NULL    | NULL |  198 |    99.49 | Using where |
    +----+-------------+--------+------------+------+-----------------------+------+---------+------+------+----------+-------------+
    1 row in set
    

    从 type 列可知,使用了全表扫描,此时没有使用索引。

    7、is null,is not null也无法使用索引

    mysql>  explain select * from staffs where name is null ;
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra            |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
    |  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | NULL     | Impossible WHERE |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
    1 row in set
    

    由于该列默认不为null,所以默认在使用 is null 时type 为null

    mysql>  explain select * from staffs where name is not null ;
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  198 |      100 | NULL  |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
    1 row in set

    当使用 not null 时,会进行全文扫描,查找不是null 的项,此时索引失效。

    8、like以通配符开头,mysql索引失效会编程全表扫描的操作

    • 百分like加右边
    mysql>  explain select * from staffs where name like '%hu%' ;
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  198 |    11.11 | Using where |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set
    mysql>  explain select * from staffs where name like '%hu' ;
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | staffs | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  198 |    11.11 | Using where |
    +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
    1 row in set
    
    mysql>  explain select * from staffs where name like 'hu%' ;
    +----+-------------+--------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
    | id | select_type | table  | partitions | type  | possible_keys         | key                   | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+--------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | staffs | NULL       | range | idx_staffs_nameAgePos | idx_staffs_nameAgePos | 74      | NULL |    1 |      100 | Using index condition |
    +----+-------------+--------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+
    1 row in set
    

    9、字符串不加单引号,索引失效

    • 避免隐式类型转换

    10、少用or,用它连接时索引会失效

  • 相关阅读:
    零基础入门学习python--第一章
    mount: no medium found on /dev/sr0 找不到介质
    linux中shell变量$#,$@,$0,$1,$2的含义解释
    ospf多区域实例配置
    Linux查看cpu信息
    ethtool查看网卡以及修改网卡配置
    circusctl命令在ubuntu 上执行,卡住的现象处理。
    ubuntu 16.04.1 LTS zabbix-agent安装
    ubuntu 16.04.1 LTS 初始化
    Ubuntu开机启动的方式
  • 原文地址:https://www.cnblogs.com/wushaopei/p/12283647.html
Copyright © 2011-2022 走看看