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查询的字段建上索引连同主键一起查出来,然后做二次查询,后面有没有更好的方法,需要以后实际中再考虑了。

  • 相关阅读:
    PAT 1010. 一元多项式求导 (25)
    PAT 1009. 说反话 (20) JAVA
    PAT 1009. 说反话 (20)
    PAT 1007. 素数对猜想 (20)
    POJ 2752 Seek the Name, Seek the Fame KMP
    POJ 2406 Power Strings KMP
    ZOJ3811 Untrusted Patrol
    Codeforces Round #265 (Div. 2) 题解
    Topcoder SRM632 DIV2 解题报告
    Topcoder SRM631 DIV2 解题报告
  • 原文地址:https://www.cnblogs.com/tudou1223/p/11014728.html
Copyright © 2011-2022 走看看