某系统反馈慢SQL影响生产,查看SLOW LOG发现下面慢SQL:

  1. SELECT COUNT(DISTINCT m.batch_no)
  2. FROM ob_relation r
  3. INNER JOIN ob_batch_d d
  4. ON r.sub_order_no = d.outbound_no
  5. INNER JOIN ob_batch_m m
  6. ON d.batch_no = m.batch_no
  7. WHERE r.production_mode =1
  8. AND r.yn=0
  9. AND r.outbound_no ='xxxx2156'
  10. AND d.yn=0
  11. AND m.yn=0
  12. AND m.SEND_FLAG=0
  13. AND m.batch_no!='xxx00025984';

设计表上索引情况如下:

  1. ob_relation上索引:
  2. KEY `idx_outbound_no` (`OUTBOUND_NO`),
  3. KEY `idx_sub_order_no` (`SUB_ORDER_NO`)
  4.  
  5. ob_batch_d上索引:
  6. KEY `idx_update_time` (`UPDATE_TIME`),
  7. KEY `idx_ob_outbound_batch_d_batch_no` (`BATCH_NO`),
  8. KEY `idx_ORDER_GROUP_ID` (`ORDER_GROUP_ID`),
  9.  
  10. ob_batch_m上索引:
  11. KEY `idx_update_time` (`UPDATE_TIME`),
  12. KEY `idx_BATCH_NO` (`BATCH_NO`),
  13. KEY `idx_BEAT_NO` (`BEAT_NO`),
  14. KEY `idx_BATCH_TYPE_OPT_STATUS` (`BATCH_TYPE`,`OPT_STATUS`),
  15. KEY `ix_SEND_FLAG` (`SEND_FLAG`)

查看执行计划为:

  1. +----+-------------+-------+------------+------+----------------------------------+----------------------------------+---------+--------------------+-------+----------+-------------+
  2. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  3. +----+-------------+-------+------------+------+----------------------------------+----------------------------------+---------+--------------------+-------+----------+-------------+
  4. | 1 | SIMPLE | r | NULL | ref | idx_outbound_no,idx_sub_order_no | idx_outbound_no | 92 | const | 4 | 1.25 | Using where |
  5. | 1 | SIMPLE | m | NULL | ref | idx_BATCH_NO,ix_SEND_FLAG | ix_SEND_FLAG | 2 | const | 54292 | 5.07 | Using where |
  6. | 1 | SIMPLE | d | NULL | ref | idx_ob_outbound_batch_d_batch_no | idx_ob_outbound_batch_d_batch_no | 92 | ob_task.m.BATCH_NO | 16 | 1.00 | Using where |
  7. +----+-------------+-------+------------+------+----------------------------------+----------------------------------+---------+--------------------+-------+----------+-------------+

本着直觉判定使用索引ix_SEND_FLAG但影响行数为54292步骤存在问题,虽然过滤条件中包含SEND_FLAG=0且列SEND_FLAG上有索引,但选择性较差,初步断定查询走错索引导致。

尝试1:删除列SEND_FLAG上索引,迫使查询走列BATCH_NO上索引,删除列SEND_FLAG上索引后,执行计划变为:

  1. +----+-------------+-------+------------+-------+----------------------------------+----------------------------------+---------+--------------------+--------+----------+---------------------------------------------------------------------------+
  2. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  3. +----+-------------+-------+------------+-------+----------------------------------+----------------------------------+---------+--------------------+--------+----------+---------------------------------------------------------------------------+
  4. | 1 | SIMPLE | r | NULL | ref | idx_outbound_no,idx_sub_order_no | idx_outbound_no | 92 | const | 4 | 1.25 | Using where |
  5. | 1 | SIMPLE | m | NULL | range | idx_BATCH_NO | idx_BATCH_NO | 92 | NULL | 146187 | 9.99 | Using index condition; Using where; Using join buffer (Block Nested Loop) |
  6. | 1 | SIMPLE | d | NULL | ref | idx_ob_outbound_batch_d_batch_no | idx_ob_outbound_batch_d_batch_no | 92 | ob_task.m.BATCH_NO | 16 | 1.00 | Using where |
  7. +----+-------------+-------+------------+-------+----------------------------------+----------------------------------+---------+--------------------+--------+----------+---------------------------------------------------------------------------+

查询影响行数变得更高,性能更差。

尝试2:检查INNER JOIN 关联列和WHERE条件列上的数据类型,排除隐式转换导致。

尝试3: 去除与ob_batch_m的所有相关进行,仅剩表ob_relation和ob_batch_d做INNER JOIN,其执行计划为:

  1. SELECT COUNT(DISTINCT d.batch_no)
  2. FROM ob_relation r
  3. INNER JOIN ob_batch_d d
  4. ON r.sub_order_no = d.outbound_no
  5. WHERE r.production_mode =1
  6. AND r.yn=0
  7. AND r.outbound_no ='xxxx2156'
  8. AND d.yn=0
  9.  
  10. +----+-------------+-------+------------+------+----------------------------------+-----------------+---------+-------+---------+----------+----------------------------------------------------+
  11. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  12. +----+-------------+-------+------------+------+----------------------------------+-----------------+---------+-------+---------+----------+----------------------------------------------------+
  13. | 1 | SIMPLE | r | NULL | ref | idx_outbound_no,idx_sub_order_no | idx_outbound_no | 92 | const | 4 | 1.25 | Using where |
  14. | 1 | SIMPLE | d | NULL | ALL | NULL | NULL | NULL | NULL | 4917114 | 1.00 | Using where; Using join buffer (Block Nested Loop) |
  15. +----+-------------+-------+------------+------+----------------------------------+-----------------+---------+-------+---------+----------+----------------------------------------------------+

发现表ob_batch_d的关联条件上缺少索引导致。

问题总结:

查询中ob_relation和ob_batch_d关联,而ob_batch_d和ob_batch_m关联,但由于表ob_batch_d关联条件上没有索引且表ob_relation上WHERE过滤条件选择性极高,因此查询优化器将SQL转换为:

  1. SELECT COUNT(DISTINCT m1.batch_no) FROM (
  2. SELECT m.batch_no,d.outbound_no
  3. FROM ob_batch_d d
  4. INNER JOIN ob_batch_m m
  5. ON d.batch_no = m.batch_no
  6. WHERE d.yn=0
  7. AND m.yn=0
  8. AND m.SEND_FLAG=0
  9. AND m.batch_no!='xxx00025984'
  10. )AS m1
  11. INNER JOIN (
  12. SELECT r.sub_order_no
  13. FROM ob_relation r
  14. WHERE r.production_mode =1
  15. AND r.yn=0
  16. AND r.outbound_no ='xxxx2156'
  17. )AS r1
  18. ON m1.outbound_no=r1.sub_order_no

对于m1子查询内部,表ob_batch_m可以通过SEND_FLAG=0来过滤部分数据(虽然选择性较差),因此选择使用索引ix_SEND_FLAG,而表ob_batch_d上缺少索引的问题被“完美隐藏”。

在优化INNER JOIN操作时,通常需要先确定两表的关系(外表和内表),外表通过WHERE条件列来过滤数据,而内表通过关联条件列来定位数据。

如对于下列查询:

  1. SELECT COUNT(1)
  2. FROM ob_relation r
  3. INNER JOIN ob_batch_d d
  4. ON r.sub_order_no = d.outbound_no
  5. WHERE r.outbound_no ='xxxx2156';

表ob_relation和表ob_batch_d做INNER JOIN操作
1、表ob_relation作为外表,可以通过outbound_no ='xxxx2156'来过滤数据,因此需要在ob_relation(outbound_no)上创建索引。

2、表ob_batch_d作为内表,需要通过关联列outbound_no来定位数据,因此需要在ob_batch_d(outbound_no)上创建索引。

3、表ob_relation的关联条件sub_order_no并不需要单独作为索引第一列来创建索引,但在部分查中可以通过覆盖索引特性来优化查询,如上面查询中创建组合索引ob_relation(outbound_no,sub_order_no)能获得最佳性能。

总结:

有时候,经验能帮助你快速处理问题,但有些时候,经验能带你直接走入误区。

MySQL Index--关联条件列索引缺失导致执行计划性能不佳的更多相关文章

  1. SQL Server-聚焦使用索引和查询执行计划(五)

    前言 上一篇我们讲了聚集索引对非聚集索引的影响,对数据库一直在强调的性能优化,所以这一节我们统筹讲讲利用索引来看看查询执行计划是怎样的,简短的内容,深入的理解,Always to review the ...

  2. mysql查询优化器为什么可能会选择错误的执行计划

    有可能导致mysql优化器选择错误的执行计划的原因如下: A:统计信息不准确,mysql依赖存储引擎为其提供的统计信息来评估成本,然而有的存储引擎提供的信息是准确的,有的引擎提供的可能就偏差很大,如: ...

  3. SQL Tuning 基础概述10 - 体会索引的常见执行计划

    在<SQL Tuning 基础概述05 - Oracle 索引类型及介绍>的1.5小节,提到了几种"索引的常见执行计划": INDEX FULL SCAN:索引的全扫描 ...

  4. SQL Server-聚焦使用索引和查询执行计划

    前言 上一篇我们讲了聚集索引对非聚集索引的影响,对数据库一直在强调的性能优化,所以这一节我们统筹讲讲利用索引来看看查询执行计划是怎样的,简短的内容,深入的理解,Always to review the ...

  5. MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划

    这篇文章主要介绍了MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划的相关资料,需要的朋友可以参考下 一.索引 MongoDB 提供了多样性的索引支持,索引信息被保存 ...

  6. MySQL 索引管理与执行计划

    1.1 索引的介绍 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息.如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息. ...

  7. MySQL学习【第七篇索引管理及执行计划】

    一.索引介绍 1.什么是索引? 索引由如字典,目的就是为了更快寻找到要找的内容. 令搜索查询的数据更有目的性,从而提高数据检索的能力 2.索引类型介绍 1.BTREE: B+树索引 2.HASH: H ...

  8. 第六章· MySQL索引管理及执行计划

    一.索引介绍 1.什么是索引 1)索引就好比一本书的目录,它能让你更快的找到自己想要的内容. 2)让获取的数据更有目的性,从而提高数据库检索数据的性能. 2.索引类型介绍 1)BTREE:B+树索引 ...

  9. Mysql索引、explain执行计划

    1.索引的使用场景 哪些情况使用索引: 1.主键自动建立唯一索引 2.频繁作为查询条件的字段应该创建索引 where 3.多表关联查询中,关联字段应该创建索引on两边都要创建索引 select * f ...

随机推荐

  1. 缓存:修改Hosts不生效

    修改Hosts为何不生效,是DNS缓存? - Barret李靖 - 博客园https://www.cnblogs.com/hustskyking/p/hosts-modify.html 换个未打开过的 ...

  2. 如何通过配置tomcat或是web.xml让ie直接下载文件

    web.xml(tomcat\conf\web.xml)中配置了 <mime-mapping>   <extension>txt</extension>   < ...

  3. vmware装centos7 无法上网

    现象 使用ip address看不到ip地址 ping www.baidu.com无法ping通 解决方式: 1.设置网卡 vi /etc/sysconfig/network-scripts/ifcf ...

  4. python 把带小数的浮点型字符串转换为整数的解决方案

    以下内容在python中完全可以接受: 将整数的字符串表示形式传递给 int 将float的字符串表示形式传递给 float 但是,如果你将float型的字符串传递给int将会得到错误. >&g ...

  5. 011-数据结构-树形结构-B+树[mysql应用]、B*树

    一.B+树概述 B+树是B树的变种,有着比B树更高的查询效率. 一棵 B+ 树需要满足以下条件: 节点的子树数和关键字数相同(B 树是关键字数比子树数少一) 节点的关键字表示的是子树中的最大数,在子树 ...

  6. Qt QtXml读取xml文件内容

    Qt QtXml读取xml文件内容 xml文件内容 <?xml version="1.0" encoding="UTF-8"?> <YG_RT ...

  7. LODOP打印超文本有边距不居中的情况2

    之前的博文:LODOP打印项水平居中.之前的博文有介绍超文本和纯文本的居中方式,设置超文本打印项居中时,注意打印内容要在打印项本身宽度里居中.之前的博文超文本用的是个表格,而且表格本身没有margin ...

  8. mysql8忘记秘密-重置密码步骤

    mysql8修改密码的方式有些许不同 1.配置无密码登录 修改/etc/my.cnf文件,在mysqld模块下添加 skip-grant-tables 2.重启mysql 3.mysql -uroot ...

  9. [LeetCode] 651. 4 Keys Keyboard 四键的键盘

    Imagine you have a special keyboard with the following keys: Key 1: (A): Print one 'A' on screen. Ke ...

  10. windows下Java调用可执行文件

    缘起: 由于没有找到java转换文件的接口,因此使用java调用exe文件进行文件转换 public void convertFile(){ Runtime rn = Runtime.getRunti ...