今天晚上下班回来才有空看群,群友发了一条很简单的慢SQL问怎么优化。

非常简单,我自己模拟的数据。

表结构:

-- auto-generated definition
CREATE TABLE HHHHHH
(
ID NUMBER NOT NULL
PRIMARY KEY,
NAME VARCHAR2(20),
PARAGRAPH_ID NUMBER
)
/ CREATE INDEX IDX_1_2_PARAGRAPH_HIST_RULE
ON HHHHHH (PARAGRAPH_ID)
/ CREATE INDEX IDX_1_2_NAME_HIST_RULE
ON HHHHHH (NAME)
/

数据量:

SQL> select count(1) from HHHHHH;

  COUNT(1)
----------
200002 Elapsed: 00:00:00.00

慢SQL:

SELECT a.* FROM hhhhhh a
WHERE a.name IN (
SELECT name from hhhhhh b
GROUP BY b.name HAVING count(DISTINCT b.paragraph_id) = 1
); Plan hash value: 1063187735 ------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 | 5 (20)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | HHHHHH | 1 | 38 | 2 (0)| 00:00:01 |
|* 3 | FILTER | | | | | |
| 4 | HASH GROUP BY | | 1 | 25 | 3 (34)| 00:00:01 |
| 5 | VIEW | VM_NWVW_1 | 1 | 25 | 3 (34)| 00:00:01 |
| 6 | SORT GROUP BY | | 1 | 25 | 3 (34)| 00:00:01 |
| 7 | TABLE ACCESS FULL| HHHHHH | 1 | 25 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- " 1 - filter( EXISTS (SELECT 0 FROM (SELECT ""B"".""PARAGRAPH_ID"" "
" ""$vm_col_1"",""B"".""NAME"" ""$vm_col_2"" FROM ""HHHHHH"" ""B"" GROUP BY "
" ""B"".""NAME"",""B"".""PARAGRAPH_ID"") ""VM_NWVW_1"" GROUP BY ""$vm_col_2"" HAVING "
" ""$vm_col_2""=:B1 AND COUNT(""$vm_col_1"")=1))"
" 3 - filter(""$vm_col_2""=:B1 AND COUNT(""$vm_col_1"")=1)"

 跑了24秒没出结果我就干掉了,正常来说Oracle 这种遥遥领先的数据库,不能100毫秒以内出结果都有问题。

简单看了下上面的计划 Predicate Information 谓词信息,里面信息很复杂,懒得解释(其实我也不懂为啥CBO为啥这样乱分组过滤),并没啥卵用,感觉很SB。

一句话就是CBO等价改写了 EXISTS 还有 :B1这种变量,每次都是传个值到:B1 然后进行filter , 重点是每次。反正各位读者以后在计划中看到这种 :B1 变量都是每次每次,就是一次一次的传值,比较完一个数据继续传。

这种按照 PG 的说法就是复杂的子连接无法提升,  GROUP BY b.name HAVING count(DISTINCT b.paragraph_id) = 1 惹得锅。

复杂的子连接无法提升参考 <<PostgreSQL技术内幕:查询优化深度探索 >>这本书 3.2篇章。

加个HINT:

SELECT a.* FROM hhhhhh a
WHERE a.name IN (
SELECT /*+ unnest */ name from hhhhhh b
GROUP BY b.name HAVING count(DISTINCT b.paragraph_id) = 1
5 ); ID NAME PARAGRAPH_ID
---------- -------------------- ------------
200002 aaaaa 10000001 Elapsed: 00:00:00.05 Plan hash value: 3353221841 -------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 50 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN SEMI | | 1 | 50 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL | HHHHHH | 1 | 38 | 2 (0)| 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 1 | 12 | 3 (34)| 00:00:01 |
|* 4 | FILTER | | | | | |
| 5 | HASH GROUP BY | | 1 | 25 | 3 (34)| 00:00:01 |
| 6 | VIEW | VM_NWVW_2 | 1 | 25 | 3 (34)| 00:00:01 |
| 7 | HASH GROUP BY | | 1 | 25 | 3 (34)| 00:00:01 |
| 8 | TABLE ACCESS FULL| HHHHHH | 1 | 25 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- " 1 - access(""A"".""NAME""=""NAME"")"
" 4 - filter(COUNT(""$vm_col_1"")=1)"

使用HINT将子链接强行提升(展开)以后,秒出。

但是使用HINT容易将执行计划固定住,非必要情况下不推荐。

等价改写该SQL 方式1:

SELECT A.*
FROM HHHHHH A
INNER JOIN (SELECT COUNT(1) BB, NAME
FROM HHHHHH B
5 GROUP BY NAME) B ON A.NAME = B.NAME AND B.BB = 1; ID NAME PARAGRAPH_ID
---------- -------------------- ------------
200002 aaaaa 10000001 Elapsed: 00:00:00.03 Plan hash value: 3909860973 --------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 50 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN | | 1 | 50 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL | HHHHHH | 1 | 38 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 1 | 12 | 3 (34)| 00:00:01 |
|* 4 | FILTER | | | | | |
| 5 | HASH GROUP BY | | 1 | 12 | 3 (34)| 00:00:01 |
| 6 | TABLE ACCESS FULL| HHHHHH | 1 | 12 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- " 1 - access(""A"".""NAME""=""B"".""NAME"")"
4 - filter(COUNT(*)=1)

改写成 join 以后也是秒出。

等价改写该SQL 方式2:

SELECT X.ID,
X.NAME,
X.PARAGRAPH_ID
FROM (SELECT A.*, COUNT(DISTINCT PARAGRAPH_ID) OVER (PARTITION BY NAME) CNT FROM HHHHHH A) X
5 WHERE X.CNT = 1; ID NAME PARAGRAPH_ID
---------- -------------------- ------------
200002 aaaaa 10000001 Elapsed: 00:00:00.07 Plan hash value: 2750561680 ------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 51 | 3 (34)| 00:00:01 |
|* 1 | VIEW | | 1 | 51 | 3 (34)| 00:00:01 |
| 2 | WINDOW SORT | | 1 | 38 | 3 (34)| 00:00:01 |
| 3 | TABLE ACCESS FULL| HHHHHH | 1 | 38 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- " 1 - filter(""X"".""CNT""=1)"

改写成开窗函数以后也是秒出。

<<PostgreSQL技术内幕:查询优化深度探索 >> 这本书是真的不错,偷偷刷了好几次,每次看完都有新的理解。

Oracle "脑残" CBO 优化案例的更多相关文章

  1. 【Oracle】CBO优化详解

    SQL优化是数据优化的重要方面,本文将分析Oracle自身的CBO优化,即基于成本的优化方法.Oracle为了自动的优化sql语句需要各种统计数据作为优化基础.外面会通过sql的追踪来分析sql的执行 ...

  2. Oracle中CBO优化器简介

    Oracle中CBO优化器简介 Oracle数据库中的优化器是SQL分析和执行的优化工具.它负责制定SQL的执行计划,也就是它负责保证SQL的执行计划的效率最高,比如优化器决定Oracle以什么样的方 ...

  3. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    本文原作者:“竹千代”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.前言 无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交 ...

  4. Oracle 课程五之优化器和执行计划

    课程目标 完成本课程的学习后,您应该能够: •优化器的作用 •优化器的类型 •优化器的优化步骤 •扫描的基本类型 •表连接的执行计划 •其他运算方式的执行计划 •如何看执行计划顺序 •如何获取执行计划 ...

  5. mysql优化案例

    MySQL优化案例 Mysql5.1大表分区效率测试 Mysql5.1大表分区效率测试MySQL | add at 2009-03-27 12:29:31 by PConline | view:60, ...

  6. 脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

    本文引用了“帅地”发表于公众号苦逼的码农的技术分享. 1.引言 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢 ...

  7. 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

    本文引用了公众号纯洁的微笑作者奎哥的技术文章,感谢原作者的分享. 1.前言   老于网络编程熟手来说,在测试和部署网络通信应用(比如IM聊天.实时音视频等)时,如果发现网络连接超时,第一时间想到的就是 ...

  8. 脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

    本文原作者阮一峰,作者博客:ruanyifeng.com. 1.前言 新一代HTTP/2 协议的主要目的是为了提高网页性能(有关HTTP/2的介绍,请见<从HTTP/0.9到HTTP/2:一文读 ...

  9. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  10. 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

    .引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道“三次”和“四次”,但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方 ...

随机推荐

  1. 00-【K210】API资料、电气接线图、PCB文件

    K210的接口说明文档 API接口文档: 链接:https://pan.baidu.com/s/1mlzYRJYQIeHSEMysp_v4cg?pwd=pjmv 提取码:pjmv 2.原理图.PCB文 ...

  2. [极客大挑战 2019]web部分题解(已完结!)

    SQL部分: [极客大挑战 2019]BabySQL 打开环境后有登录界面◕‿◕ 一眼注入,后先试试万能密码: username:admin' or '1'='1 password:1 GG,出大问题 ...

  3. 设计模式之二:Builder模式

    设计模式之二:Builder模式 目录介绍 0.关于Builder模式案例下载 1.Builder模式介绍 2.Builder模式使用场景 3.Builder模式简单案例 3.1 Builder模式U ...

  4. ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接

    ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接 是因为使用urlopen方法太过频繁,引起远程主机的怀疑,被网站认定为是攻击行为.导致u ...

  5. vue3中使用simple-keyboard实现虚拟键盘(带中文切换数字键盘)

    效果图 官网 simple-keyboard官网:https://hodgef.com/simple-keyboard/ 打不开的话请用魔法 不足 中文语言包支持度不够.不过自己可以找语言包替换 依赖 ...

  6. koa2整合mysql

    引入mysql包 npm install mysql 封装mysql 创建mysql.js文件放在utils(工具包)中 使用pool连接池 mysql.js //封装mysql const mysq ...

  7. WPF自定义Panel:让拖拽变得更简单

    在 WPF 应用程序中,拖放操作是实现用户交互的重要组成部分.通过拖放操作,用户可以轻松地将数据从一个位置移动到另一个位置,或者将控件从一个容器移动到另一个容器.然而,WPF 中默认的拖放操作可能并不 ...

  8. 【问题解决1】fatal error: X11/XXXX.h: No such file or directory

    问题现象 编译鸿蒙代码时,报如下类似的错误: 错误1: 错误2: 解决方法 step 1:安装依赖文件 sudo apt-get install apt-file sudo apt-file upda ...

  9. #SG函数,记忆化搜索#HDU 4111 Alice and Bob

    题目 Alice和Bob两个好朋友又开始玩取石子了. 游戏开始时,有\(n\)堆石子排成一排,然后他们轮流操作(Alice先手),每次操作时从下面的规则中任选一个: ·从某堆石子中取走一个 ·合并任意 ...

  10. 2020东京奥运会奖牌榜可视化分析(Pyechart)

    数据获取和处理 从网页中获取各国的奖牌数量和排名以及奖牌类型(json格式). #奖牌榜数据 url = 'https://app-sc.miguvideo.com/vms-livedata/olym ...