zoukankan      html  css  js  c++  java
  • 第四章 -- 索引及执行计划管理

    索引的作用

    提供了类似于书中目录的作用,目的是为了优化查询

    索引的类型(算法)

    • BTREE索引
    • RTREE索引
    • Hash索引
    • Full text/全文索引

    BTREE的细分类(算法)

    • B-TREE
    • B+TREE
    • B*TREE/默认

    B树是如何构建的

    辅助索引

    -- 创建辅助索引
    alter table t1 add index idx_name(name);
    
    1. 将name列的所有值取出来,进行自动排序
    2. 将排完序的值均匀的落到16KB叶子节点数据页中,并将索引键值所对应的数据行的聚集索引列值
    3. 向上生成枝节点和根节点
    

    聚集索引(IOT)

    1. 默认是按照主键生成聚集索引.没有主键,存储引擎会使用唯一键
       如果都没有,会自动生成隐藏的聚集索引.
    2. 数据在存储时,就会按照聚集索引的顺序存储到磁盘的数据页.
    3. 由于本身数据就是有序的,所以聚集索引构建时,不需要进行排序.
    4. 聚集索引直接将磁盘的数据页,作为叶子节点.
    5. 枝节点和根节点只会调取下层节点主键的最小值
    

    辅助索引与聚集索引区别

    1)辅助索引:

    • 叶子节点只保存主键值+索引键值的有序存储
    • 对索引键值会自动排序
    • 需要手工创建
    • 辅助索引可以有多个,任何列都可以创建
      2)聚集索引
    • 只能在主键列上创建,唯一且非空
    • 数据存储时,就会按照聚集索引顺序进行排序
    • 叶子节点保存的是整个有序的数据行
    • 子夜节点不需要单独生成

    辅助索引细分

    • 单列辅助索引
    • 联合索引
    • 唯一索引

    索引树的高度(越低越好)

    表的数据量级大(导致索引树高度)

    • 分区表(了解、古老)
    • 分库分表(分布式架构、主流)

    索引键值的长度

    • 尽可能选择列值短的列创建索引
    • 采用前缀索引

    数据类型选择

    varchar 和char的选择,尽量使用varchar
    固定范围的只尽量使用 enum

    索引管理

    索引命令操作

    查询索引

    KEY:PRI(主键)、UNI(唯一索引)、MUL(辅助索引)

    mysql[school]>use school
    mysql[school]>desc student;
    mysql[school]>show index from studentG
    

    创建索引

    -- 创建单列索引 *
    mysql[school]>alter table student add index idx_name(sname);
    
    -- 创建联合索引 **
    mysql[school]>alter table student add index idx_sname_sage_ssex(sname,sage,ssex);
    
    -- 创建前缀索引 *
    mysql[school]>alter table student add index idx(sname(5));
    
    -- 创建唯一索引			
    mysql[school]>alter table student add unique index idx_tel(telnum);
    

    删除索引

    mysql[school]>alter table student drop index idx;
    mysql[school]>alter table student drop index idx_name;
    

    压力测试

    100W数据准备

    create database test charset utf8mb4;
    use test;
    create table t100w (id int,num int,k1 char(2),k2 char(4),dt timestamp);
    delimiter //
    create  procedure rand_data(in num int)
    begin
    declare str char(62) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    declare str2 char(2);
    declare str4 char(4);
    declare i int default 0;
    while i<num do
    set str2=concat(substring(str,1+floor(rand()*61),1),substring(str,1+floor(rand()*61),1));
    set str4=concat(substring(str,1+floor(rand()*61),2),substring(str,1+floor(rand()*61),2));
    set i=i+1;
    insert into t100w values (i,floor(rand()*num),str2,str4,now());
    end while;
    end;
    //
    delimiter ;
    
    插入100w条数据:
    
    call rand_data(1000000);
    
    commit;
    
    

    查询生成结果

    # 查询
    MySQL [test]>select count(*) from t100w;
    +----------+
    | count(*) |
    +----------+
    |  1000000 |
    +----------+
    1 row in set (0.47 sec)
    
    
    

    压测命令

    mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='test' --query="select * from test.t100w where k2='VWtu'" engine=innodb --number-of-queries=2000 -uroot -p123456 -verbose
    

    没有索引前,压测结果

    索引优化,创建索引

    use test;
    show tables;
    desc t100w;
    alter table t100w add index idx_k2(k2);  #优化
    

    优化索引后,压测结果

    explain(desc)

    抓取优化器优化过的执行计划

    语法

    explain select * from test.t100w where k2='VWtu';
    or
    desc select * from test.t100w where k2='VWtu';
    

    执行计划分析

    MySQL [test]>explain select * from test.t100w where k2='VWtu';
    +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    | id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
    +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | t100w | NULL       | ref  | idx_k2        | idx_k2 | 17      | const | 1120 |   100.00 | NULL  |
    +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    
    -- 重点关注
    table	        -- 以上SQL语句设计到的表 ***
    type 	        -- 查询的类型(全表扫描-ALL,索引扫描,查不到数据-NULL) *****
    possible_keys	-- 可能会用到的索引 ***
    key             -- 用到的索引 ****
    key_len	        -- 索引的覆盖长度 *****
    Extra           -- 额外的信息 ****
    

    type 详细说明

    ALL : 全表扫描 , 不会走任何索引

    1. 查询条件,没建索引
    use test;
    MySQL [test]>explain  select * from test.t100w where k2='VWtu';
    +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    | id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
    +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | t100w | NULL       | ref  | idx_k2        | idx_k2 | 17      | const | 1120 |   100.00 | NULL  |
    +----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)
    

    2)有索引不走

    desc select * from t100w where k2 != 'asdf';
    desc select * from t100w where k2 like '%aa%';
    desc select * from t100w where k2 not in ('asda','asas');
    desc select * from t100w;
    

    index 全索引扫描

    MySQL [test]>desc select k2 from t100w;
    

    range 索引范围查询

    所有索引:
    >, <, >=, <=, like, between and
    mysql[world]>desc select * from city where id<10;
    mysql[world]>desc select * from city where countrycode like 'CH%'
    
    in(), or 
    mysql[world]>desc select * from city where countrycode in ('CHN','USA');
    
    聚集索引:
    != not in
    mysql[test]>desc select * from world.city where id != 10;
    mysql[test]>desc select * from world.city where id not in (10,20);
    ========================================
    说明:
    B+tree 索引能额外优化到:> ,<, >=, <= ,like , between and
    in 和 or 享受不到b+tree额外的优化效果的,所以我一般情况会将in , or 进行改性
    mysql[world]>desc select * from city where countrycode = 'CHN' union all  select * from city where countrycode = 'USA';
    

    ref 辅助索引等值查询

    mysql[world]>desc select * from city where countrycode ='CHN';
    

    eq_ref 多表连接查询中,非驱动表on的条件列是主键或者唯一键

    mysql[world]>desc select a.name,b.name from city as a join country as b on a.countrycode=b.code where a.population<100;
    

    const(system) 主键或唯一键的等值

    mysql[world]>desc select * from city where id=10;
    

    NULL : 获取不到数据

    mysql[world]>desc select * from city where id=100000000000000;
    

    possible_keys:可能会用到的索引

    NULL: 没有和查询条件配置的索引条目
    有值:有和查询条件匹配的索引条目,但是没走,大部分原因是语句查询方式不符合索引应用条件

    key:使用到的索引

    最终使用的索引,可以帮助我们判断是否走了合适的索引.

    key_len:索引的覆盖长度

    在联合索引应用的判断时,会经常看

    对于单列索引:
    字符集:

    • utf8mb4 : 一个字符最大是4个字节
    • utf8 :一个字符最大是3个字节

    以utf8mb4为例
    ​| 数据类型 | not null | 没有指定not null |
    | ---------- | -------- | ---------------- |
    | int | 4 | 4+1 |
    | tinyint | 1 | 1+1 |
    | char(2) | 24 | 24+1 |
    | varchar(2) | 24+2 | 24+2+1 |

    建立索引的原则(DBA运维规范)

    (1) 必须要有主键,如果没有可以做为主键条件的列,创建无关列
    (2) 经常做为where条件列 order by group by join on, distinct 的条件(业务:产品功能+用户行为)
    (3) 最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引
    (4) 列值长度较长的索引列,我们建议使用前缀索引.
    (5) 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit(xxxxx)
    (6) 索引维护要避开业务繁忙期

  • 相关阅读:
    url 和 php变量传值的关系
    PHpstudy 怎么也启动不了?
    坚决不要360的全盘扫描
    用户邮件可以翻译的-drupal
    drupal网站被黑
    firefox加载不来
    转-潭的感悟
    register globals php
    $GLOBALS -- 变量
    array_merge AaCc
  • 原文地址:https://www.cnblogs.com/lpcsf/p/12076715.html
Copyright © 2011-2022 走看看