10 mysql选错索引

在mysql表中可以支持多个索引,有的sql不指定使用哪个索引,由mysql自己来决定,但是有时候mysql选错了索引,导致执行很慢。

例子

CREATE TABLE `t10` (
`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;

往表中插入10w记录

过程

delimiter ;;
create procedure idata_t11()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into t10 values(i, i, i);
set i=i+1;
end while;
end;;
delimiter ;
call idata_t11();

分析sql语句

mysql> select * from t where a between 10000 and 20000;

SESSION A

SESSION B

start transaction with consistent snapshot;

delete from t;

call idata_t11()

explain  select * from t10 where a between 10000 and 20000;

commit;

 

Session B的查询语句explain  select * from t10 where a between 10000 and 20000;就不会在选择所有a了,可以通过慢查询日志

set long_query_time=0;
select * from t where a between 10000 and 20000; /*Q1*/
select * from t force index(a) where a between 10000 and 20000;/*Q2*/

优化器的逻辑

选择索引是优化器的工作,而优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句

在数据库里面,扫描行数是影响执行代价的因素之一,扫描的行数越少,意味着访问磁盘数据的次数越少,消耗的cpu资源越少。

当然,扫描行数并不是唯一的判断标准,优化器还会结合是否使用临时表、是否排序等因素综合判断。

扫描行数是怎么判断的?

MySQL在真正开始语句执行之前,并不能精确地知道满足这个条件的记录是多少,只能根据统计信息来估算记录数。

这个统计信息就是索引的”区分度”,显然,一个索引上不同的值越多,这个索引的区分度也就越高,而一个索引上不同的值的个数,称为”基数”,这个基数越大越好。

Mysql采样统计的方法,采样统计的时候,innodb默认会选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。

而数据表是会持续更新的,索引统计信息也不会固定不变,所以,当变更的行数超过1/M的时候,会自动触发重新做一次索引统计。

在mysql中,有两种存储索引统计的方式,可以通过参数innodb_stats_persitent

(system@127.0.0.1:3306) [test]> show variables like 'innodb_stats_persistent';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_stats_persistent | ON |
+-------------------------+-------+

--设置为on,表示统计信息会持久化到存储,默认N=20,M=10

--设置为off,表示统计信息只存储在内存中,默认N=8,M=16

其实索引统计只是一个输入,对于一个具体的语句来说,优化器还要判断,执行这个语句要扫描多少行

统计信息不准确,使用analyze table t10;

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

索引选择异常和处理

一种方法是,采用force index(t)强行选择一个索引。

第二种方式就是,可以考虑修改语句,引导mysql使用我们期望的索引。

之前优化器选择使用索引b,因为它认为使用索引b可以避免排序(b本身是索引,已经是有序的,如果选择索引b的话,不需要在做排序只需要遍历),所以即使扫描行数更多,也判定为代价更小。

现在使用了 order by b,a,要求按照b,a排序,就意味着使用这两个索引都需要排序,因此扫描行数变成了影响决策的主要条件,此时就选择了a索引。

当然,这种修改并不是通用的优化手段,只是刚好在这个语句有limit 1,如果都有满足条件的行,要逻辑结果一致才可以这么修改。

第三种是在有些场景下,我们可以新建一个更合适的索引,来提供给优化器做选择,或者删掉误用的索引。

10 mysql选错索引的更多相关文章

  1. MySQL 选错索引的原因?

    MySQL 中,可以为某张表指定多个索引,但在语句具体执行时,选用哪个索引是由 MySQL 中执行器确定的.那么执行器选择索引的原则是什么,以及会不会出现选错索引的情况呢? 先看这样一个例子: 创建表 ...

  2. MySQL选错索引导致的线上慢查询事故

    前言 又和大家见面了!又两周过去了,我的云笔记里又多了几篇写了一半的文章草稿.有的是因为质量没有达到预期还准备再加点内容,有的则完全是一个灵感而已,内容完全木有.羡慕很多大佬们,一周能产出五六篇文章, ...

  3. 10 | MySQL为什么有时候会选错索引?

    前面我们介绍过索引,你已经知道了在MySQL中一张表其实是可以支持多个索引的.但是,你写SQL语句的时候,并没有主动指定使用哪个索引.也就是说,使用哪个索引是由MySQL来确定的. 不知道你有没有碰到 ...

  4. MySQL 笔记整理(10) --MySQL为什么有时会选错索引?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 10) --MySQL为什么有时会选错索引? MySQL中的一张表上可以 ...

  5. 10 | MySQL为什么有时候会选错索引? 学习记录

    <MySQL实战45讲>10 | MySQL为什么有时候会选错索引? 学习记录http://naotu.baidu.com/file/e7c521276650e80fe24584bc9a6 ...

  6. MySQL ORDER BY主键id加LIMIT限制走错索引

    背景及现象 report_product_sales_data表数据量2800万: 经测试,在当前数据量情况下,order by主键id,limit最大到49的时候可以用到索引report_produ ...

  7. Mysql数据库建立索引的优缺点有哪些?

    索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息. 什么是索引 数据库索引好比是一本书前面的目录,能加快数据库的查询速度. 例如这样一个查询:select * ...

  8. 2-16 MySQL字段约束-索引-外键

    一:字段修饰符 1:null和not null修饰符 我们通过这个例子来看看 mysql> create table worker(id int not null,name varchar(8) ...

  9. MySQL的前缀索引及Oracle的类似实现

    MySQL有一个很有意思的索引类型,叫做前缀索引,它可以给某个文本字段的前面部分单独做索引,从而降低索引的大小. 其实,Oracle也有类似的实现,对于文本,它可以通过substr的函数索引,实现同样 ...

随机推荐

  1. 【POJ2376】Cleaning Shifts

    题目大意:区间最小覆盖问题. 题解:本身是一道贪心水题,但是细节还是比较多的,记录一下. 由于每个奶牛对答案的贡献是一样的,肯定要选择在满足条件的基础上能够拓展最多的那个奶牛.为了满足条件,对区间左端 ...

  2. Angular4.x+Ionic3 踩坑之路之 Ionic3.x pop反向传值

    1.Ionic3.x 页面正向传值 关于正向传值,上一篇文章里面有讲,具体可以看这里https://segmentfault.com/a/11... 2.Ionic3.x 页面 pop反向传值,主要有 ...

  3. nginx部署网站step by step

    安装后,修改nginx.conf,在httpd{}中添加 include /nginx/vhosts/*.conf; 如果没有vhosts就新建一个文件夹 *.conf是一种正则表达式用法,表示纳入一 ...

  4. .NET-list扩展方法Distinct去重

    原文链接:https://blog.csdn.net/daigualu/article/details/70800012 .NET中list的扩展方法Distinct可以去掉重复的元素,分别总结默认去 ...

  5. Python3数据结构汇总

    字符 列表 元组 集合 字典 能否被索引或切片 能 能 能 否 否 元素能否被编辑 否 能 否 能 能 增 1.list.append(x):把一个元素添加到列表的结尾: 2.list.insert( ...

  6. 处理离散型特征和连续型特征共存的情况 归一化 论述了对离散特征进行one-hot编码的意义

    转发:https://blog.csdn.net/lujiandong1/article/details/49448051 处理离散型特征和连续型特征并存的情况,如何做归一化.参考博客进行了总结:ht ...

  7. react 引入swiper

    npm install --save swiper 应用模块引入 import 'swiper/dist/css/swiper.min.css' import Swiper from 'swiper'

  8. 分块查找(Blocking Search)

    1.定义 分块查找(Blocking Search)又称索引顺序查找.它是一种性能介于顺序查找和二分查找之间的查找方法. 2.基本思想 分块查找的基本思想是: (1)首先查找索引表 索引表是有序表,可 ...

  9. 直接选择排序(Straight Selection Sort)

    1.定义 选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕. 常用的选择排序方法有直接选择排序和堆 ...

  10. 小程序开发获取token值

    // 登录 wx.login({ success: res => { // 发送 res.code 到后台换取 openId, sessionKey, unionId // console.lo ...