MySQL-SQL调优-引擎选错索引或者不使用索引分析 和 字符串加索引的方式思考
优化器生成最优执行计划需要考虑的因素
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调优时,要根据当时环境的实际执行时间进行调试,然后决定是否应该强制使用索引。
注:这一节中,最后会写一些关于字符串加索引的思考,因为这部分知识不足以构成一个小节,所以把它添加到了这里。
字符串加索引的方式
给字符串字段加索引有几种方式:
- 直接创建字符串字段的完整索引,支持范围和等值查询
- 创建前缀索引,可能会增加扫描行数,会导致覆盖索引失效
- 如果前缀区分度不高,可以使用倒序存储,再根据倒叙存储的字段创建前缀索引
- 通过加入一个新的字段,这个字段的值为hash计算过的字段值,有额外的计算和存储消耗
第234种方式,考虑的更多的是节省存储空间,但是都增加了维护的成本。比如:
- 第三种方式,存储的时候就需要业务或者sql保证倒叙存储,查询的时候也需要相应的利用业务或者sql倒叙函数查询,如果一旦在业务或者sql语句上忘记使用倒叙,那么在实际存储的时候也不会报错,但是会影响业务。
- 第四种方式,除了有索引的消耗以外,还多了一个存储字段,如果有多个字符串字段需要设计搜因,那么需要增加N个hash索引字段。另外,存储和查询的时候,也多了hash计算的消耗。
在目前硬件越来越便宜的趋势下,直接使用1或者2方式创建完整或者前缀索引是完全可以的,2虽然会增加扫描行数和回表成本,但在目前的硬件下这些损耗几乎是可以忽略不计。
MySQL-SQL调优-引擎选错索引或者不使用索引分析 和 字符串加索引的方式思考的更多相关文章
- 《高性能SQL调优精要与案例解析》一书谈主流关系库SQL调优(SQL TUNING或SQL优化)核心机制之——索引(index)
继<高性能SQL调优精要与案例解析>一书谈SQL调优(SQL TUNING或SQL优化),我们今天就谈谈各主流关系库中,占据SQL调优技术和工作半壁江山的.最重要的核心机制之一——索引(i ...
- Oracle SQL调优记录
目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...
- Oracle SQL调优之分区表
目录 一.分区表简介 二.分区表优势 三.分区表分类 3.1 范围分区 3.2 列表分区 3.3 散列分区 3.4 组合分区 四.分区相关操作 五.分区相关查询 附录:分区表索引失效的操作 一.分区表 ...
- MySQL索引和SQL调优手册
MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...
- 你们一般都是怎么进行SQL调优的?MySQL在执行时是如何选择索引的?
前言 过年回来的第二周了,终于有时间继续总结知识了.这次来看一下SQL调优的知识,这类问题基本上面试的时候都会被问到,无论你的岗位是后端,运维,测试等等. 像本文标题中的两个问题,就是我在实际面试过程 ...
- MySql(十一):MySQL性能调优——常用存储引擎优化
一.前言 MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.本章将介绍最为常用的两种存储引擎进行针对性的优化建议. 二.MyISAM存储 ...
- MySQL性能调优与架构设计——第11章 常用存储引擎优化
第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处. ...
- MySQL性能调优与架构设计——第3章 MySQL存储引擎简介
第3章 MySQL存储引擎简介 3.1 MySQL 存储引擎概述 MyISAM存储引擎是MySQL默认的存储引擎,也是目前MySQL使用最为广泛的存储引擎之一.他的前身就是我们在MySQL发展历程中所 ...
- MySQL 性能调优之存储引擎
原文:http://bbs.landingbj.com/t-0-246222-1.html http://bbs.landingbj.com/t-0-245851-1.html MySQ ...
- 【叶问】 MySQL常用的sql调优手段或工具有哪些
MySQL常用的sql调优手段或工具有哪些1.根据执行计划优化 通常使用desc或explain,另外可以添加format=json来输出更详细的json格式的执行计划,主要注意点如下: ...
随机推荐
- 基于NVIDIA NGC容器安装使用PaddlePaddle
基于NVIDIA NGC容器安装使用PaddlePaddle PaddlePaddle PaddlePaddle作为国内首个自主研发的深度学习平台,自2016年正式向专业社区开源,是一个技术先进.功能 ...
- kubeadm 快速搭建 Kubernetes 集群
快速搭建 K8s 集群 角色 ip k8s-master-01 192.168.111.170 k8s-node-01 192.168.111.171 k8s-node-02 192.168.111. ...
- 一站式解决方案 :OFD电子证照生成
前言 证照的电子化是一个趋势:可以预计,未来几年内,绝大部分证照都会电子化.电子证照的种类越来越多,应用场景也复杂多样:这就给电子证照规范的制定.电子证照的生成提出了更高的要求.电子证照采用的格式有两 ...
- Springboot 整合 xxl-job
前言 很久很久以前写过好几篇关于定时任务的使用系列的文章: 这一篇是最简单的,就是单纯跑跑定时任务,那你看这篇就行,没必要用xxljob(因为xxljob要跑服务端,然后自己服务作为客户端接入): 文 ...
- Redis的分布式锁详解
Redis实现的分布式锁 # 对资源key加锁,key不存在时创建,并且设置,10秒自动过期 SET key value EX 10 NX # 删除key DEL key NX的作用 NX参数是为了保 ...
- SQL查询语句中for update使用注意事项
1.join查询语句中,适用的情况下,尽量使用of关键字对必要的表上锁,而不是锁定所有表的相关行. 上述代码是在门诊医嘱签名时,为了处方签名重复操作,在签名修改数据前对涉及医嘱行进行上锁处理,for ...
- 浅谈Redis的三种集群策略及应用场景
本文分享自天翼云开发者社区<浅谈Redis的三种集群策略及应用场景>,作者:段林 Redis提供了三种集群策略: 1.主从模式:这种模式⽐较简单,主库可以读写,并且会和从库进⾏数据同步,这 ...
- yum repo和rpm,添加阿里repos
RPMRPM(Red-hat Package Manager),是一个由红帽最早开发出来的包管理器,目前已经是大多数Linux发行的默认包管理器.RPM管理的包都是以.rpm结尾,其中存储了该软件的安 ...
- Flink 部署和整体架构
一.Flink运行部署模式和流程 部署模式: 1.Local 本地部署,直接启动进程,适合调试使用 2.Standalone Cluster集群部署,flink自带集群模式 3.On Yarn 计算资 ...
- [SCOI2007] 蜥蜴 题解
发现实际上就是在求有多少只蜥蜴能逃出来. 发现可以将柱子拆成入点和出点两部分,自己的出点向别人的入点连边,自己的入点向自己的出点连边.最后再加一个超级源点 \(S\),连接所有有蜥蜴的柱子入点:再加一 ...