优化案例5:视图目标列改写优化

优化案例5:视图目标列改写优化

  • 1. 问题描述
  • 2. 分析过程
    • 2.1 目标SQL
    • 2.2 解决思路
      • 1)效率低的执行计划
      • 2)视图过滤性
      • 3)查看已有索引定义
    • 2.3 视图改写
    • 2.4 增添复合索引
  • 3. 优化总结

DM技术交流QQ群:940124259

1. 问题描述

视图改写优化单独拿出一例分享,未做hint优化,简单地改写视图列和增加一个索引就能搞定。
这条SQL本身很简单,被广州同事使出三板斧(统计信息、索引、ET耗时、HINT、清理执行计划),招式使尽,却没去留意视图定义本身内容的特点,利用视图的谓词下推的策略,就能达到优化目的。

截图为同事部分一堆骚操作:
在这里插入图片描述


2. 分析过程

2.1 目标SQL

-- 原始SQL代码
SELECT * FROM (SELECT A., ROWNUM R FROM(SELECT COUNT(1) OVER () RECORDCOUNT, M. from DISPLAYCENTER.WL_DDBB_WEEK_V mwhere m.bbid='BB-DD-002' and bbrq='20221014'and hzb=45 and lzb=6 ) A where rownum <=1000)b where r>0; -- telphoning   --4ms
-- 视图原始定义WL_DDBB_WEEK_V
CREATE OR REPLACE VIEW WL_DDBB_WEEK_V AS
SELECT t1.bbzd_id bbid, '' bbmc,
SUBSTR (t1.bbzd_date, 1, 4)  || SUBSTR (t1.bbzd_date, 7, 2)  || SUBSTR (t1.bbzd_date, 9, 2) AS bbrq,
t1.hzd_nm hzb, t1.lzd_nm lzb, dyzd_sj as VALUE
FROM (SELECT
T1.*
FROM RAW_SMES.Bb_Dwsj_Tb T1) t1  ;

2.2 解决思路

1)效率低的执行计划


/*
--  predicate condition
1   #NSET2: [6597, 1, 912]
2     #PRJT2: [6597, 1, 912]; exp_num(8), is_atom(FALSE)
3       #SLCT2: [6597, 1, 912]; B.R > var2
4         #PRJT2: [6597, 1, 912]; exp_num(8), is_atom(FALSE)
5           #RN: [6597, 1, 912]
6             #PRJT2: [6597, 1, 912]; exp_num(7), is_atom(FALSE)
7               #TOPN2: [6597, 1, 912]; top_num(exp11)
8                 #AFUN: [6597, 1, 912]; afun_num(1); partition_num(0); order_num(0)
9                   #PRJT2: [6597, 34, 912]; exp_num(6), is_atom(FALSE)
10                    #SLCT2: [6597, 34, 912]; (exp_cast(T1.HZD_NM) = 45 AND exp_cast(T1.LZD_NM) = 6 AND exp11 || exp11 || exp11 = '20221014')
11                      #BLKUP2: [6597, 2754812, 912]; IDX_BB_DWSJ(T1)
12                        #SSEK2: [6597, 2754812, 912]; scan_type(ASC), IDX_BB_DWSJ(BB_DWSJ_TB as T1), scan_range[('BB-DD-002',min,min,min),('BB-DD-002',max,max,max))
*/

从执行计划步骤12 SSEK2和步骤10 SLCT2操作符的附加信息可以看出视图的过滤条件被下放。 但回表大严重(2754812行),由此可以推断这表很大,然而看着应用复合索引,只能命中一个字段定位,二次回表再过滤,不慢才怪。 所以影响此SQL的罪魁祸首是回表200+W的数据,造成大量的逻辑读和磁盘读。

2)视图过滤性

select count(*) from DISPLAYCENTER.WL_DDBB_WEEK_V ; -- 110 265 448   1亿1千万的数据行
select count(*) from DISPLAYCENTER.WL_DDBB_WEEK_V m where m.bbid='BB-DD-002' and m.bbrq='20221014'; -- 816  过滤性极强 
select count(*) from  DISPLAYCENTER.WL_DDBB_WEEK_V m where m.bbid='BB-DD-002' and hzb=45 and lzb=6 and bbrq='20221014'; -- 1

视图里面只有一个基表且数据量庞大,bbid和bbrq组合条件过滤性很强,对它们建个索引效果更好。

3)查看已有索引定义

/*
-- 表定义
CREATE TABLE "RAW_SMES"."BB_DWSJ_TB"
(
"QYZD_BH" VARCHAR2(40),
"DWZD_BH" VARCHAR2(30),
"BBZD_ID" VARCHAR2(20),
"BBZD_DATE" VARCHAR2(10),
"BBZD_YEAR" VARCHAR2(10),
"BBZD_MON" VARCHAR2(10),
"BBZD_DAY" VARCHAR2(10),
"BBZD_QUA" VARCHAR2(10),
"BBZD_TENDAY" VARCHAR2(10),
"BBZD_WEEK" VARCHAR2(10),
"HZD_ZB" NUMBER,
"LZD_ZB" NUMBER,
"H_BZBM" VARCHAR2(30),
"L_BZBM" VARCHAR2(30),
"DYZD_SJ" VARCHAR2(500),
"DYZD_DATA" NUMBER(20,6),
"XSSX" NUMBER,
"HZD_NM" VARCHAR2(50),
"LZD_NM" VARCHAR2(50),
"INSERT_ODS_TIME" TIMESTAMP(0),
"UPDATE_ODS_TIME" TIMESTAMP(0),
"M_ROW$$" VARCHAR2(128)) STORAGE(ON "RAW_SCGK", CLUSTERBTR) ;-- 索引定义 
CREATE UNIQUE  INDEX "UK_M_ROW" ON "RAW_SMES"."BB_DWSJ_TB"("M_ROW$$" ASC) STORAGE(ON "RAW_SCGK", CLUSTERBTR) ;
CREATE  INDEX "IDX_BB_DWSJ" ON "RAW_SMES"."BB_DWSJ_TB"("BBZD_ID" ASC,"BBZD_DATE" ASC,"HZD_NM" ASC,"LZD_NM" ASC) STORAGE(ON "RAW_SCGK", CLUSTERBTR) ;
*/

看到索引定义("BBZD_ID" ASC,"BBZD_DATE" ASC,"HZD_NM" ASC,"LZD_NM" ASC) 时,知道他们离优化成功半步之遥,不懂BBZD_DATE字段被视图转换拼接, 已不再是原始字段,所以这个索引无法利用上第2个字段,则解释清楚1)所说的执行计划涉及的回表严重。

2.3 视图改写

原始视图的bbrq视图列定义SUBSTR (t1.bbzd_date, 1, 4) || SUBSTR (t1.bbzd_date, 7, 2) || SUBSTR (t1.bbzd_date, 9, 2) AS bbrq, 写得太复杂,无非就是从字符类型的bbzd_date截取出合法的日期格式数据,把一大趾函数转换简单化,变成stuff函数,减少复杂计算, 还能让后面建函数索引更简单方便。
-- redefination view reduce function cost
CREATE OR REPLACE VIEW DISPLAYCENTER.WL_DDBB_WEEK_V
AS
SELECT
t1.bbzd_id bbid,
'' bbmc        ,
stuff(t1.bbzd_date, 5, 2, '')  AS bbrq,  -- 改写位置
t1.hzd_nm hzb                         ,
t1.lzd_nm lzb                         ,
dyzd_sj as VALUE
FROM
(
SELECT T1.* FROM RAW_SMES.Bb_Dwsj_Tb T1
)
t1 ;

2.4 增添复合索引

create index idx_comb_bbid_hzb_lzb on “RAW_SMES”.“BB_DWSJ_TB”(BBZD_ID, STUFF(bbzd_date, 5, 2, ‘’), HZD_NM,LZD_NM ) ONLINE;

将就原来他们建的索引IDX_BB_DWSJ的逻辑,把第2个字段替换成stuff函数。再来一探执行计划的变化,不出意外的话,将会充分利用上索引前两个字段的过滤性。

/* 执行时间:4毫秒
1   #NSET2: [163, 1, 912]
2     #PRJT2: [163, 1, 912]; exp_num(8), is_atom(FALSE)
3       #SLCT2: [163, 1, 912]; B.R > var2
4         #PRJT2: [163, 1, 912]; exp_num(8), is_atom(FALSE)
5           #RN: [163, 1, 912]
6             #PRJT2: [163, 1, 912]; exp_num(7), is_atom(FALSE)
7               #TOPN2: [163, 1, 912]; top_num(exp11)
8                 #AFUN: [163, 1, 912]; afun_num(1); partition_num(0); order_num(0)
9                   #PRJT2: [163, 68469, 912]; exp_num(6), is_atom(FALSE)
10                    #SLCT2: [163, 68469, 912]; (exp_cast(T1.HZD_NM) = 45 AND exp_cast(T1.LZD_NM) = 6)
11                      #BLKUP2: [163, 68469, 912]; IDX_COMB_BBID_HZB_LZB(T1)
12                        #SSEK2: [163, 68469, 912]; scan_type(ASC), IDX_COMB_BBID_HZB_LZB(BB_DWSJ_TB as T1), scan_range[('BB-DD-002','20221014',min,min),('BB-DD-002','20221014',max,max))
*/
执行计划BLKUP2 显示回表68469,索引统计信息未收集,收集一下就成。 总体来说,优化已经达到预期目标,4毫秒已经很nice。可能美中不足复合索引剩下两字段没用上,跑到SLCT2作回表过滤。 细心地会发现(exp_cast(T1.HZD_NM) = 45 AND exp_cast(T1.LZD_NM) = 6) 出现exp_cast数据库内部隐式转换,所以才漏掉。 喊他们把条件数字带上单引号【hzb='45' and lzb='6'】,避免类型转换,也就解决索引全列过滤。

3. 优化总结

懂得索引合理创建,不要乱建索引,复合索引的组合字段弄得太多不是好事,因为能利用上的索引键就一个或两个,完全没意义弄这么多索引键,潜在隐藏一个信息,索引体积太大,索引B+树庞大,可能引起大量的IO读写,影响索引扫描的效率。

一定要充分利用索引特性,够小(体积小,可以理解为表的瘦身版),够高效(过滤性强)。

明白视图的优化手段,无非包含视图上拉、视图合并等等优化思想。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/91535.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

『PyQt5-Qt Designer篇』| 06 Qt Designer中水平布局和垂直布局的使用

06 Qt Designer中水平布局和垂直布局的使用 1 水平布局1.1 按钮布局1.2 位置移动1.3 先布局再放按钮1.4 保存文件并调用2 垂直布局2.1 按钮布局2.2 保存并调用1 水平布局 1.1 按钮布局 拖动几个按钮: 选中这几个按钮,右键-布局-水平布局: 可以看到按钮间隔等宽水平排列: 也…

Linux线程控制

目录 一、线程的简单控制 1.多线程并行 2.线程结束 3.线程等待 &#xff08;1&#xff09;系统调用 &#xff08;2&#xff09;返回值 4.线程取消 5.线程分离 二、C多线程小组件 三、线程库TCB 1.tid 2.局部储存 一、线程的简单控制 1.多线程并行 我们之前学过pt…

使用openpyxl来创建一个月的日程表

首先你心里要有一张表的样子&#xff0c;openpyxl才能帮你创建出其余的29张。 import openpyxl from openpyxl.styles import Alignment, Font import calendar from datetime import datework_path rXX\YY\ZZ\日报-九月.xlsxtry:workbook openpyxl.load_workbook(work_path…

AttributeError: ‘ConfigDict‘ object has no attribute ‘log_level‘

运行 python tools/train.py configs/pspnet/pspnet_r50-d8_512x512_80k_ade20k.py 时出现 问题 Traceback (most recent call last):File "tools/train.py", line 242, in <module>main()File "tools/train.py", line 167, in mainlogger get_ro…

基于java swing和mysql实现的仓库商品管理系统(源码+数据库+运行指导视频)

一、项目简介 本项目是一套基于java swing和mysql实现的仓库商品管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经…

GPU编程(基于Python和CUDA)(二)——显示GPU信息

系列文章目录 GPU编程&#xff08;基于Python和CUDA&#xff09;&#xff08;一&#xff09;——零基础安装pycuda GPU编程&#xff08;基于Python和CUDA&#xff09;&#xff08;二&#xff09;——显示GPU信息 显示GPU信息 系列文章目录前言通过CUDA查看GPU信息使用pycuda查…

c++(8.28)菱形继承,虚继承,多态,抽象类,模板+Xmind

xmind: 作业&#xff1a; 1.编程题&#xff1a; 以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴…

web功能测试方法大全—完整!全面!(纯干货,建议收藏哦~)

本文通过六个部分为大家梳理了web功能测试过程中&#xff0c;容易出现的遗漏的部分&#xff0c;用以发掘自己工作中的疏漏。&#xff08;纯干货&#xff0c;建议收藏哦~&#xff09; 一、输入框 1、字符型输入框 2、数值型输入框 3、日期型输入框 4、信息重复 在一些需要命名…

vue v-for 例子

vue v-for 例子 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&…

React 使用 useRef() 获取循环中所有子组件实例

目录 背景思考实现完整代码&#xff1a;成功运行后的界面如下&#xff1a; 知识点总结uesRef() 作对象处理useImperativeHandle() 父组件操作引入子组件的内部方法最后 背景 之前项目中使用了antd pro 中的 可编辑表格 (EditableProTable)&#xff0c;在页面中表格要经过多层遍…

Java 多线程系列Ⅰ(创建线程+查看线程+Thread方法+线程状态)

多线程基础 一、创建线程的五种方法前置知识1、方法一&#xff1a;使用继承Thread类&#xff0c;重写run方法2、方法二&#xff1a;实现Runnable接口&#xff0c;重写run方法3、方法三&#xff1a;继承Thread&#xff0c;使用匿名内部类4、方法四&#xff1a;实现Runnable&…

C#---第21: partial修饰类的特性及应用

0.知识背景 局部类型适用于以下情况&#xff1a; 类型特别大&#xff0c;不宜放在一个文件中实现。一个类型中的一部分代码为自动化工具生成的代码&#xff0c;不宜与我们自己编写的代码混合在一起。需要多人合作编写一个类 局部类型的限制: 局部类型只适用于类、接口、结构&am…