目录

  • 前言
  • 1、内连接中的类似笛卡尔积现象导致oom
    • 场景简述
    • 分析与现象还原
  • 2、单表有多种查询时索引的建立
    • 场景简述
    • 权衡添加索引
  • 3、绑定执行计划纠正错误的索引选择
    • 场景简述
    • sql绑定执行计划
  • 4、index join的Probe 端加上索引加快join
  • 5、其他情况
    • - sql中有查询视图
    • - 强行定义子查询让某些表先连接
    • - 原始sql变动改造
    • - 将exsit改造成join去实现
  • 作者想说

前言

上周支持了一个金融场景的TiDB项目,集群版本是5.1.2,因为某些原因,未使用tiflash组件,而在生产中又确实有许多复杂的sql需要执行,且存在部分高并发的sql,基于现状,就做了很多sql调优的工作。

这篇文章,主要是分享作者做过的一些比较有意思的sql调优的方式方法。


1、内连接中的类似笛卡尔积现象导致oom

场景简述

应用反馈有个功能有时候能跑出来,有时候跑不出来(内存占用超过10G)。在dashboard慢查询中定位到了对应的sql,对sql和执行计划进行分析发现这个sql是对三张表的一个inner join的关联查询,执行计划显示,三张表经过过滤出来结果集分别约为3千条、20万条、1000万条数据,进行连接后最终的结果集超过11亿行数据。经过对比分析,功能跑不出来的原因是每次计算到11亿行数据时容易触发oom,导致查询失败报错。

分析与现象还原

当时第一眼很困惑在左连接中没有一个超过11亿行的表,为什么最终join的结果集这么大,后来分析定位发现是两表中的中关联条件存在大量重复的数据,导致产生了一个类似笛卡尔积的现象,导致结果集过大。

举例与演示:

CREATE TABLE a(id INT(10) ,NAME CHAR(20), gra INT(20),PRIMARY KEY (id));
CREATE TABLE b(id INT(10) ,NAME CHAR(20), class CHAR(20));
INSERT INTO a VALUES(1,'李四',10);
INSERT INTO a VALUES(2,'李四',11);
INSERT INTO a VALUES(3,'王五',12);INSERT INTO b VALUES(2,'李四',11);
INSERT INTO b VALUES(2,'李四',11);
INSERT INTO b VALUES(2,'李四',11);
INSERT INTO b VALUES(3,'王五',12);
INSERT INTO b VALUES(3,'王五',13);
INSERT INTO b VALUES(3,'王五',12);
INSERT INTO b VALUES(3,'王五',13);#原始的sql
EXPLAIN ANALYZE
SELECT a.id,a.name,a.gra
FROM a INNER JOIN b ON a.name=b.name
GROUP BY a.id#改造后的sql
EXPLAIN ANALYZE
SELECT a.id,a.name,a.gra
FROM a INNER JOIN (SELECT DISTINCT NAME  FROM b) b ON a.name=b.name
GROUP BY a.id

原始sql在join后会产生10行记录,原因是b表中多行记录其实能和a表中多行记录匹配到,结果集数量类似于笛卡尔积的那种产生方式,在关联的表数据量大的时很容易oom(#这里是2*3+1*4=10)

由于在这个sql中,b表的作用其实只是相当于取name列的数据到a表name列中进行过滤,且中间的多行结果集并不影响最终结果,这里可以加一个临时表,先将b表数据进行去重,在真实的场景中数据量特别大时,去重后,连接计算量会明显变小,内存消耗变小,结果集变小,sql不会oom了,sql也更快了。(#有时候sql消耗的很大一部分内存是连接时候的一个内存放大)


2、单表有多种查询时索引的建立

场景简述

通常我们通过dashboard抓取到慢sql时,通过执行计划分析时,如果发现多次查询,且查询的数据量很少,且对表的查询没有走索引,在执行计划中是全表查询的,然后在到内存中进行过滤,这个时候我们就会考虑对过滤条件的字段建立索引。

执行计划大致如下:

但是当你准备给这个张表的部分字段添加索引时,你已经发现这张表有5~6个索引时,你就不能直接继续添加新索引,因为维护索引是有成本的,而且为了维护一致性读,在高并发的场景中不适合添加太多的索引,这个时候你就需要综合考虑所有对表的操作来添加有限的索引

权衡添加索引

1、不是所有的过滤条件都需要添加索引

当表A已经有索引A(a,b,c)时,这时候有个查询的过滤条件字段分别是(b,a,d),这个时候如果当表A中字段a和字段b的过滤性不错的时候,就不再单独需要对(b,a,d)再添加索引了。在sql实际执行时,会先利用索引A对条件字段(a,b)进行过滤(最左匹配原则),再到内存中对条件字段d进行过滤。

类似的执行计划:

2、字段过滤性越好,优先级越高

##从直方图中查询A表的过滤性
show stats_histograms where table_name = 'A';

举例:加入需要对org_no,table_name,up_org_no三个条件添加索引,根据直方图中distinct_count列的过滤性显示,索引字段的顺序应该是org_no,up_org_no,table_name。

#有时候也考虑字段内容,例如长文本等就不建议添加索引

3、字段复用率越高,查询频次越高越应该添加索引

  • 当对表的多个查询的过滤条件都涉及的字段,我们越应该将它添加到索引中,且应该放在索引左边更容易复用。

  • 和应用开发人员确认,执行频率越高的sql的过滤条件,我们越应该添加索引。

4、依据最左匹配原则减少索引数量

例如有4组查询条件

(a,b)
(a,b,c)
(a)
(a,b,c,d)

(a,b,c)过滤性良好的情况下,只需要用(a,b,c)字段创建一个索引就行,且越被复用的字段就应该越放在左边

5、综合考虑拆表

当查询的种类变多,索引的简历就要考虑到整体影响,一般而言,一张表的索引数量不应该超过6个,对表的需求再多的时候建议拆分表,宽表变多个窄表


3、绑定执行计划纠正错误的索引选择

场景简述

在一次排查慢sql的过程中,发现有一条sql会偶发性的执行时间特别长,对比执行计划,发现耗时长的sql在走一个子查询算子查询时,特别耗时,查看算子的执行信息,发现这个算子索引的选择与其他的索引选择不一致(索引走错了),查看表索引,发现这个表的索引较多,且部分索引会部分重复。

(V5.1.4)多次发现,有当表的索引很多时,执行器会偶尔错误的选择索引,不选最佳的索引。

分析执行计划展示:

sql绑定执行计划

举例:这里强行表b走索引x_y_z,去绑定执行计划

create global binding for
select *
from a
inner join b use index(x_y_z)
on a.id=b.id
where b.x='chen' and b.y='zhuo'
using
select *
from a
inner join b use index(x_y_z)
on a.id=b.id
where b.x='chen' and b.y='zhuo'

4、index join的Probe 端加上索引加快join

用 EXPLAIN 查看 JOIN 查询的执行计划 | PingCAP Docs


5、其他情况

还有一些其他情况

- sql中有查询视图

有一次有一个慢sql,查看执行计划发现是有多个表关联,但是sql很简单,后面意识到是有视图,在这个sql中视图其实就可以看成子查询,一个提前定义好的子查询,所以针对这个sql的优化也需要考虑到视图(子查询)的优化,添加索引等。

- 强行定义子查询让某些表先连接

有时侯多表连接时,某些表先连接计算会效率比较高,这样我们可以定义子查询指定某些表先连接

举例:

#改造前:
select a.id ,b.name,c.gra
from a,b,c
where a.id=b.id
and b.name=c.name
and c.gra=a.gra
#强行指定a和b表先做连接,
#改造后:
select t.id ,t.name,c.gra
from
(
select a.id ,b.name ,a.gra
from a
inner join b
on a.id=b.id
) t
inner join c
on t.gra= c.gra
and t.name=c.name

- 原始sql变动改造

有时候开发人员在编写sql时,由于考虑拼接复用,或者某些工具生成的sql,并未考虑sql执行性能等,也未考虑实际需要,这里就需要多和应用人员一起去核对部分慢sql,考虑:是否就是需要全表查询、全表关联、一次性取太多数据等等问题

#1、作者就碰到过,sql每次向应用服务器返回几十万条数据,然后到应用端再去过滤,某次并发高了,应用服务器oom,这种就需要在sql上,限值查询返回的数据量

#2、作者还碰到过关联的表未加任何过滤条件,全表关联,和应用确认后业务上可以先添加过滤条件过滤,再关联,该造后sql耗时大大变小

- 将exsit改造成join去实现

#这里不是去讲exsit和in的相互替换与区别

根据tidb官方学习视频,exsit和in在执行时都会转化为连接去实现,但是根据多次实测,建议尽量主动去将sql中exsit改写成inner join去实现。


作者想说

1、文章是作者主观所写,如果有错误或者笔误欢迎指正。

2、sql调优还有许多大量的典型案例,估计大家都知道,我这里就都没讲,只是重点讲了部分比较有意思的、偏门的。

3、sql调优是一个持续优化,不断优化更进的事情!

版权声明:本文由神州数码云基地团队整理撰写,若转载请注明出处。
公众号搜索神州数码云基地,后台回复TiDB,加入TiDB技术交流群!

【TiDB】一些很有意思的sql调优案例分享相关推荐

  1. sql如何遍历几百万的表_Oracle PL/SQL调优技巧分享

    原创作者:如人饮水冷暖自知 责任编辑:AcDante 前言 开门见山,今天和大家聊聊如何对PL/SQL代码进行优化,以及如何编写高效的PL/SQL代码,如果您是开发DBA,或者您是数据库开 发人员,对 ...

  2. 无线网调优案例分享,很实用

    背景: 某工厂选择了华为的wlan无线覆盖,为厂区的PDA等终端设备采集数据实时上传至总部服务器:在部署后客户测试阶段,录入数据时会片面出现终端缓冲转圈的情况,经ping测有丢包出现,1000包丢5, ...

  3. SQL调优案例,MYSQL服务器性能调优

    服务器环境见下表 服务器环境 序号 名称 版本 内存 CPU 1 Windows Server 2008 64bit R2 16G 2 2 Mysql 5.7 256M 2 一.问题现象 1.服务器C ...

  4. ORACLE SQL调优案例一则

    收到监控告警日志文件(Alert)的作业发出的告警邮件,表空间TEMPSCM2不能扩展临时段,说明临时表空间已经被用完了,TEMPSCM2表空间不够用了 Dear All:     The Insta ...

  5. jvm性能调优 - 11J线上VM调优案例分享

    文章目录 Pre 案例分析 业务背景 这个系统到底多快会塞满新生代? 触发Minor GC的时候会有多少对象进入老年代? 系统运行多久,老年代大概就会填满? 这个系统运行多久,老年代会触发1次Full ...

  6. sql调优的几种方式_「数据库调优」屡试不爽的面试连环combo

    点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...

  7. Mysql高级调优篇——第五章:Sql调优在面试中深度剖析

    上节讲了Sql调优实战,本章聊聊面试中Sql调优深度的剖析场景! 在讲之前我们先做一些准备工作,建立一些需要用到的表: Mysql高级调优篇表补充--建表SQL_风清扬逍遥子的博客-CSDN博客⭐️t ...

  8. 读《程序员的SQL金典》[4]--SQL调优

    一.SQL注入 如果程序中采用sql拼接的方式书写代码,那么很可能存在SQL注入漏洞.避免的方式有两种: 1. 对于用户输入过滤敏感字母: 2. 参数化SQL(推荐). 二.索引 ①索引分类 聚簇索引 ...

  9. sql优化的方法及思路_合理的sql优化思路--如何缩短SQL调优时间?

    概述 当生产环境发生故障或者系统特别慢的时候,这时候你从awr报告拿到有问题的sql,但是优化的时候却优化了很久还没解决,这时候在领导或者客户面前就不太好了...那么我们怎么去缩短sql调优的时间,一 ...

最新文章

  1. Xamarin 学习笔记 - 配置环境(Windows iOS)
  2. TweetBot TabBar
  3. error_reporting()
  4. Ghost网刻后window 7 sysprep无人值守应答文件制作
  5. 域控制器显示无法使用解决办法
  6. python接口测试_Python接口自动化测试框架实战开发(一)
  7. Scrapy 教程(九)-日志系统
  8. 风渠全能永久免费进销存,无功能限制,网络+单机组合版本+云商平台管理系统,风渠ERP。(源代码)
  9. html中车牌号省份简称输入键盘
  10. 极限-反函数极限问题
  11. 朱松纯领衔、北大清华超强联合,开启「通用人工智能实验班」
  12. 会话技巧---英文单词
  13. 【§炫彩苹果win7主题§】
  14. 2022CCPC桂林站感想与反思
  15. 物联网临界段实现原理
  16. 按照分数进行名次计算、名次排序
  17. 最新研究!美国爱荷华州立大学利用量子计算模拟原子核
  18. 【作业】{r} :Shiny app 中使用 isolate 函数,达到 app 作图变换时的不实时反馈效果
  19. 学习笔记——面向对象第三天
  20. Delph 表格数据导出方法汇总

热门文章

  1. Centos安装Gitlab
  2. 解决苹果手机微信音视频不能自动播放问题
  3. 《阴阳师》桃花妖在哪打
  4. 根据qq号获取qq头像
  5. split()分割字符串数组
  6. Java编程中的注意点
  7. java linkedlist排序_Java LinkedList排序
  8. 如何用ZBrush改变物体的颜色和材质
  9. JS实现localStorage自动保存功能
  10. 如何使用PS给照片加水印