• 动力节点索引优化解决方案学习笔记——查询优化


    3.查询优化

    创建一张测试表并插入数据:

    drop table if exists students;
    CREATE TABLE students (
      id INT PRIMARY KEY AUTO_INCREMENT COMMENT "主键id",
      sname VARCHAR (24) COMMENT '学生姓名',
      age INT COMMENT '年龄',
      score INT COMMENT '分数',
      time TIMESTAMP COMMENT '入学时间'
    );
     
    INSERT INTO students(sname,age,score,time) VALUES('小明',22,100,now());
    INSERT INTO students(sname,age,score,time) VALUES('小红',23,80,now());
    INSERT INTO students(sname,age,score,time) VALUES('小绿',24,80,now());
    INSERT INTO students(sname,age,score,time) VALUES('黑',23,70,now());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.1索引失效

    1)最佳左前缀法则:如果索引了多列,要遵循最左前缀法则,指的是查询从索引的最左前列开始并且不跳过索引中的列。

    alter table students add index idx_sname_age_score(sname,age,score);
    
    -- 索引失效情况
    ① explain select * from students where sname="小明" and age = 22 and score = 100;
    ② explain select * from students where sname="小明" and age = 22;
    ③ explain select * from students where sname="小明";
    ④ explain select * from students where sname="小明" and score = 80;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以看到①②都遵守最佳左前缀法则,但是②的where条件没有完全覆盖包含索引的列,所以①的key_len相对较高,即索引使用率高
    ③遵守但是④不遵守,两者都锁定了sname,但是score使索引不再生效,所以③④的索引使用率一样

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2)不在索引列上做任何计算、函数操作,会导致索引失效而转向全表扫描。

    -- 不在索引列上做任何计算、函数操作,会导致索引失效而转向全表扫描。
    explain select * from students where left(sname,2) = "小明";
    
    • 1
    • 2

    在这里插入图片描述

    3)存储引擎不能使用索引中范围条件右边的列。

    -- 存储引擎不能使用索引中范围条件右边的列。
    explain select * from students where sname="小明" and age > 22 and score = 100;
    
    • 1
    • 2

    在这里插入图片描述

    4)Mysql在使用不等于时无法使用索引会导致全表扫描。

    -- Mysql在使用不等于时无法使用索引会导致全表扫描。
    explain select * from students where sname!="小明";
    
    • 1
    • 2

    在这里插入图片描述

    5)is null可以使用索引,但是is not null无法使用索引。

    -- is null可以使用索引,但是is not null无法使用索引。
    explain select * from students where sname is not null;
    
    • 1
    • 2

    在这里插入图片描述

    6)like以通配符开头会使索引失效导致全表扫描。

    -- like以通配符开头会使索引失效导致全表扫描。
    explain select * from students where sname like "%黑%";
    
    • 1
    • 2

    在这里插入图片描述

    7)字符串不加单引号索引会失效。

    -- 字符串不加单引号索引会失效。
    explain select * from students where sname = 123;
    
    • 1
    • 2

    在这里插入图片描述

    8)使用or连接时索引失效。

    -- 使用or连接时索引失效。
    explain select * from students where sname="小明" or age = 22;
    
    • 1
    • 2

    在这里插入图片描述
    在这里插入图片描述

    建议:
    1.对于单值索引,尽量选择针对当前查询字段过滤性更好的索引。
    2.对于组合索引,当前where查询中过滤性更好的字段在索引字段顺序中位置越靠前越好。
    3.对于组合索引,尽量选择能够包含在当前查询中where子句中更多字段的索引。
    4.尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的。

    3.2单表查询优化

    例子:

    -- 单表查询优化
    CREATE TABLE IF NOT EXISTS article (
    id INT(10) PRIMARY KEY AUTO_INCREMENT,
    author_id INT(10) NOT NULL,
    category_id INT(10) NOT NULL,
    views INT(10) NOT NULL,
    comments INT(10) NOT NULL,
    title VARBINARY(255) NOT NULL,
    content TEXT NOT NULL
    );
     
    INSERT INTO article(author_id, category_id, views, comments, title, content) VALUES
    (1, 1, 1, 1, '1', '1'),
    (2, 2, 2, 2, '2', '2'),
    (1, 1, 3, 3, '3', '3');
    
    #1.查询category_id为1的,且comments大于1的情况下,views最多的id和author_id的信息
    explain select id,author_id 
    from article
    where category_id=1 and comments>1 order by views desc limit 1;
    #2.建立索引
    alter table article add index idx_ccv(category_id,comments,views);
    #3.再次测试
    explain select id,author_id 
    from article
    where category_id=1 and comments>1 order by views desc limit 1;
    #4.重新创建索引
    drop index idx_ccv on article;
    alter table article add index idx_cv(category_id,views);
    #5.再次测试
    explain select id,author_id 
    from article
    where category_id=1 and comments>1 order by views desc limit 1;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3.3关联查询优化

    例子:

    CREATE TABLE IF NOT EXISTS class (
    id INT(10) AUTO_INCREMENT,
    card INT(10),
    PRIMARY KEY (id)
    );
    CREATE TABLE IF NOT EXISTS book (
    bookid INT(10) AUTO_INCREMENT,
    card INT(10),
    PRIMARY KEY (bookid)
    );
     
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
     
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
    
    #1.联表查询
    explain select *
    from class
    left join book
    on class.card = book.card;
    #2.建立索引
    alter table book add index idx_card(card);
    #3.测试
    explain select *
    from class
    left join book
    on class.card = book.card;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    内连接时,mysql会自动把小结果集的选为驱动表,所以大表的字段最好加上索引。左外连接时,左表会全表扫描,所以右边大表字段最好加上索引,右外连接同理。我们最好保证被驱动表上的字段建立了索引。

    3.4排序优化

    在这里插入图片描述

    1.尽量避免使用Using FileSort方式排序。
    2.order by语句使用索引最左前列或使用where子句与order by子句条件组合满足索引最左前列。
    3.where子句中如果出现索引范围查询会导致order by索引失效。

    3.5分组优化

    drop table if exists students;
    CREATE TABLE students (
      id INT PRIMARY KEY AUTO_INCREMENT COMMENT "主键id",
      sname VARCHAR (24) COMMENT '学生姓名',
      age INT COMMENT '年龄',
      score INT COMMENT '分数',
    	time TIMESTAMP COMMENT '入学时间'
    );
     
    INSERT INTO students(sname,age,score,time) VALUES('小明',22,100,now());
    INSERT INTO students(sname,age,score,time) VALUES('小红',23,80,now());
    INSERT INTO students(sname,age,score,time) VALUES('小绿',24,80,now());
    INSERT INTO students(sname,age,score,time) VALUES('黑',23,70,now());
    
    -- 分组优化
    alter table students add index idx_sas(sname,age,score);
    explain select count(*),sname 
    from students 
    where sname="小明" and age > 22
    GROUP BY score;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    react createElement 和 cloneElement 有什么区别?
    pynvml.nvml.NVMLError_FunctionNotFound: Function Not Found
    C++ 配置VSCode开发环境
    etcd cli选举流程
    达索系统SOLIDWORKS Electrical机电一体化协同设计
    C# NanoFramework 开发单片机嵌入式之 ESP32
    记录一个@Transaction注解引发的bug
    编程笔记 Golang基础 018 常量与变量
    旋转数组最小数字、数字在升序数组中出现的次数
    河北大学选择ZStack Cube超融合一体机打造实训云平台
  • 原文地址:https://blog.csdn.net/G823909/article/details/127941683