1. 程式人生 > >使用Listagg分析函式優化wmsys.wm_concat

使用Listagg分析函式優化wmsys.wm_concat

在上週末優化班的時候一個朋友拿了一個SQL出來,讓我現場優化,因為當時太忙,我安排七年老師幫忙處理。跑得慢的SQL如下:

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_concatLISTAGG

一、簡單介紹 最近專案需要進行行轉列,經過上網查資料發現了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