• 关于索引


    一.测试数据

    MyISAM:

    CREATE TABLE `test` (
      `id` int(10) NOT NULL AUTO_INCREMENT,
      `uid` int(11) NOT NULL,
      `name` char(255) CHARACTER SET gbk NOT NULL,
      `time` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `uid` (`uid`) USING BTREE,
      KEY `name_time` (`name`,`time`)
    ) ENGINE=MyISAM;

      

    INSERT INTO test VALUES ('1', '14', 'test', '1513338971');
    INSERT INTO test VALUES ('2', '15', 'jack', '1513338980');
    INSERT INTO test VALUES ('3', '16', 'home2', '1513338980');
    

      

    InnoDB:

    CREATE TABLE `test2` (
      `id` int(10) NOT NULL AUTO_INCREMENT,
      `uid` int(11) NOT NULL,
      `name` char(255) CHARACTER SET gbk NOT NULL,
      `time` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `uid` (`uid`) USING BTREE,
      KEY `name_time` (`name`,`time`)
    ) ENGINE=InnoDB
    

      

    INSERT INTO test2 VALUES ('1', '14', 'test', '1513338971');
    INSERT INTO test2 VALUES ('2', '15', 'jack', '1513338980');
    INSERT INTO test2 VALUES ('3', '16', 'home2', '1513338980');
    

      

    二.实例分析,只有where的情形下

     1.为什么要有最左前缀限制?

    对于多列索引,最左前缀是必须的.否者mysql无法使用索引,因为符合索引是按第一列,第二列,第三列...一次来排序的.不符合最左前缀原则,mysql将放弃使用索引.

    如:

    mysql> explain select * from test where time=1513338971;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    
    mysql> explain select * from test2 where time=1513338971;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | test2 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    

      

    2.AND

    对于where中的and,只要and两边有一边的字段有索引,就能用到索引.

    mysql> explain select * from test where time=1513338971 and name='jack';
    +----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+
    | id | select_type | table | type | possible_keys | key       | key_len | ref         | rows | Extra       |
    +----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+
    |  1 | SIMPLE      | test  | ref  | name_time     | name_time | 515     | const,const |    1 | Using where |
    +----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from test2 where time=1513338971 and name='jack';
    +----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+
    | id | select_type | table | type | possible_keys | key       | key_len | ref         | rows | Extra       |
    +----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+
    |  1 | SIMPLE      | test2 | ref  | name_time     | name_time | 515     | const,const |    1 | Using where |
    +----+-------------+-------+------+---------------+-----------+---------+-------------+------+-------------+
    1 row in set (0.00 sec)
    

      

    3.OR

    对于OR,只要有一个字段没有索引,就不会用到索引

    mysql> explain select * from test where  name='jack' or time=1513338971;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | test  | ALL  | name_time     | NULL | NULL    | NULL |    3 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from test2 where  name='jack' or time=1513338971;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    |  1 | SIMPLE      | test2 | ALL  | name_time     | NULL | NULL    | NULL |    3 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
    1 row in set (0.00 sec)
    

      

    三.Order(不带where条件)

    (一).单列索引

    1.除非强制走索引或覆盖索引,否者myisam不会用到索引,而进行额外排序(Extra列中出现using filesort)

    mysql> explain select * from test order by id desc;
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    |  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    

    myisam是非聚集索引,优化器认为排序完后还需要具体的去读取数据行,所以干脆放弃了使用索引,也就无法索引扫描排序.除非是覆盖索引,否则优化器都不会用到索引,而进行额外排序.

     

    2.InnoDB则可以用到索引,只扫描索引就可以排序(type列出现index,表明使用了索引排序)

    mysql> explain select * from test2 order by id desc;
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
    | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
    |  1 | SIMPLE      | test2 | index | NULL          | PRIMARY | 4       | NULL |    3 |       |
    +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
    

    因为是聚集索引,索引和数据是在一起的,优化器认为不必再去查找数据.所以会用到主键索引. 

    (二).复合索引 

    1.覆盖索引情况下,只要排序字段中排序方向一致,两者均可用到索引扫描排序.反向不一致,就不会用到索引排序.

    mysql> explain select name,time from test order by name asc,time asc;
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
    |  1 | SIMPLE      | test  | index | NULL          | name_time | 515     | NULL |    3 | Using index |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
    

      

    mysql> explain select name,time from test2 order by name asc,time asc;
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
    |  1 | SIMPLE      | test2 | index | NULL          | name_time | 515     | NULL |    3 | Using index |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------------+
    

      

    2.非覆盖索引情况下,即便方向一致,两者均需要去进行额外排序,而且优化器对两者均不进行任何索引优化

    mysql> explain select * from test order by name asc,time asc;
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    |  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    

      

    mysql> explain select * from test2 order by name asc,time asc;
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    |  1 | SIMPLE      | test2 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------------+
    

      

    可以强制让其走索引

    mysql> explain select * from test force index(name_time) order by name asc,time asc;
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+
    | id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+
    |  1 | SIMPLE      | test  | index | NULL          | name_time | 515     | NULL |    3 |       |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+
    
    mysql> explain select * from test2 force index(name_time) order by name asc,time asc;
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+
    | id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+
    |  1 | SIMPLE      | test2 | index | NULL          | name_time | 515     | NULL |    3 |       |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-------+
    

      

    方向不一致就不用去说了.无论如何都会进行一次额外排序的.

    四.Where+Order

    (一).单列索引

    1.只要where中有单列索引,一定会用到索引的.

    mysql> explain select * from test where uid=14 order by id desc;
    +----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                       |
    +----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+
    |  1 | SIMPLE      | test  | ref  | uid           | uid  | 4       | const |    1 | Using where; Using filesort |
    +----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from test2 where uid=14 order by id desc;
    +----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra       |
    +----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
    |  1 | SIMPLE      | test2 | ref  | uid           | uid  | 4       | const |    1 | Using where |
    +----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
    1 row in set (0.00 sec)
    

      

    但是不同之处在于,myisam的非聚集索引,在排序时还需要数据行取数据,所以会用到额外排序.而innodb因为聚集索引,所以不会进行额外排序.(索引肯定是排好序的)

    2.where中没有索引,order中有索引,也不会走索引

    mysql> explain select * from test where time=14 order by uid desc;
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+
    |  1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where; Using filesort |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from test2 where time=14 order by uid desc;
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                       |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+
    |  1 | SIMPLE      | test2 | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where; Using filesort |
    +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------+
    1 row in set (0.00 sec)
    

    where中没有索引,order中有索引,也不会走索引 

    (二).复合索引

    仅讨论where列和order列构建的复合索引

    mysql> explain select * from test where name='jack' order by time asc;
    +----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+
    | id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra       |
    +----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+
    |  1 | SIMPLE      | test  | ref  | name_time     | name_time | 510     | const |    1 | Using where |
    +----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from test2 where name='jack' order by time asc;
    +----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+
    | id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra       |
    +----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+
    |  1 | SIMPLE      | test2 | ref  | name_time     | name_time | 510     | const |    1 | Using where |
    +----+-------------+-------+------+---------------+-----------+---------+-------+------+-------------+
    1 row in set (0.00 sec)
    

      

    只有where列是一个常量,才使用索引扫描.否则将是额外排序.

    mysql> explain select * from test where name>'jack' order by time asc;
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+
    | id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra                       |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+
    |  1 | SIMPLE      | test  | range | name_time     | name_time | 510     | NULL |    2 | Using where; Using filesort |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+
    1 row in set (0.00 sec)
    
    mysql> explain select * from test2 where name>'jack' order by time asc;
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+
    | id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows | Extra                       |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+
    |  1 | SIMPLE      | test2 | range | name_time     | name_time | 510     | NULL |    1 | Using where; Using filesort |
    +----+-------------+-------+-------+---------------+-----------+---------+------+------+-----------------------------+
    1 row in set (0.00 sec)
    

      

    mysql每次只能使用一个索引,无论是单例索引还是符合索引.

    只有用到索引,才有可能用到索引扫描(一句废话)

     

  • 相关阅读:
    敏捷开发系列学习总结(5)——这几招搞定团队协同Coding
    敏捷开发系列学习总结(4)—Git管理工具sourcetree的安装
    Java基础学习总结(74)——Java常见笔试题及答案汇总
    iOS 极光推送
    iOS UI控件没有显示时的调试技巧
    iOS 搜索之拼音搜索
    iOS MJExtension框架之字典数组转模型数组
    iOS 单例
    iOS 切换键盘
    iOS 正则表达式
  • 原文地址:https://www.cnblogs.com/itfenqing/p/8056752.html
Copyright © 2020-2023  润新知