使用Listagg分析函式優化wmsys.wm_concat
with temp as
(select sgd.detail_id id,
wmsys.wm_concat(distinct(sg.gp_name)) groupnames,
wmsys.wm_concat(distinct(su.user_name)) usernames
from sgd
left join sg
on sg.id = sgd.gp_id
left join sug
on sg.id = sug.gp_id
left join su
on sug.user_id = su.id
group by sgd.detail_id)
select zh.id,
zh.id detailid,
zh.name detailname,
zh.p_level hospitallevel,
zh.type hospitaltype,
dza.name region,
temp.groupnames,
temp.usernames,
(case
when gd.gp_id is null then
0
else
1
end) isalloted
from zh
left join dza
on zh.area_id = dza.id
left join temp
on zh.id = temp.id
left join (select gp_id, detail_id from sys_gp_detail where gp_Id = :0) gd
on zh.id = gd.detail_id order by length(id),zh.id asc
該SQL返回20779行資料,要跑4分32秒。
該執行計劃中全是HASH JOIN,我就不貼了。
大家看我分析思路:
1. 首先這SQL最終返回20779行資料,該SQL語句最後部分沒有GROUP BY,僅僅是表關聯,並且是外連線
2. 那麼我可以判定zh也就差不多20779行資料,因為它是外連線的主表
3. 我也可以判定整個SQL裡面的表都不大,因為最終只返回20779行資料,並且沒有最終是沒有GROUP BY
4. 問題來了,既然都是小表,那為啥跑4分32秒?
遇到這種奇怪問題,我喜歡把SQL拆了。並且喜歡拆子查詢部分。所以你懂的
我們需要單獨跑with as裡面的SQL語句,跑了一下,發現居然要跑1--2分鐘
with as 的子查詢我們單獨拿出來看看
select sgd.detail_id id,
wmsys.wm_concat(distinct(sg.gp_name)) groupnames,
wmsys.wm_concat(distinct(su.user_name)) usernames
from sgd
left join sg
on sg.id = sgd.gp_id
left join sug
on sg.id = sug.gp_id
left join su
on sug.user_id = su.id
group by sgd.detail_id
這個子查詢裡面就多了2個列轉行函式wmsys.wm_concat
把它給註釋掉單獨跑一下列,發現SQL秒殺了
現在基本上定位問題所在,就是這個wmsys.wm_concat列轉行函式引起的效能問題
於是我將上面SQL進行了部分拆分
select sgd.detail_id id, wmsys.wm_concat(distinct(sg.gp_name)) groupnames
from sys_gp_detail sgd
left join sys_gp sg on sg.id = sgd.gp_id
group by sgd.detail_id
已用時間: 00: 00: 58.04
執行計劃
----------------------------------------------------------
Plan hash value: 3491823204
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20584 | 824K| | 1308 (8)| 00:00:06 |
| 1 | SORT GROUP BY | | 20584 | 824K| 15M| 1308 (8)| 00:00:06 |
|* 2 | HASH JOIN RIGHT OUTER| | 313K| 12M| | 449 (6)| 00:00:02 |
| 3 | TABLE ACCESS FULL | SYS_GP | 3 | 69 | | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | SYS_GP_DETAIL | 313K| 5518K| | 438 (5)| 00:00:02 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SG"."ID"(+)="SGD"."GP_ID")
統計資訊
----------------------------------------------------------
1 recursive calls
249348 db block gets
44447 consistent gets
0 physical reads
0 redo size
9993548 bytes sent via SQL*Net to client
6067828 bytes received via SQL*Net from client
83118 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
請注意,select語句居然產生了 db block gets。db block gets一般情況下只有DML語句才會產生
select語句中除了延遲塊清除,或者有with as 產生的臨時表之外,實在想不通哪裡還能產生 db block gets
那麼這個SQL跑得慢就是慢在db block gets,相信大家對這塊沒有異議
要想成為所謂的技術大牛,必須通讀官方文件。不管你是搞Oracle,Mysql,Hadoop,Java....等等,都必須通讀官方文件
Oracle11g/Oracle10.2.0.5之後,wmsys.wm_concat 返回的是Clob,之前返回的是Varchar2
這就是為什麼會產生大量的db block gets,知道了這個原因,立即將這個SQL進行等價改寫,使用Listagg分析函式代替wmsys.wm_concat
wmsys.wm_concat 函式是可以支援 distinct 的,但是listagg分析函式是不支援 distinct的,所以改寫SQL的時候,需要先去重,再進行列轉行
select detail_id, listagg(gp_name, ',') within
group(
order by null)
from (select sgd.detail_id, sg.gp_name
from sys_gp_detail sgd
left join sys_gp sg on sg.id = sgd.gp_id
group by sgd.detail_id, sg.gp_name)
group by detail_id;
已用時間: 00: 00: 01.12
執行計劃
----------------------------------------------------------
Plan hash value: 147456425
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20584 | 1547K| | 1467 (7)| 00:00:07 |
| 1 | SORT GROUP BY | | 20584 | 1547K| | 1467 (7)| 00:00:07 |
| 2 | VIEW | VM_NWVW_0 | 43666 | 3283K| | 1467 (7)| 00:00:07 |
| 3 | HASH GROUP BY | | 43666 | 1748K| 15M| 1467 (7)| 00:00:07 |
|* 4 | HASH JOIN RIGHT OUTER| | 313K| 12M| | 449 (6)| 00:00:02 |
| 5 | TABLE ACCESS FULL | SYS_GP | 3 | 69 | | 3 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | SYS_GP_DETAIL | 313K| 5518K| | 438 (5)| 00:00:02 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SG"."ID"(+)="SGD"."GP_ID")
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
2775 consistent gets
0 physical reads
0 redo size
450516 bytes sent via SQL*Net to client
15595 bytes received via SQL*Net from client
1387 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
20779 rows processed
可以看到,SQL等價改寫之後,可以秒殺,之前需要58秒。改寫完了一個 wmsys.wm_concat ,還有另外一個 wmsys.wm_concat 需要改寫。思路一樣
select detail_id, listagg(user_name, ',') within
group(
order by null)
from (select sgd.detail_id id, su.user_name
from sgd
left join sg on sg.id = sgd.gp_id
left join sug on sg.id = sug.gp_id
left join su on sug.user_id = su.id
group by sgd.detail_id, su.user_name)
group by detail_id;
最終將改寫好的2個結果集合並,得到等價的with as 語句,再替換原始SQL的with as語句,就可以秒殺了。
等價的with as 語句如下:
select a.detail_id id , a.groupnames, b.usernames
from (select detail_id, listagg(gp_name, ',') within
group(
order by null) groupnames
from (select sgd.detail_id, sg.gp_name
from sys_gp_detail sgd
left join sys_gp sg on sg.id = sgd.gp_id
group by sgd.detail_id, sg.gp_name)
group by detail_id) a,
(select detail_id, listagg(user_name, ',') within
group(
order by null) usernames
from (select sgd.detail_id, su.user_name
from sgd
left join sg on sg.id = sgd.gp_id
left join sug on sg.id = sug.gp_id
left join su on sug.user_id = su.id
group by sgd.detail_id, su.user_name)
group by detail_id) b
where a.. detail_id = b.detail_id;
結語: 道森學院 建議各位開發人員以後在開發過程中,儘量使用listagg函式代替wmsys.wm_concat
相關推薦
使用Listagg分析函式優化wmsys.wm_concat
在上週末優化班的時候一個朋友拿了一個SQL出來,讓我現場優化,因為當時太忙,我安排七年老師幫忙處理。跑得慢的SQL如下:with temp as (select sgd.detail_id id,
oracle連線字串函式,wmsys.wm_concat和LISTAGG
一、簡單介紹 最近專案需要進行行轉列,經過上網查資料發現了wmsys.wm_concat和LISTAGG函式,在這分享給大家 wmsys.wm_concat是oracle 10g推出的,用來連線字串,LISTAGG是oracle 11g推出的,它的作用和wmsys.wm_
with as +分析函式優化自連結
select para_id from dwf.f_Savc_Buscode b where b.Para_Id = (SELECT MIN(Para_Id) FROM Dwf.f_Savc_Buscode
oracle wmsys.wm_concat函式的用法
今天才發現了wmsys.wm_concat這個有趣有用的函式,它的作用是以’,’連結字元。 例子如下: SQL> create table idtable (id number,name varchar2(30)); Table created S
oracle聚合函式wmsys.wm_concat超長問題記錄
原文連結:https://blog.csdn.net/zym1550974736/article/details/69400400 今天在專案中執行sql時遇到一個問題,執行 select wmsys.wm_concat(p_codes) codes from t_rel where id=
分組連線欄位函式WMSYS.WM_CONCAT的使用
一、語法 WMSYS.WM_CONCAT(要連線的欄位) 該函式返回來自同一個分組的指定欄位的非NULL值的連線起來字串 二、用法 準備資料如下: 1、以c
oracle行轉列函式WMSYS.WM_CONCAT用法
select t.rank, t.Name from t_menu_item t; 10 CLARK 10 KING 10 MILLER 20 ADAMS 20 FORD 20 JONES 20 SCOTT 20 SMITH 30 ALLEN 30 BLAKE 30 JAMES 30 MARTIN 30 T
關於redis性能問題分析和優化
replica latency fragment 帶寬 more 日誌文件 隨機 2.6 one 一、如何查看Redis性能 info命令輸出的數據可分為10個分類,分別是: server,clients,memory,persistence,stats,repli
使用BatteryHistorian分析和優化應用電量
art man protobuf 工具 tail 數據請求 number 能夠 htm 歡迎Follow我的GitHub, 關註我的CSDN. 在Android項目中, 較難監控應用的電量消耗, 可是用戶卻很關心手機的待機時間. 過度耗電的應用
ExoPlayer Talk 01 緩存策略分析與優化
sca google mes efi allocator method policy 類型 let 操作系統:Windows8.1 顯卡:Nivida GTX965M 開發工具:Android studio 2.3.3 | ExoPlayer r2.5.1 使用 ExoP
PostgreSQL CPU滿(100%)性能分析及優化(轉)
mark ike -- 過多 mar 是不是 影響 sas sql日誌 PostgreSQL CPU滿(100%)性能分析及優化 轉自:https://help.aliyun.com/knowledge_detail/43562.html 在數據庫運維當中,
總結:windows下性能分析以及優化報告
快的 size 輸出結果 -s bsp 實現 替代 部分 個性 性能分析以及優化 使用的是vs2017自帶的性能分析工具。 主要分析了遇到的性能瓶頸,以及想到的優化方法,有的驗證了,有的沒有來得及。 首先看整體用時以及cpu占有率。 最終
MySQL瓶頸分析與優化
MySQL 優化 簡介通過sysbench的oltp_read_write測試來模擬業務壓力、以此來給指定的硬件環境配置一份比較合理的MySQL配置文件。環境介紹硬件配置軟件環境優化層級與指導思想優化層級MySQL數據庫優化可以在多個不同的層級進行,常見的有:SQL優化參數優化 架構優化本文重點關註:
mysql性能優化-慢查詢分析、優化索引和配置【轉】
簡單的 ssi any 通過命令 字型 reat created 效果 tle 一、優化概述 二、查詢與索引優化分析 1性能瓶頸定位 Show命令 慢查詢日誌 explain分析查詢 profiling分析查詢 2索引及查詢優化 三、配置優化 1) max_c
MySQL服務器 IO 100%的分析與優化方案
文件 %u mysq 希望 影響 前言 文章 興趣 排查 前言 壓力測試過程中,如果因為資源使用瓶頸等問題引發最直接性能問題是業務交易響應時間偏大,TPS逐漸降低等。而問題定位分析通常情況下,最優先排查的是監控服務器資源利用率,例如先用TOP 或者nmon等查看CPU、內存
如何協助 MySQL 實現 Oracle 高階分析函式
Oracle 支援一些獨特的語法和函式,在移植到 MySQL 上時或多或少給程式設計師造成了困擾,下面我們針對 Oracle 的一些特殊用法舉例並講解如何用集算器來完成同樣功能。這些方法當然也不限於針對 MySQL,對於所有其它資料庫也能支援。 1、 &
Mysql 多表聯合查詢效率分析及優化
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
oracle 之分析函式 over (partition by ...order by ...)
一:分析函式overOracle從8.1.6開始提供分析函式,分析函式用於計算基於組的某種聚合值,它和聚合函式的不同之處是對於每個組返回多行,而聚合函式對於每個組只返回一行。 1、分析函式和聚合函式的不同之處: 分析函式和聚合函式很多是同名的,意思也一樣,只是聚合函式用group by分組,每個分組返回一
R語言 迴歸分析函式說明
迴歸分析相關的函式 1、一元線性迴歸 lm() #計算beta0,beta1引數 summary() # 提取lm()引數資訊 anovn() #方差分析 predict() # 根據給出自變數預測因變數的值 例: a=lm(y~1+x,data=…) #對x,y
Hive(12):Hive分析函式
一、實現功能 對於分組之後的資料進行處理。 官網:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+WindowingAndAnalytics 二、例項 1.測試表 emp.empno em