陈顼

大家好,我是来自天善BI社区的老头子,专注于 BI 方向,是个 Oracle 爱好者,同时也是 ACOUG 成员。今天想给大家分享一个SQL性能方面的话题 — 不合理视图合并引发的性能问题。

在开始分享具体案例之前,首先我们需要了解两个概念:视图合并和笛卡尔积。下面我来分别解释一下:

视图合并:视图合并是 SQL 算法生成时所发生的一种查询转换,这表示 CBO 在确保查询结果正确的前提下,为了产生更好的执行计划而隐式的等价改写了 SQL。而视图合并的改写方式则是就是 CBO 把不同查询块中的对象拆分重新组合后,再把本来没有直接关联关系的表进行重写为 CBO 认为最优的表关联顺序。如果在一个查询块中使用了如聚集合运算、rownum 等这种需要整体计算的函数的时候,CBO 就无法进行视图合并,因为如果进行合并改写则可能会引起结果不正确。

如:当存在以下情况时,CBO 则无法进行视图合并操作:

内联视图中含有集合运算:UNION, UNION ALL, INTERSECT, MINUS 等

聚集函数:AVG, COUNT, MAX, MIN, SUM 等

rownum、connect by、rollup、cube 等

在 CBO 允许的情况下,我们可以使用/*+ MERGE(V)*/的hint来强制视图合并,但如果 Oracle 发现改写后 SQL 的结果和原始的不一致,那么即便加了hint也无法改变执行计划。

同上,在结果集不变的前提下,强制禁止视图合并的 Hint:/*+ NO_MERGE */

如果 Oracle 没有做视图合并,那么我们可以在执行计划中看到 view 关键字(特殊情况除外,如临时视图等)

视图合并大概介绍这么多,大家应该有个大概的了解,那么我们为什么还要讲笛卡儿积呢?因为笛卡儿积是在 SQL 性能问题中一个典型的性能故障点,而在我后面分享的案例中,就遭遇了由于不当的视图合并导致错误的笛卡儿积算法。

笛卡尔积:又称直积,两个集合X和Y的笛卡尔积表示为 X * Y,是所有X和Y可能组合的集合。在数据库中表现为表A和表B没有任何关联条件而产生的结果集。

例如:

X 集合有3条数据{1,2,3}

Y集合有3条数据{3,4,5}

那么X和Y的笛卡尔积为:{(1,3), (1,4), (1,5), (2,3), (2,4), (2,5), (3,3), (3,4), (3,5)} 共9组数据。

但并非所有笛卡尔积都是有问题的,如:关联的其中一个集合只有一条数据时,此时笛卡尔积就不会引发性能问题,因为当X = 1时,X * Y = Y。

我之前的博客曾经写过对典型笛卡尔积引发性能问题的优化案例:

这里再简单介绍下,例如:A、B、C三表做连接查询:

SELECT * FROM A AA, B BB, C CC

WHERE AA.ID = BB.ID

AND BB.ID = CC.ID

那么根据 SQL 来看正确的关联顺序应该是A先和B表关联,再和C表关联。

然而由于统计信息不准确,或 CBO bug 引起的A和C两表走了关联,由于A 和 C 之间没有关联条件,从而导致低效的笛卡尔积。

基于上面的介绍,我分享一个简单的小案例由于视图合并而引起的低效笛卡尔积从而导致 SQL 性能低下。

案例背景:

表数据量:

ZQGS:88

H1H2H3:518459

HDB:81

CCOD_PROV_INFO:32

CC_CITY_INFO:335

SQL 如下,要跑 20s:

SELECT COUNT(Z.REMOTE_URL)

FROM ZQGS Z,

(SELECT H.H1H2H3

FROM H1H2H3 H, HDB D, CCOD_PROV_INFO P, CC_CITY_INFO C

WHERE H.AREA_CODE = C.CITY_ID

AND C.PROV_ID = P.PROV_ID

AND P.PROV_ID = 1

AND H.H1H2H3 LIKE D.HD || '%'

AND D.ID = '1') M

WHERE (Z.END_TYPE = 255 OR Z.END_TYPE = 254)

AND Z.REMOTE_URL LIKE 'TEL:' || M.H1H2H3 || '%';

COUNT(Z.REMOTE_URL)

——————-

21

Elapsed: 00:00:20.21

预估执行计划及统计信息如下:

从执行计划中可以看出,SQL 走了2个笛卡尔积(MERGE JOIN CARTESIAN)

第一个笛卡尔积 ID = 6:

我们暂不谈 CBO 评估是否有误,且认为 CBO 评估的 rows 是正确的,所以这里是因为 CBO 对 CCOD_PROV_INFO 评估只有1条数据(ID 为7的行,Rows 列的值评估为1),从而 CBO 评估笛卡尔积的连接方式代价比其他连接更低。所以这一个笛卡尔积,属于上文所提到的其中一个集合只有1条数据时,笛卡尔积是更高效的匹配方式。

第二个笛卡尔积 ID = 5:

这里就是由于 HDB 表和其他表并没有任何关联,而由于视图合并引发两个没有关联的表做了关联查询,从而引发的笛卡尔积。

由于开发人员说 SQL 中的主表是测试使用的表,即便优化后也无法模拟真实情况,于是在优化前换了个主表 TBPT,重新造了数据(表结构一样,接近真实数据量),数据量为18682454(其他表不变)

TBPT:18682454

H1H2H3:518459

HDB:81

CCOD_PROV_INFO:32

CC_CITY_INFO:335

SQL 如下:

SELECT/*+ GATHER_PLAN_STATISTICS */

COUNT(Z.REMOTE_URL)

FROM TBPT Z,

(SELECT H.H1H2H3

FROM H1H2H3 H, HDB D, CCOD_PROV_INFO P, CC_CITY_INFO C

WHERE H.AREA_CODE = C.CITY_ID

AND C.PROV_ID = P.PROV_ID

AND P.PROV_ID = 1

AND H.H1H2H3 LIKE D.HD || '%'

AND D.ID = '1') M

WHERE (Z.END_TYPE = 255 OR Z.END_TYPE = 254)

AND Z.REMOTE_URL LIKE 'TEL:' || M.H1H2H3 || '%';

主表从 ZQGS 的40条 , 增加到了 TBPT 表数据量的1800万条,基本跑不出数据来,所以超过5分钟我就把 SQL 中断掉了。

新的评估执行计划如下:

通过上面的执行计划看出,换了表的 SQL 依旧存在笛卡尔积,但由于数据量的改变,导致两个表的关联顺序发生了改变,所以性能故障点并没有改变,

ID = 6 和 ID = 7 的两个笛卡尔积

ID=12 的 TBPT 的全表扫描

根据 ID= 8 的 rows = 1得出 ID = 7 的笛卡尔积是高效关联。所以,此 SQL 最大的开销在 ID=6 的笛卡尔积,和 ID=12 的 TBPT 的全表扫描。所以要减少这两步的 cost 首先要让 SQL 走正确的关联路径,其次在 TBPT 表增加索引,减少全表扫描所带来的开销。

优化点:

1. 在内联视图中增加提示:/*+ NO_MERGE */禁止视图合并,目的是防止无关联的表进行关联,而引起低效的笛卡尔积。

关于 NO_MERGE 的案例,大家也可以参考杨老师很早以前写过的一个博文:

2. 主表 TBPT 的 remote_url 字段增加索引,目的是增加嵌套循环被驱动表的扫描速度(也可以建立 remote_url + entd_type 的组合索引,这样在 CBO 模式下,很可能选择快速索引扫描替代全表扫描,执行代价会更低)。

CREATE INDEX INDEX_TBPT_URL ON TBPT(REMOTE_URL);

SELECT/*+ GATHER_PLAN_STATISTICS */

COUNT(Z.REMOTE_URL)

FROM TBPT Z,

(SELECT/*+ NO_MERGE*/H.H1H2H3

FROM H1H2H3 H, HDB D, CCOD_PROV_INFO P, CC_CITY_INFO C

WHERE H.AREA_CODE = C.CITY_ID

AND C.PROV_ID = P.PROV_ID

AND P.PROV_ID = 1

AND H.H1H2H3 LIKE D.HD || '%'

AND D.ID = '1') M

WHERE (Z.END_TYPE = 255 OR Z.END_TYPE = 254)

AND Z.REMOTE_URL LIKE 'TEL:' || M.H1H2H3 || '%';

优化后执行计划:

在这里可以看到 ID=4 的 View 关键字,说明我们已成功禁止视图的合并,让内联视图作为一个单独的整体查询后再进行和其他表的关联查询。

ID=13 的索引扫描也极大减少了 NestLoop 的成本

测试时间:1.45s

禁用视图合并 + 索引的优化效果:

40条数据 20s   –>   1800 万条数据1.45s

优化点结论:

由于 CBO 的算法缺陷或统计信息的不完整,并非所有的查询改写都是优化,有可能有些不必要的视图合并,引起了更严重的性能问题。

嵌套循环的被驱动表中如果有索引将会大大提高扫描、关联的效率。

陈顼oracle,一次视图合并引起的性能问题相关推荐

  1. Oracle 12CR2查询转换之视图合并

    这里的测试数据库版本为12.2.0.1,在视图合并中,优化器代表视图的查询块到包含视国的查询块中.视图合并通过让优化器考虑额外的连接顺序,访问方法与其它转换来提高性能.例如,在一个视图被合并后并且在一 ...

  2. oracle 组合视图,查询转换之视图合并

    视图合并常常发生在当外部查询块的谓语出现下列项的时候 能够在另一个查询块的索引中使用的列 能够在另一个查询块的分区截断中使用的列 在一个连接视图中能够返回限制行数 SQL> set autotr ...

  3. oracle 条件动态视图,oracle最重要的9个动态性能视图

    oracle最重要的9个动态性能视图 v$session v$session_wait (在10g里功能被整合,凑合算1个吧.) v$process v$sql v$sqltext v$bh (更宁愿 ...

  4. Oracle之物化视图

    近期根据项目业务需要对oracle的物化视图有所接触,在网上搜寻关于这方面的资料,便于提高,整理内容如下: 物化视图是一种特殊的物理表,"物化"(Materialized)视图是相 ...

  5. oracle v$system_event,45.Oracle杂记——Oracle常用动态视图v$system_event

    45.Oracle杂记--Oracle常用动态视图v$system_event 视图v$system_event 显示一个事件的总共等待. 如果不支持计时机制,那么TIME_WAITED和AVERAG ...

  6. oracle中的视图详解

    1.视图的概述 视图其实就是一条查询sql语句,用于显示一个或多个表或其他视图中的相关数据.视图将一个查询的结果作为一个表来使用,因此视图可以被看作是存储的查询或一个虚拟表.视图来源于表,所有对视图数 ...

  7. 创建数据库_详解Oracle数据库物化视图及创建物化视图索引

    概述 物化视图是一种特殊的物理表,"物化"(Materialized)视图是相对普通视图而言的.普通视图是虚拟表,应用的局限性大,任何对视图的查询,Oracle都实际上转换为视图S ...

  8. Oracle多行记录合并/连接/聚合字符串的几种方法

    Oracle多行记录合并/连接/聚合字符串的几种方法 怎么合并多行记录的字符串,一直是oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结.   ...

  9. oracle12c视图刷新,Oracle可更新视图

    在本教程中,您将学习Oracle可更新视图以及如何通过视图在基表中插入或更新数据. 视图就像一个表,因为可以像表一样从中查询数据.但是,不能总是通过视图来操作数据.如果针对视图的语句可以被转换成针对基 ...

  10. oracle v$context,30.Oracle杂记——Oracle常用动态视图v$session

    30.Oracle杂记--Oracle常用动态视图v$session 视图v$session:有关会话的信息 这个视图包含了超级多的列,说明其包含巨大的信息,小伙伴千万要记得使用,不然浪费掉了ORAC ...

最新文章

  1. 华科发布报告:41%研究生学霸是单身!
  2. linux svn 命令
  3. 华为1999元起的智能眼镜,能通话能播放音乐,预售就抢疯了!
  4. cisco2950 查看端口流量
  5. Marlin 溫度感應器 數值轉換對應表
  6. 华为马海旭:+智能,IoT行业云服务使能产业物联网
  7. udhcpc 后台运行的方法
  8. UDP中sendto()和recvfrom()两个函数的使用
  9. 电脑计算机的快捷键是什么,电脑保存的快捷键是什么-电脑知识
  10. Mysql优化碎片空间
  11. 好汉歌计算机音乐,好汉歌歌曲赏析
  12. Attention Mechanisms in Computer Vision: A Survey(四)
  13. java项目-第34期基于SpringBoot实现的中小医院HIS管理系统【毕业设计】
  14. zcash mining
  15. 头皮发麻之win10宽带拨号错误797
  16. glade java_Gtk+/Glade编程(一)--简介
  17. PMP笔记:解析质量管理的8项基本原则
  18. 开漏(open drain)和开集(open colletor)
  19. Leonard代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II。
  20. 请实现一个算法,确定一个字符串的所有字符是否全都不同。这里我们要求不允许使用额外的存储结构。 给定一个string iniString,请返回一个bool值,True代表所有字符全都不同,False代

热门文章

  1. 【GAN】生成式对抗网络论文笔记及TF2代码实现
  2. IT人物TOP100英雄人物榜
  3. “被授权”泛滥 个人信息保护怎么管?
  4. 计算机CPU四大体系架构
  5. 聊聊这个倾注10年的开源CRM项目,如何一步步火爆GitHub!
  6. android 置灰不可点击,android 按钮置灰效果
  7. Android Studio插件GsonFormat快速实现JavaBean
  8. android+设置运行内存大小,怎样增大安卓手机的虚拟运行内存RAM ,手机的ram太小....
  9. Hive数据分析案例
  10. 10年后的GOOGLE会怎么样