MySQL45讲之优化器选错索引

前言

本文简要介绍了优化器选择索引的依据,以及如何人为地引导优化器选择较好的执行方案。

[En]

This paper briefly introduces the basis for the optimizer to select the index and the ways to artificially guide the optimizer to choose a better execution scheme.

为什么会出现选错索引

可能是统计索引基数信息错误,导致优化器错选索引,也可能是 MySQLbug

选择依据

优化器根据扫描的行记录的数量、返回表的次数、是否创建临时表以及是否对其进行排序来选择索引。

[En]

The optimizer selects the index based on the number of scanned row records, the number of times the table is returned, whether to create a temporary table, and whether to sort it.

索引扫描行数。通过取样的方式统计索引列上不同的值数量,取 N张数据页,统计页面上不同值的数量,然后估算总的不同数量(基数 cardinality),这也称之为索引的”区分度”。可以通过 SHOW INDEX FROM table_name来查看每个索引的基数。

对于这条执行语句 SELECT * FROM t WHERE a BETWEEN (1, 10000) AND b BETWEEN (50000, 100000) ORDER BY b LIMIT 1,从扫描行数上考虑,应该选择 a上的索引,但通过 MySQL执行计划发现,实际选择了 b索引。因为优化器考虑了需要根据 b排序,选择 b索引扫描获取记录可以避免再排序。但是,使用 a索引的查询耗时远比使用 b索引耗时低。

如何避免选错索引

1、强制使用索引

使用 force Index(a)强制 SQL执行时采用某个索引,比如 SELECT * FROM t force Index(a) WHERE a BETWEEN (1, 10000) AND b BETWEEN (50000, 100000) ORDER BY b LIMIT 1

2、重新计算基数

因为 MySQL取样估计基数可能存在比较大的误差,导致优化器选择低效的执行方案。为了避免这个统计信息的问题,可以使用 Analyze TABLE t来重新统计信息。

3、选择更合适的索引或者删除误用的索引

提问

表结构
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;
创建过程,插入 100000 条数据
delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i

MySQL45讲之优化器选错索引

如果在执行事务 B之前不开启事务 A,那么语句 explain select * from t where a between 10000 and 20000;扫描行数约为 10000行;当开启事务 A,则扫描行数约为 37000行,这是为什么呢?

解释:
不开启事务 A扫描行数为 10000行,因为 MySQL采用的是标记删除的方法,在 purge线程还未执行之前,索引树和表数据并没有清除。当新插入 100000行数据时,因为主键和已经删除的相同,所以会直接复用之前删除的空间,所以优化器抽样判断扫描的行数是 10000行。

开启事务 A扫描行数为 37000行,因为事务 A开启了一致性读,于是新插入数据时,不能复用已经删除的空间,必须开辟新的空间存储,使得索引数据页的数据更加密集,从而优化器抽样判断扫描行数是 37000行。

Original: https://www.cnblogs.com/flowers-bloom/p/select-error-index.html
Author: flowers-bloom
Title: MySQL45讲之优化器选错索引

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/508167/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python 垃圾回收总结

    前言 最近在阅读《垃圾回收的算法与实现》,里面将讲到了一些常用的垃圾回收(Garbage Collect)算法,如:标记-清除、引用计数、分代回收等等。后面讲到了 Python 的…

    数据库 2023年6月6日
    0109
  • mysql视图,索引

    一、视图 View 视图是一个 虚拟表,是sql语句的查询结果,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据,在使用视图时动态生成。视图的数据变化会影响到基…

    数据库 2023年6月9日
    069
  • mysql开启二进制日志

    打开xhell进入系统 进入mysql配置文件目录 执行 cd /etc/mysql 首先找到my.cnf这个配置文件,然后使用vim进入文件编辑 放开我标记的地方。 注意我标记的…

    数据库 2023年6月6日
    0123
  • [springmvc]ssm框架整合超简单

    此整合没有具体的业务,因为ssm整合最难的点就在于配置文件的整合,因此这里只详细记录配置文件的整合 spring和dao整合将mybatis的配置文件的数据库连接和sqlsessi…

    数据库 2023年6月16日
    080
  • 西数数码-安装hmx_linux下的环境记录

    [nginx]name=nginx repobaseurl=http://nginx.org/packages/centos/6/x86_64/gpgcheck=0enabled=…

    数据库 2023年6月14日
    060
  • MySQL学习(3)—MySQL常用命令

    ps:此随笔基于mysql 5.7.*版本。 准备 net start mysql 启动MySQL服务 net stop mysql 关闭MySQL服务 mysql [-h exi…

    数据库 2023年5月24日
    086
  • go test 的内联问题

    写单测的时候遇到一个问题,在使用 gomonkey 进行打桩时,使用 gland 的 debug 运行测试时,测试程序正常跑通,而使用 run 或者命令行运行 go test -v…

    数据库 2023年6月9日
    0126
  • Golang实现set

    Golang语言本身未实现set,但是实现了map golang的map是一种无序的键值对的集合,其中键是唯一的 而set是键的不重复的集合,因此可以用map来实现set 由于ma…

    数据库 2023年6月14日
    072
  • 为知笔记迁移到印象笔记-从入门到放弃

    最新进展 已经放弃了,目前正在逐步把笔记迁移到本地,用icloud来同步。 为什么放弃迁移? 没有找到好的迁移方案,迁移过去文档不方便查找和使用 为什么放弃印象笔记? 1.主要使用…

    数据库 2023年6月9日
    093
  • SpringMvc(一)-初识

    1、环境搭建 1.1 jar包 4.3.18.RELEASE org.springframework spring-web ${spring.version} org.spring…

    数据库 2023年6月16日
    084
  • String vs StringBuffer vs StringBuilder

    String vs StringBuffer vs StringBuilder 本文翻译自:https://www.digitalocean.com/community/tutor…

    数据库 2023年6月11日
    096
  • 设计模式在业务系统中的应用

    本文的重点在于说明工作中所使用的设计模式,为了能够更好的理解设计模式,首先简单介绍一下业务场景。使用设计模式,可以简化代码、提高扩展性、可维护性和复用性。有哪些设计模式,这里就不再…

    数据库 2023年6月14日
    076
  • 分割list,将集合按规定个数分为n个部分。

      /** * 按指定大小,分隔&#x9…

    数据库 2023年6月11日
    079
  • 8、ThreadPoolTaskExecutor线程并发

    一、线程池的优点: 1、降低资源消耗。通过重复利用自己创建的线程降低线程创建和销毁造成的消耗。 2、提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。 3、提高线…

    数据库 2023年6月6日
    093
  • 类加载器及其加载原理

    概述 在之前的文章”类的加载流程”讲了一个Class文件从加载到卸载整个生命周期的过程,并且提到”非数组类在加载阶段是可控性最强的”…

    数据库 2023年6月11日
    0110
  • 第十六章:接口

    本篇翻译自《Practical Go Lessons》 Chapter 16: Interfaces 1 你将在本章学到什么? 什么是类型接口? 如何定义接口。 “实现…

    数据库 2023年6月6日
    0100
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球