zoukankan      html  css  js  c++  java
  • 使用覆盖索引优化like查询

    什么叫覆盖索引?
    解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。

    解释二: 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。

    解释三:是非聚集组合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆盖查询语句[select子句]与查询条件[Where子句]中所涉及的字段,也即,索引包含了查询正在查找的所有数据)。

    总之,不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引

    explain里type字段注解:

    system
    const的特例,仅返回一条数据的时候。
    const 查找主键索引,返回的数据至多一条(0或者1条)。 属于精确查找
    eq_ref 查找唯一性索引,返回的数据至多一条。属于精确查找 ref 查找非唯一性索引,返回匹配某一条件的多条数据。属于精确查找、数据返回可能是多条
    range 查找某个索引的部分索引,一般在where子句中使用 < 、>、in、between等关键词。只检索给定范围的行,属于范围查找
    index 查找所有的索引树,比ALL要快的多,因为索引文件要比数据文件小的多。
    ALL 不使用任何索引,进行全表扫描,性能最差。

    explain里extra字段注解:

    using index :使用覆盖索引的时候就会出现
    using where:在查找使用索引的情况下,需要回表去查询所需的数据
    using index condition:查找使用了索引,但是需要回表查询数据
    using index & using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据
    有实验证明using index & using where要优于using index condition。

    1.回表

    上面讲过如果索引的列在select子句中就不需要回表,索引列也是表,如果索引中包括你需要的列,查询结果就找到了,如果没有你需要的列,索引列中有指针指向表记录的行位置,从表中查询列值。

    2.索引篇

    聚簇索引:每个InnoDB表具有一个特殊的索引称为聚集索引。如果您的表上定义有主键,该主键索引是聚集索引。如果你不定义为您的表的主键 时,MySQL取第一个唯一索引(unique)而且只含非空列(NOT NULL)作为主键,InnoDB使用它作为聚集索引。如果没有这样的列,InnoDB就自己产生一个这样的ID值,它有六个字节,而且是隐藏的,使其作为聚簇索引。

    二级索引:又称辅助索引、非聚集索引(no-clustered index)。b+tree树结构,然而二级索引的叶子节点不保存记录中的所有列,其叶子节点保存的是<健值,(记录)地址>,非叶子节点存放的记录格式为<键值,主键值,地址>。而聚集索引叶子节点保存保存记录中的所有列,非叶子节点保存的是下一层节点地址。

    做个测试吧:

    建表:

    CREATE TABLE `t_user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) DEFAULT NULL,
      `age` tinyint(4) DEFAULT NULL,
      `create_time` datetime DEFAULT NULL,
      `update_time` datetime DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `name` (`name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    生成测试数据:

    DELIMITER ;;
    CREATE DEFINER=`root`@`%` PROCEDURE `proc_batch_insert`()
    BEGIN
    DECLARE pre_name BIGINT;
    DECLARE ageVal INT;
    DECLARE i INT;
    SET pre_name=187635267;
    SET ageVal=100;
    SET i=1;
    WHILE i < 1000000 DO
            INSERT INTO t_user(`name`,age,create_time,update_time) VALUES(CONCAT(pre_name,'@qq.com'),(ageVal+i)%30,NOW(),NOW());
    SET pre_name=pre_name+100;
    SET i=i+1;
    END WHILE;
    END;;
    DELIMITER ;

    id name age create_time update_time
    1 187635267@qq.com 11 2019-06-13 01:53:36 2019-06-13 01:53:36

    后面就用这一行记录做测试吧,先不加索引看看:

    运行语句:

    select name from t_user where name like '%187635267%';

    这里扫了全表,无论是百分号的位置在哪边都会去扫全表。

    那加个索引吧

    create unique index `name` on `t_user` (`name`);

    再运行同样的语句

    Using where; Using index表示要查询的数据在索引列就能获取,所以并没有回表查询。

    改下语句:

    explain select name,age from t_user where name like '187635267%';

    这边增加了age字段后,extra列显示Using index condition,因为age并不是索引 所以需要回表再查一遍age字段才行。

    那么我加上复合索引呢?试试吧:

    create index `index_name_age` on `t_user` (`name`,`age`);

    再运行上面的语句:

    又走回了覆盖索引,并且没有回表查询.因为name,age已经是复合索引了 在索引列就能获取到数据。上面也显示了用到了index_name_age这个索引.

    如果不是建的复合索引呢,比如单独给age建一个索引:

    create index `index_name_age` on `t_user` (`age`);

    所以这里并没有用到age字段的索引,需要回表查询。

    目前来说接触的大部分系统 后台都几乎是一张表的7,8成字段都要参与搜索,我总不可能每个字段都去建索引吧,目前能想到的时候把那种like查询的字段建上索引连同主键一起查出来,然后做二次查询,后面有没有更好的方法,需要以后实际中再考虑了。

  • 相关阅读:
    MCMC算法解析
    深度学习结合SLAM研究总结
    语义SLAM研究现状总结
    Tensorflow--矩阵切片与连接
    faster-rcnn原理讲解
    Tensorflow 大规模数据集训练方法
    SPP-net原理解读
    Batch Normalization原理
    RCNN算法的tensorflow实现
    Tensorflow基本操作理解
  • 原文地址:https://www.cnblogs.com/tudou1223/p/11014728.html
Copyright © 2011-2022 走看看