对于IN查询,MySQL会根据当前表数据结构(索引)和数据分布(统计信息和预估)生成多种执行计划,并根据执行成本挑选出“最优执行计划”。

假设有查询

  1. SELECT *
  2. FROM student
  3. WHERE class_id IN (1,2,3,4);

有下面三种执行计划:

1、对表student做表扫描
2、循环IN列表中每个值,对表student上class_id列做索引查找
3、计算IN列表中最大值和最小值,对表student上class_id列做索引范围扫描

方式1:对表student做表扫描

对表做全表扫描,遍历student表的每行数据,找出每行匹配IN条件的记录并返回。查询效率与表数据量成正比。

伪代码:

  1. def get_students_01():
  2. class_id_list=(1,2,3,4)
  3. matched_rows=[]
  4. for student_row in (table scan in table student):
  5. if student_row.class_id in class_id_list:
  6. matched_rows.append(student_row)
  7. return matched_rows

适用场景:

1、列class_id上无索引,导致只能全表扫描

2、满足IN条件的数据占整表数据比重较大时,如表中班级ID仅有(1,2,3,4,5),需要查询满足(1,2,3,4)的记录,表中大部分数据都满足该条件,如果使用列class_id做索引查找+PRIMARY KEY LOOKUP操作,PRIMARY KEY LOOKUP操作会产生大量随机IO,执行成本远超过全表扫描产生的顺序IO。

性能问题:

当列class_id上存在索引且满足IN条件的数据占整表数据比重较小时,全表扫描会访问大量“无用数据”,浪费IO和CPU资源,导致性能问题。如全表数据有1000W,满足IN条件的数据仅有10行,此时使用INDEX SEEK+KEY LOOPUP会效率更高。

方式2:循环IN列表中每个值,对表student上class_id列做索引查找

循环取出IN列表中每个值,并使用该值去表student中根据class_id做等值查询,然后做PRIMARY KEY LOOPUP,最后将每个IN列表值查询结果汇总后返回

伪代码:

  1. def get_students_02():
  2. class_id_list=(1,2,3,4)
  3. matched_rows=[]
  4. for tmp_class_id in class_id_list:
  5. for tmp_student_id in (index seek in table student with index idx_class_id where class_id = tmp_class_id):
  6. student_row = (index seek in table student with primary key where student_id = tmp_student_id)
  7. if student_row is not null:
  8. matched_rows.append(student_row)
  9. return matched_rows

适用场景:

1、列class_id上有索引,且列class_id选择性较高,IN列表数据量较少

性能问题:

1、列class_id上有索引,但列class_id选择性较差,需要进行大量KEY LOOPUP操作,产生大量随机IO导致性能问题

2、列class_id上有索引,但IN列表包含值太多,需要进行多次循环,MySQL Server层和存储引擎层需要进行多次交互,引发性能问题。

方式3:计算IN列表中最大值和最小值,对表student上class_id列做索引范围扫描

获取IN列表中最大值和最小值,并使用这两值去表student中根据class_id做范围扫描(顺序IO),对扫描后的结果按照IN列表进行过滤,然后做PRIMARY KEY LOOPUP,最后将所有满足条件的数据汇总返回。

伪代码:

  1. def get_students_02()
  2. class_id_list=(1,2,3,4)
  3. matched_rows=[]
  4. max_class_id=max(class_id_list)
  5. min_class_id=min(class_id_list)
  6. for tmp_student_id in (index seek in table student with index idx_class_id where class_id >=min_class_id and class_id<=max_class_id):
  7. student_row = (index seek in table student with primary key where student_id = tmp_student_id)
  8. if student_row is not null:
  9. if student_row.class_id in class_id_list:
  10. matched_rows.append(student_row)
  11. return matched_rows

方式3是对方式2的优化,通过一次范围扫描来替换循环索引查找。

适用场景:

1、列class_id上有索引,IN列表包含大量值,且值集中在特定范围,如class_id的值分布在0-99999范围,而IN列表的值集中在1000-2000范围,扫描该范围数据可获得所有满足条件的数据。

性能问题:

1、列class_id上有索引,IN列表包含大量值,且值分散在整表范围,如class_id的值分布在0-99999范围,而IN列表的值为(1000,5000,10000,90000),取值在1000-90000范围,需要扫描范围过大,其扫描结果中大量数据不满足IN条件,访问过多“无用数据”,造成性能问题。

扩展知识:

对于IN列表中的值进行预估时,受参数eq_range_index_dive_limit影响,超过阈值后,会导致预估准确率问题。

https://www.cnblogs.com/TeyGao/p/6585879.html

MySQL Execution Plan--IN查询计划的更多相关文章

  1. MySQL Execution Plan--IN子查询包含超多值引发的查询异常

    问题描述 版本:MySQL 5.7.24 SQL语句: SELECT wave_no, SUM(IF(picking_qty IS NULL, 0, picking_qty)) AS PICKED_Q ...

  2. MySQL Execution Plan--NOT IN查询

    在某系统中想使用NOT IN子查询进行数据过滤,SQL为: SELECT * FROM TB001 AS T1 DAY) AND T1.BATCH_NO NOT IN(SELECT BATCH_NO ...

  3. Mysql优化之Explain查询计划查看

    我们经常说到mysql优化,优化中一种常见的方式就是对于经常查询的字段创建索引.那么mysql中有哪些索引类型呢? 一.索引分类1.普通索引:即一个索引只包含单个列,一个表可以有多个单列索引 2.唯一 ...

  4. MySQL Execution Plan--IN子查询对UPDATE语句影响

    问题描述 在系统中发现一条执行时间为为44652.060734秒(12.5小时)的慢SQL,SQL语句为: UPDATE ob_internal_task SET OPERATE_STATUS WHE ...

  5. MySQL Execution Plan--IN子查询包含超多值引发的查询异常1

    ======================================================================= SQL语句: SELECT wave_no, SUM(I ...

  6. Execution Plan 执行计划介绍

    后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载.  下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 ...

  7. SQLServer查询计划

    参考:http://blog.csdn.net/luoyanqing119/article/details/17022649 1. 开启方式 菜单栏:query---Display Estimated ...

  8. sql server 执行计划(execution plan)介绍

    大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习. 什么是 ...

  9. MySQL的查询计划中ken_len的值计算

    本文首先介绍了MySQL的查询计划中ken_len的含义:然后介绍了key_len的计算方法:最后通过一个伪造的例子,来说明如何通过key_len来查看联合索引有多少列被使用. key_len的含义 ...

  10. MYSQL查询计划KEY_LEN

    http://www.innomysql.com/article/25241.html 1 key_len的含义 2 MySQL中key_len计算规则 3 通过key_len分析联合索引 本文首先介 ...

随机推荐

  1. robot framework学习五——AutoltLibrary库

    安装中遇到的问题: 安装好了AutoItLibrary,但是导入到RIDE后,仍然红色显示 搜索了下解决办法,说要安装下autoit-v3-setup.exe https://www.autoitsc ...

  2. English trip EM2-LP-4B At school Teacher:Will

    课上内容(Lesson) 词汇(Key Word ) art  美术:艺术 business  商科 engineering  工程学 graphic design  平面造型学 history  历 ...

  3. Introducing the Microservices Reference Architecture from NGINX

    Introducing the Microservices Reference Architecture from NGINX https://www.nginx.com/blog/introduci ...

  4. day048 BOM和DOM

    BOM   Browser Object Model(文档对象模型) > window对象 1.alert     弹出带有提示和一个确认按钮的警示框 2.confirm       弹出带有一 ...

  5. 1023. Camelcase Matching驼峰式匹配

    网址:https://leetcode.com/problems/camelcase-matching/ 依题意可得逻辑 class Solution { public: vector<bool ...

  6. [luogu P3648] [APIO2014]序列分割

    [luogu P3648] [APIO2014]序列分割 题目描述 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序 ...

  7. AIX中PV,VG,LV及FS常用相关命令

    1.PV常用相关命令 1)lsdev:列出ODM(Object Data Manager)中的设备. 2)chdev:修改一个AIX设备的属性. 3)mkdev:创建一个AIX设备. 4)chpv:修 ...

  8. Eclipse+Spring boot开发教程

    一.安装 其实spring boot官方已经提供了用于开发spring boot的定制版eclipse(STS,Spring Tool Suite)直接下载使用即可,但考虑到可能有些小伙伴不想又多装个 ...

  9. Linux下maven安装

    1.下载maven的tar.gz格式文件到/opt文件夹下 2.解压mavenmaven压缩包 tar -xvzf maven.tar.gz -C /usr/local 3.配置maven的环境变量 ...

  10. Saiku本地编译运行后Debug调试(十二)

    Saiku源码拉下来在本地编译通过,然后想进行单元测试 发现不知道怎么写测试类了... 幸好有同事大佬的帮助,教了一招哈哈哈哈... 1.将本地编译通过的Saiku打包好(mvn clean inst ...