zoukankan      html  css  js  c++  java
  • 5 深入浅出索引(下)

    5 深入浅出索引(下)

     上一篇介绍了innodb索引的数据结构模型,这一篇将继续索引有关的概念

    create table T5 (
    ID int primary key,
    k int NOT NULL DEFAULT 0, 
    s varchar(16) NOT NULL DEFAULT '',
    index k(k))
    engine=InnoDB;
    
    insert into T5 values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

    执行语句select * from T5 where k BETWEEN 3 and 5;

    需要执行几次索引的搜索操作,会扫描多少行

    先看索引的结构

    分析sql语句的执行流程

    --1 k索引树上找到k=3的记录,取得id=300

    --2 再到id索引树上查到id=300对应的R3

    --3 k索引上找到k=5的记录,取得id=500

    --4 再回到id索引找到id=500的对应值R4

    --5 k索引上取下一个值k=6,不满足条件,循环结束。

    在这个过程中,回到主键索引树搜索的过程,称为回表,这个查询过程读了k索引树的3条记录,回表了两次。

    在这个例子中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表,那么,有没有可能经过索引优化,避免回表过程呢?

    覆盖索引

    执行语句

    (system@127.0.0.1:3306) [test]> select id from T5 where k BETWEEN 3 and 5;

    这时只需要查询id的值,而id的值已经在k索引树上,可以直接提供查询结果,不需要回表,这个查询里,索引k已经”覆盖了”我们的查询需求,称为覆盖索引

    由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的优化手段

    在讨论一个问题,在一个市民信箱表上,是否有必须要将身份证和名字建立联合索引?

    CREATE TABLE `tuser` (
      `id` int(11) NOT NULL,
      `id_card` varchar(32) DEFAULT NULL,
      `name` varchar(32) DEFAULT NULL,
      `age` int(11) DEFAULT NULL,
      `ismale` tinyint(1) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `id_card` (`id_card`),
      KEY `name_age` (`name`,`age`)
    ) ENGINE=InnoDB

    现在有一个高频需求,根据市民的身份证号查询他的姓名,建立一个联合索引(身份证号、姓名),在这个查询上用到覆盖索引,不需要在回表查整行记录,减少语句的执行时间。

    索引字段的维护是有代价的,因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑。

    最左前缀原则

    B+树这种索引结构,可以利用索引的”最左前缀”

    前面的(name,age)索引来分析

    可以看到,索引项是按照索引定义里面出现字段的顺序排序的。

    查询语句” where name like ‘%’ ”能够用上索引,查询到第一个符合条件的记录是id3,然后向后遍历,直到不满足条件为止

    可以看到,不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索,这个最左前缀可以是联合字段索引的最左N个字段,也可以是字符串索引的最左M个字符。

    基于上面对最左前缀索引的说明:在建立联合索引的时候,如何安排索引内的字段顺序

      评估标准是,索引的复用能力,因为可以支持最左前缀,所以当已经有了(a,b)这个联合索引后,一般不需要单独在a上建立索引了。第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的

      联合索引(a,b),查询条件只有b的语句,是无法使用该索引的,得新建一个(b)的索引才能使用。

    索引下推

    前面说到满足最左前缀原则的时候,最左前缀可以用于在索引中定位记录

    mysql> select * from tuser where name like '%' and age=10 and ismale=1;

    Mysql 5.6引入了索引下推优化(index condition pushdown)可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数

    思考题

    表结构定义如下

    CREATE TABLE `geek` (
      `a` int(11) NOT NULL,
      `b` int(11) NOT NULL,
      `c` int(11) NOT NULL,
      `d` int(11) NOT NULL,
      PRIMARY KEY (`a`,`b`),
      KEY `c` (`c`),
      KEY `ca` (`c`,`a`),
      KEY `cb` (`c`,`b`)
    ) ENGINE=InnoDB;

    由于历史原因表需要ab做联合主键,cacb两个索引的查询

    select * from geek where c=N order by a limit 1;

    select * from geek where c=N order by b limit 1;

    分析联合索引cacb和索引c之间的合理性

    --添加索引c

    --添加索引cb

    分析

    表记录

    --a--|b--|c--|d

    主键ab的聚簇索引组织顺序相当于order by a,b,也就是先按a排序,再按b排序,c无序

    索引ca的组织是先按照c排序,再按照a排序,同时记录主键

    --c--|a--|主键部分b(注意这里不是ab,而是只有b

    这个跟索引c的数据是一样的

    索引cb是先c排序,再按b排序,同时记录主键

    --c--|b--|主键部分a--

    所以,索引ca可以去掉,cb可以保留

  • 相关阅读:
    Linux命令总结--grep命令
    Linux命令总结--sed命令
    python函数--enumerate()方法
    python函数--index()方法
    在objc项目中使用常量的最佳实践
    iOS 开发 初级:应用内购买 In-App Purchase
    CFUUIDRef和CFStringRef-生成唯一标识符
    保留你的dSYM文件
    xcode 环境,多工程联编设置【转】
    ld: symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o for architecture i386
  • 原文地址:https://www.cnblogs.com/yhq1314/p/11064513.html
Copyright © 2011-2022 走看看