zoukankan      html  css  js  c++  java
  • MySQL 组合索引、唯一组合索引的原理

    组合索引

    前言

    之前在网上看到过很多关于 mysql 联合索引最左前缀匹配的文章,自以为就了解了其原理,最近面试时和面试官交流,发现遗漏了些东西,这里自己整理一下这方面的内容。

    什么时候创建组合索引?

    当我们的 where 查询存在多个条件查询的时候,我们需要对查询的列创建组合索引。

    为什么不对没一列创建索引

    • 减少开销
    • 覆盖索引
    • 效率高

    减少开销:假如对 col1、col2、col3 创建组合索引,相当于创建了(col1)、(col1,col2)、(col1,col2,col3)3 个索引。注意,根据最左原则,不会创建(col2, col3)索引!
    覆盖索引:假如查询 SELECT col1, col2, col3 FROM 表名,由于查询的字段存在索引页中,那么可以从索引中直接获取,而不需要回表查询。

    效率高:对 col1、col2、col3 三列分别创建索引,MySQL 只会选择辨识度高的一列作为索引。假设有 100w 的数据,一个索引筛选出 10% 的数据,那么可以筛选出 10w 的数据;对于组合索引而言,可以筛选出 100w * 10% * 10% * 10% = 1000 条数据。

    最左匹配原则

    假设我们创建(col1,col2,col3)这样的一个组合索引,那么相当于对 col1 列进行排序,也就是我们创建组合索引,以最左边的为准,只要查询条件中带有最左边的列,那么查询就会使用到索引。

    创建测试表

    CREATE TABLE student ( 
    id int(11) NOT NULL, 
    name varchar(16) NOT NULL, 
    age int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY idx_id_name_age (`id`,name(10),`age`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    -- 建表时,name 长度为 16,这里用 10。这是因为一般情况下名字的长度不会超过 10,这样会加速索引查询速度,还会减少索引文件的大小,提高 INSERT 的更新速度。
    -- 如果分别在 id, name, age 上建立单列索引,让该表有 3 个单列索引,查询时和上述的组合索引效率也会大不一样,远远低于我们的组合索引。因为此时虽然有了三个索引,但 MySQL 只能用到其中的那个它认为似乎是最有效率的单列索引。
    

    填充 100w 条测试数据

    -- 因为 mysql 一遇到分号,它就要自动执行。因此在输入多条语句的时候要使用 DELIMITER 重新定义结束符号,告诉 mysql 解释器,该段命令是否已经结束了,mysql 是否可以执行了。MYSQL 的默认结束符为";"。
    DELIMITER $$ 
    DROP PROCEDURE IF EXISTS pro10$$
    CREATE PROCEDURE pro100()
    BEGIN
        DECLARE i INT;
        DECLARE char_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        DECLARE return_str varchar(255) DEFAULT '';
        DECLARE age INT;
        SET i = 1;
        WHILE i < 1000000 do
            SET return_str = substring(char_str, FLOOR(1 + RAND()*62), 8);
            SET i = i+1;
            SET age = FLOOR(RAND() * 100);
            INSERT INTO student (id, name, age) values (i, return_str, age);
        END WHILE;
    END$$
    -- 恢复 MYSQL 的默认结束符为";"
    DELIMITER ;
    -- 执行写入 100 万条数据 
    CALL pro100();
    

    场景测试

    EXPLAIN SELECT * FROM student WHERE id = 2;
    

    可以看到该查询使用到了索引(type=const&possible_keys=PRIMARY, idx_id_name_age&key=PRIMARY)

    EXPLAIN SELECT * FROM student WHERE id = 2 AND name = 'defghijk';
    

    可以看到该查询使用到了索引 (type=const&possible_keys=PRIMARY, idx_id_name_age&key=PRIMARY)

    EXPLAIN SELECT * FROM student WHERE id = 2 AND name = 'defghijk' and age = 8;
    

    可以看到该查询使用到了索引(type=const&possible_keys=PRIMARY, idx_id_name_age&key=PRIMARY)

    EXPLAIN SELECT * FROM student WHERE id = 2 AND age = 8;
    

    可以看到该查询使用到了索引(type=const&possible_keys=PRIMARY, idx_id_name_age&key=PRIMARY)

    EXPLAIN SELECT * FROM student WHERE name = 'defghijk' AND age = 8;
    

    可以看到该查询没有使用到索引 (type=all&possible_keys=null&key=null),类型为 all,查询行数为 4989449,几乎进行了全表扫描,由于组合索引只针对最左边的列进行了排序,对于 name、age 列只能进行全部扫描

    EXPLAIN SELECT * FROM student WHERE name = 'defghijk' AND id = 2;
    EXPLAIN SELECT * FROM student WHERE age = 8 AND id = 2; 
    EXPLAIN SELECT * FROM student WHERE name = 'defghijk' and age = 8 AND id = 2;
    

    可以看到如上查询也使用到了索引(type=const&possible_keys=PRIMARY, idx_id_name_age&key=PRIMARY),id 放前面和放后面查询到的结果是一样的,MySQL 会找出执行效率最高的一种查询方式,就是先根据 id 进行查询

    总结

    如上测试,可以看到只要查询条件的列中包含组合索引最左边的那一列,不管该列在查询条件中的位置,都会使用索引进行查询。

    联合唯一索引

    例如: tbl_test 表中有 aa,bb 两个字段,如果不希望有 2 条一模一样的记录(即:aa 字段的值可以重复; bb 字段的值也可以重复,但是一条记录(aa, bb)组合值不允许重复),需要给 tbl_test 表添加多个字段的联合唯一索引:

    alter table tbl_test add unique index (aa, bb);
    

    这样如果向表中添加相同记录的时候,会返回一下错误信息。
    但是配合Insert into…ON DUPLICATE KEY UPDATE…来使用就不会报错,存在相同的记录,直接忽略。

    INSERT INTO unit (id, unitsubclass, name, state)
    VALUES('1111','CPU','CPU','0' ) ON DUPLICATE KEY UPDATE       unitsubclass=VALUES(unitsubclass),name =VALUES(name),state =VALUES(state);
    

    还有一种情况就是,我们需要为以前的表 创建这个索引,有可能以前的数据中存在重复的记录 那怎么办呢?

    alter ignore table tbl_test add unique index (aa,bb);
    

    它会删除重复的记录(会保留一条),然后建立唯一索引,高效而且人性化。

    参考资料:
    [MySQL组合索引与最左匹配原则详解] https://www.jb51.net/article/157920.htm
    [普通索引和组合索引] https://www.jianshu.com/p/40edfbb50046

  • 相关阅读:
    fastx_toolkit软件使用说明
    转:bwa的使用方法
    转: Annovar 软件注释流程介绍
    转:linux下bwa和samtools的安装与使用
    GFF3格式
    漂浮广告窗
    CPU指令集设计RISC和CISC
    南方
    成都 夹三品
    微嵌1
  • 原文地址:https://www.cnblogs.com/sochishun/p/14605317.html
Copyright © 2011-2022 走看看