优化器生成最优执行计划需要考虑的因素

MySQL有一个优化器,专门负责生成最优的查询计划,生成最优查询计划可能考虑的因素有:

  • 扫描行数
  • 是否排序
  • 是否需要回表
  • 是否需要临时表 等等

在不同的因素作用下,生成的查询计划可能和我们预想的不同。

具体实例

实验前

先准备好表

CREATE TABLE `t` (
`id` int(11) NOT NULL,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB;

使用存储过程插入10万条数据

delimiter ;;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into t values(i, i, i);
set i=i+1;
end while;
end;;
delimiter ;
call idata();
1. 范围查询某普通索引字段,引擎选择了全表扫描,没有使用索引

调用下列语句:

explain select * from t  where a between 20000 and 40000;

执行计划查询结果如下:

| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | t | NULL | ALL | a | NULL | NULL | NULL | 100448 | 37.37 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

发现mysql使用了全表扫描,没有使用a列上的普通索引。

原因如下:

如果使用普通索引查询,还需要回表操作。当回表次数占总数据行数达到一定比例时,做随机IO查询的效率较低,并且当磁盘是机械硬盘时,多次随机IO查询一定比顺序查询的全表扫描要慢的多。

但是如果使用的是固态硬盘,随机读操作的性能很高,可以强制或者引导MySQL优化器使用普通索引来查询。

2. 查询语句中含有order by 可能会促使mysql选择排序字段对应的索引

调用下列语句:

explain select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;

执行计划查询结果如下:

| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows  | filtered | Extra                              |
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+------------------------------------+
| 1 | SIMPLE | t | NULL | range | a,b | b | 5 | NULL | 50224 | 1.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+------------------------------------+
1 row in set, 1 warning (0.00 sec)

发现MySQL选择了b列上的索引。

我们分析一下,如果使用a列上的索引,搜索的行数为1000行,回表次数为1000次,因为使用a列索引,所以排序b列时,会在排序消耗一些时间;如果使用b列的索引,搜索行数变多,回表也变多,但是不需要排序。显然,mysql在这里更加注重了排序的影响,所以选择了b列的索引。

我们执行一下强制使用a列索引的相同sql语句,和不使用force index的sql语句都执行三次,对比一下执行时间,可以查看到如果使用a索引,平均执行时间要比使用b列索引快的多。

mysql> select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.05 sec) mysql> select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.04 sec) mysql> select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.05 sec) mysql> select * from t force index(a) where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.01 sec) mysql> select * from t force index(a) where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.00 sec) mysql> select * from t force index(a) where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
Empty set (0.00 sec)
总结

相同的sql语句,在不同的计算机下,执行时间也会变得不同,上面的实验结果只代表在作者的计算机上运行得到的结果,在进行sql调优时,要根据当时环境的实际执行时间进行调试,然后决定是否应该强制使用索引。


注:这一节中,最后会写一些关于字符串加索引的思考,因为这部分知识不足以构成一个小节,所以把它添加到了这里。

字符串加索引的方式

给字符串字段加索引有几种方式:

  1. 直接创建字符串字段的完整索引,支持范围和等值查询
  2. 创建前缀索引,可能会增加扫描行数,会导致覆盖索引失效
  3. 如果前缀区分度不高,可以使用倒序存储,再根据倒叙存储的字段创建前缀索引
  4. 通过加入一个新的字段,这个字段的值为hash计算过的字段值,有额外的计算和存储消耗

第234种方式,考虑的更多的是节省存储空间,但是都增加了维护的成本。比如:

  • 第三种方式,存储的时候就需要业务或者sql保证倒叙存储,查询的时候也需要相应的利用业务或者sql倒叙函数查询,如果一旦在业务或者sql语句上忘记使用倒叙,那么在实际存储的时候也不会报错,但是会影响业务。
  • 第四种方式,除了有索引的消耗以外,还多了一个存储字段,如果有多个字符串字段需要设计搜因,那么需要增加N个hash索引字段。另外,存储和查询的时候,也多了hash计算的消耗。

在目前硬件越来越便宜的趋势下,直接使用1或者2方式创建完整或者前缀索引是完全可以的,2虽然会增加扫描行数和回表成本,但在目前的硬件下这些损耗几乎是可以忽略不计。

MySQL-SQL调优-引擎选错索引或者不使用索引分析 和 字符串加索引的方式思考的更多相关文章

  1. 《高性能SQL调优精要与案例解析》一书谈主流关系库SQL调优(SQL TUNING或SQL优化)核心机制之——索引(index)

    继<高性能SQL调优精要与案例解析>一书谈SQL调优(SQL TUNING或SQL优化),我们今天就谈谈各主流关系库中,占据SQL调优技术和工作半壁江山的.最重要的核心机制之一——索引(i ...

  2. Oracle SQL调优记录

    目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...

  3. Oracle SQL调优之分区表

    目录 一.分区表简介 二.分区表优势 三.分区表分类 3.1 范围分区 3.2 列表分区 3.3 散列分区 3.4 组合分区 四.分区相关操作 五.分区相关查询 附录:分区表索引失效的操作 一.分区表 ...

  4. MySQL索引和SQL调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...

  5. 你们一般都是怎么进行SQL调优的?MySQL在执行时是如何选择索引的?

    前言 过年回来的第二周了,终于有时间继续总结知识了.这次来看一下SQL调优的知识,这类问题基本上面试的时候都会被问到,无论你的岗位是后端,运维,测试等等. 像本文标题中的两个问题,就是我在实际面试过程 ...

  6. MySql(十一):MySQL性能调优——常用存储引擎优化

    一.前言 MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.本章将介绍最为常用的两种存储引擎进行针对性的优化建议. 二.MyISAM存储 ...

  7. MySQL性能调优与架构设计——第11章 常用存储引擎优化

    第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处. ...

  8. MySQL性能调优与架构设计——第3章 MySQL存储引擎简介

    第3章 MySQL存储引擎简介 3.1 MySQL 存储引擎概述 MyISAM存储引擎是MySQL默认的存储引擎,也是目前MySQL使用最为广泛的存储引擎之一.他的前身就是我们在MySQL发展历程中所 ...

  9. MySQL 性能调优之存储引擎

    原文:http://bbs.landingbj.com/t-0-246222-1.html        http://bbs.landingbj.com/t-0-245851-1.html MySQ ...

  10. 【叶问】 MySQL常用的sql调优手段或工具有哪些

     MySQL常用的sql调优手段或工具有哪些1.根据执行计划优化   通常使用desc或explain,另外可以添加format=json来输出更详细的json格式的执行计划,主要注意点如下:     ...

随机推荐

  1. Abp vNext 扩展属性

    扩展属性 我们发现abp的默认都会有一个ExtraProperties属性,那么他的作用是什么呢?当我们使用abp的时候,需要对其原有的表进行扩展或者添加我们想要的字段,又不想改源码,以最小的方式实现 ...

  2. Coravel:一个可轻松实现任务调度、队列、邮件发送的开源项目

    推荐一个轻量级的任务调度开源项目. 01 项目简介 Coravel是一个.NET开源任务调度库,只需简单代码.几乎零配置就可以实现多种功能柜,如任务调度.队列.缓存.事件广播和邮件发送等.该项目特点就 ...

  3. 快速上手jquery

    优点 强大的选择器机制 优质的隐私迭代 链式编程 选择机制 选择器 标签名 $('div') id $('#id') class $('.clname') 属性 $('div:[name='66']' ...

  4. Solution Set - “我将它捣成美梦愿你梦里无忧”

    目录 0.「NOI Simu.」掌分治 1.「集训队互测 2019」「LOJ #3077」绝目编诗 2.「ICPC 2019 WF」「洛谷 P6256」Directing Rainfall 3.「CT ...

  5. Solution - 「OurOJ #47407」巧立名目

    \(\mathscr{Description}\)   Private link.   给定一棵含有 \(n\) 个点的带点权树和大小为 \(m\) 的有序点对集合 \(\{(s_i,t_i)\}_{ ...

  6. 新版 Cursor 把其他 AI 编程工具按在地上摩擦了!

    大家好,我是汤师爷~ AI编程助手Cursor背后的Anysphere公司刚刚完成了1亿美元的B轮融资,估值直接飙升至26亿美元. 四个月前,这家公司刚拿下6000万美元,估值还只有4亿美元.如今,增 ...

  7. ffmpeg 视频修复和调整频率和码率

    视频修复ffmpeg -err_detect ignore_err -i input.mp4 -vcodec copy -acodec copy repaired_video.mp4 -y 调整频率和 ...

  8. 阿里云-数据库-ClickHouse

    https://help.aliyun.com/product/144466.html 云数据库ClickHouse是开源列式数据库管理系统ClickHouse在阿里云上的托管服务,用户可以在阿里云上 ...

  9. Q:记录一次ssh毫无规律的断线

    查找tailf /var/log/secure 网上一般是这三个原因 1.ssh服务端配置 vim /etc/ssh/sshd_config #客户端每隔多少秒向服务发送一个心跳数据,0代表不发送#C ...

  10. Q: 远程ssh登录不上

    1.密码没有问题 .2.防火墙没有禁用端口.3.ssh服务已安装且开启一般是ssh配置文件问题打开ssh配置文件 vim /etc/ssh/sshd_config ################## ...