10 mysql选错索引
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选错索引的更多相关文章
- MySQL 选错索引的原因?
MySQL 中,可以为某张表指定多个索引,但在语句具体执行时,选用哪个索引是由 MySQL 中执行器确定的.那么执行器选择索引的原则是什么,以及会不会出现选错索引的情况呢? 先看这样一个例子: 创建表 ...
- MySQL选错索引导致的线上慢查询事故
前言 又和大家见面了!又两周过去了,我的云笔记里又多了几篇写了一半的文章草稿.有的是因为质量没有达到预期还准备再加点内容,有的则完全是一个灵感而已,内容完全木有.羡慕很多大佬们,一周能产出五六篇文章, ...
- 10 | MySQL为什么有时候会选错索引?
前面我们介绍过索引,你已经知道了在MySQL中一张表其实是可以支持多个索引的.但是,你写SQL语句的时候,并没有主动指定使用哪个索引.也就是说,使用哪个索引是由MySQL来确定的. 不知道你有没有碰到 ...
- MySQL 笔记整理(10) --MySQL为什么有时会选错索引?
笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 10) --MySQL为什么有时会选错索引? MySQL中的一张表上可以 ...
- 10 | MySQL为什么有时候会选错索引? 学习记录
<MySQL实战45讲>10 | MySQL为什么有时候会选错索引? 学习记录http://naotu.baidu.com/file/e7c521276650e80fe24584bc9a6 ...
- MySQL ORDER BY主键id加LIMIT限制走错索引
背景及现象 report_product_sales_data表数据量2800万: 经测试,在当前数据量情况下,order by主键id,limit最大到49的时候可以用到索引report_produ ...
- Mysql数据库建立索引的优缺点有哪些?
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息. 什么是索引 数据库索引好比是一本书前面的目录,能加快数据库的查询速度. 例如这样一个查询:select * ...
- 2-16 MySQL字段约束-索引-外键
一:字段修饰符 1:null和not null修饰符 我们通过这个例子来看看 mysql> create table worker(id int not null,name varchar(8) ...
- MySQL的前缀索引及Oracle的类似实现
MySQL有一个很有意思的索引类型,叫做前缀索引,它可以给某个文本字段的前面部分单独做索引,从而降低索引的大小. 其实,Oracle也有类似的实现,对于文本,它可以通过substr的函数索引,实现同样 ...
随机推荐
- Scale-up and Scale-out(转载)
原地址:http://www.cnblogs.com/spork/archive/2009/12/29/1634766.html 来自原小站,曾经迷糊过的东西,表上来,希望对正在迷糊或即将迷糊的人有帮 ...
- Java多线程1:使用多线程的几种方式以及对比
前言 Java多线程的使用有三种方法:继承Thread类.实现Runnable接口和使用Callable和Future创建线程,本文将对这三种方法一一进行介绍. 1.继承Thread类 实现方式很简单 ...
- .NET Compiler Platform,一个.NET编译平台
.NET Compiler Platform,一个.NET编译平台 如何利用C# Roslyn编译器写一个简单的代码提示/错误检查? OK, 废话不多说,这些天在写C#代码时突然对于IDE提示有了 ...
- 【SQL-自动生成编号】按规则自动生成单据编号 以及并发问题_使用触发器、函数 等
描述:每种单据新建时,自动生成它的单据编号. 规则如:固定码+日期+流水号 (ABC1603180001) 方法一:触发器 触发器的缺点是,执行了sql之后才看到编码. 测试:流水号不能超过最大数,否 ...
- Python CGI编程Ⅵ
GET和POST方法 浏览器客户端通过两种方法向服务器传递信息,这两种方法就是 GET 方法和 POST 方法. 使用GET方法传输数据 GET方法发送编码后的用户信息到服务端,数据信息包含在请求页面 ...
- JS实现表格隔行变色
用到的鼠标事件:(1)鼠标经过 onmouseover:(2)鼠标离开 onmouseout 核心思路:鼠标经过 tr 行的时候,当前行会改变背景颜色,鼠标离开的时候去掉背景颜色. 注意:第一行(th ...
- POJ 1466 大学谈恋爱 二分匹配变形 最大独立集
Girls and Boys Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 11694 Accepted: 5230 D ...
- ZooKeeper 简介说明
1.什么是Zookeeper? Zookeeper是一个高效的分布式协调服务,它暴露了一些公用服务,比如命名/配置管理/同步控制/群组服务等.我们可以使用Zookeeper来实现比如达成共识/集群管理 ...
- B. Chocolates
B. Chocolates time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- bootstrap editable有默认值
function listEditor(data,productCode) { $('#tab1').bootstrapTable('load', data); $('#tab1').bootstra ...