生產系統調優之_敢於質疑
接著昨天的那個問題來說。有個sql語句在做了統計資訊收集之後,速度有了一定的提升,從5秒的響應降低到了2秒。但是和預期還是有一定
的差距,按照80條查詢請求在短時間內響應。2秒*80000次/60/60=44.4小時,本來感覺可以接受的一下子就成了大問題。
|
Elapsed Time (s) |
Executions |
Elapsed Time per Exec (s) |
%Total |
%CPU |
%IO |
SQL Id |
SQL Module |
SQL Text |
31st May |
305.44 |
145 |
2.11 |
25.56 |
99.69 |
0.26 |
gext1GenericEx@ccbdbpr1 (TNS V1-V3) |
/* */ SELECT DISTINCT 'K', AR.... |
和那個同事又確認了下,他說在其他專案也用的這個sql語句資料量還要大的多,就是沒有問題。
有了昨天的一些資料,我自己也基本心裡有數了,我表示懷疑,在此基礎上能做的就是仔細看看這個sql語句了,看看到底實現細節有沒有問題。
可以看到加入了一些hint,嵌入了子查詢。
SELECT DISTINCT 'K',
AR.RESOURCE_VALUE,
AR.RESOURCE_TYPE,
GREATEST(TO_CHAR(AR.EFFECTIVE_DATE, 'YYYYMMDDHH24MISS'),
TO_CHAR(SB.EFFECTIVE_DATE, 'YYYYMMDDHH24MISS')),
LEAST(NVL(TO_CHAR(AR.EXPIRATION_DATE, 'YYYYMMDDHH24MISS'),
'47001231000000'),
NVL(TO_CHAR(SB.EXPIRATION_DATE, 'YYYYMMDDHH24MISS'),
'47001231000000')),
AR.AGR_NO,
SB.MEDIUM_CUS_ID,
SB.SUB_STATUS,
SB.BUSINESS_ENTITY_ID,
SB.LANGUAGE,
SB.ROUTING_POLICY_ID,
SB.L9_PORT_IND,
SB.L9_SPLIT_PERIOD
FROM HUGE_RESOURCE AR, --這個表有大約2000多萬條資料,做了分割槽
MEDIUM_SUB SB, --這個表有50萬左右的資料
(select /*+ RESULT_CACHE */
DISTINCT PARAM_NAME as PARAM_NAME
from SMALL_PARAM --這個表比較小,有不到2萬條記錄,如果加過濾條件,能過濾掉一半多的資料,因為那個欄位不在索引欄位裡,所以加了result_cache
where GUIDING_IND = 'Y') OP,
MEDIUM_CUS CS
WHERE AR.AGR_NO = 1056851
AND AR.AGREEMENT_KEY = MOD(1056851, 100)
AND (AR.RESOURCE_STATE != 'F' OR AR.RESOURCE_STATE IS NULL)
AND AR.RANGE_IND = 'N'
AND SB.MEDIUM_SUB_NO = AR.AGR_NO
AND EXISTS
(select /*+ INDEX(OP SMALL_PARAM_1IX) */
1
from SMALL_PARAM OP
where OP.PARAM_NAME in (AR.RESOURCE_PRM_CD, AR.BASE_PARAM_NAME) )
AND SB.MEDIUM_CUS_ID = CS.MEDIUM_CUS_ID
AND (SB.EXPIRATION_DATE IS NULL OR SB.EXPIRATION_DATE >= to_date('19000101000000','YYYYMMDDHH24MISS'))
AND (AR.EXPIRATION_DATE IS NULL OR AR.EXPIRATION_DATE >= to_date('19000101000000','YYYYMMDDHH24MISS'))
AND (AR.EFFECTIVE_DATE < SB.EXPIRATION_DATE OR
SB.EXPIRATION_DATE IS NULL)
AND (AR.EXPIRATION_DATE IS NULL OR
AR.EXPIRATION_DATE > SB.EFFECTIVE_DATE)
AND SB.SUB_STATUS != 'T'
UNION ALL
SELECT DISTINCT 'K',
AR.RESOURCE_VALUE,
AR.RESOURCE_TYPE,
GREATEST(TO_CHAR(AR.EFFECTIVE_DATE, 'YYYYMMDDHH24MISS'),
TO_CHAR(SH.EFFECTIVE_DATE, 'YYYYMMDDHH24MISS')),
LEAST(NVL(TO_CHAR(AR.EXPIRATION_DATE, 'YYYYMMDDHH24MISS'),
'47001231000000'),
NVL(TO_CHAR(SH.EXPIRATION_DATE, 'YYYYMMDDHH24MISS'),
'47001231000000')),
AR.AGR_NO,
SH.MEDIUM_CUS_ID,
SH.SUB_STATUS,
SH.BUSINESS_ENTITY_ID,
SH.LANGUAGE,
SH.ROUTING_POLICY_ID,
SH.L9_PORT_IND,
SH.L9_SPLIT_PERIOD
FROM HUGE_RESOURCE AR,
MEDIUM_SUB_HISTORY SH,
(select /*+ RESULT_CACHE */
DISTINCT PARAM_NAME as PARAM_NAME
from SMALL_PARAM
where GUIDING_IND = 'Y') OP,
MEDIUM_CUS CS
WHERE AR.AGR_NO = 1056851
AND AR.AGREEMENT_KEY = MOD(1056851, 100)
AND (AR.RESOURCE_STATE != 'F' OR AR.RESOURCE_STATE IS NULL)
AND AR.RANGE_IND = 'N'
AND SH.MEDIUM_SUB_NO = AR.AGR_NO
AND EXISTS
(select /*+ INDEX(OP SMALL_PARAM_1IX) */
1
from SMALL_PARAM OP
where OP.PARAM_NAME in (AR.RESOURCE_PRM_CD, AR.BASE_PARAM_NAME))
AND SH.MEDIUM_CUS_ID = CS.MEDIUM_CUS_ID
AND (SH.EXPIRATION_DATE IS NULL OR SH.EXPIRATION_DATE >= to_date('19000101000000','YYYYMMDDHH24MISS'))
AND (AR.EXPIRATION_DATE IS NULL OR AR.EXPIRATION_DATE >= to_date('19000101000000','YYYYMMDDHH24MISS'))
AND (AR.EFFECTIVE_DATE < SH.EXPIRATION_DATE OR
SH.EXPIRATION_DATE IS NULL)
AND (AR.EXPIRATION_DATE IS NULL OR
AR.EXPIRATION_DATE > SH.EFFECTIVE_DATE)
AND SH.SUB_STATUS NOT IN ('C', 'T')
試著在生產上抓了一個執行計劃,又看了一下統計資訊。
Statistics
----------------------------------------------------------
113 recursive calls
8 db block gets
31581 consistent gets
0 physical reads
0 redo size
1997 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
20 sorts (memory)
0 sorts (disk)
6 rows processed
Elapsed: 00:02:44.14
---------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 13 | 2905 | 519 (59)| 00:00:07 | | |
在備份庫上檢視,結果同樣的查詢一下子沒有了反應。執行了將近3分鐘還是沒有反應。備份庫的資源要比生產差一些。好了感覺有問題了。開始看看這個sql語句的第一部分。
SELECT DISTINCT 'K',
AR.RESOURCE_VALUE,
AR.RESOURCE_TYPE,
GREATEST(TO_CHAR(AR.EFFECTIVE_DATE, 'YYYYMMDDHH24MISS'),
TO_CHAR(SB.EFFECTIVE_DATE, 'YYYYMMDDHH24MISS')),
LEAST(NVL(TO_CHAR(AR.EXPIRATION_DATE, 'YYYYMMDDHH24MISS'),
'47001231000000'),
NVL(TO_CHAR(SB.EXPIRATION_DATE, 'YYYYMMDDHH24MISS'),
'47001231000000')),
AR.AGR_NO,
SB.MEDIUM_CUS_ID,
SB.SUB_STATUS,
SB.BUSINESS_ENTITY_ID,
SB.LANGUAGE,
SB.ROUTING_POLICY_ID,
SB.L9_PORT_IND,
SB.L9_SPLIT_PERIOD
FROM HUGE_RESOURCE AR, --這個表有大約2000多萬條資料,做了分割槽
MEDIUM_SUB SB, --這個表有50萬左右的資料
(select /*+ RESULT_CACHE */
DISTINCT PARAM_NAME as PARAM_NAME
from SMALL_PARAM --這個表比較小,有不到2萬條記錄,如果加過濾條件,能過濾掉一半多的資料,因為那個欄位不在索引欄位裡,所以加了result_cache
where GUIDING_IND = 'Y') OP,
MEDIUM_CUS CS
WHERE AR.AGR_NO = 1056851
AND AR.AGREEMENT_KEY = MOD(1056851, 100)
AND (AR.RESOURCE_STATE != 'F' OR AR.RESOURCE_STATE IS NULL)
AND AR.RANGE_IND = 'N'
AND SB.MEDIUM_SUB_NO = AR.AGR_NO
AND EXISTS
(select /*+ INDEX(OP SMALL_PARAM_1IX) */
1
from SMALL_PARAM OP
where OP.PARAM_NAME in (AR.RESOURCE_PRM_CD, AR.BASE_PARAM_NAME) )
AND SB.MEDIUM_CUS_ID = CS.MEDIUM_CUS_ID
AND (SB.EXPIRATION_DATE IS NULL OR SB.EXPIRATION_DATE >= to_date('19000101000000','YYYYMMDDHH24MISS'))
AND (AR.EXPIRATION_DATE IS NULL OR AR.EXPIRATION_DATE >= to_date('19000101000000','YYYYMMDDHH24MISS'))
AND (AR.EFFECTIVE_DATE < SB.EXPIRATION_DATE OR
SB.EXPIRATION_DATE IS NULL)
AND (AR.EXPIRATION_DATE IS NULL OR
AR.EXPIRATION_DATE > SB.EFFECTIVE_DATE)
AND SB.SUB_STATUS != 'T'
因為結果集的輸出中沒有op這個表的列,而且在where子句中存在exists語句,在exists裡面也沒有做關聯,那個同事堅持說想在做關聯的時候把op的資料先做了result cache,在子查詢中就能做關聯了,避免重複的表掃描。聽起來好像有道理,我覺得語句有問題,儘管說是產品部分提供的方案。op在from 後,但是和後面的流程都沒有關聯,但也沒有做笛卡爾積。在他的強烈反對中我把以下的部分從from中刪除。
(select /*+ RESULT_CACHE */
DISTINCT PARAM_NAME as PARAM_NAME
from SMALL_PARAM --這個表比較小,有不到2萬條記錄,如果加過濾條件,能過濾掉一半多的資料,因為那個欄位不在索引欄位裡,所以加了result_cache
where GUIDING_IND = 'Y') OP,
然後在備份庫上重新跑一次,沒想到一下子就有了反應。存在一定的物理讀,第二次執行就沒有了。邏輯度有了近6倍的提升,執行時間在0.02-0.07之間。
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
5854 consistent gets
605 physical reads
72 redo size
1900 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4 rows processed
按照這個速度,0.07秒*80000次/60/60=1.55小時,剩下的事情就是和他們確認一些具體的細節了。下午晚些時候產品部分也確認這確實是個問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-1173785/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 生產系統調優之_毫秒級的改進
- 生產系統pl/sql調優案例SQL
- 生產sql調優之統計資訊分析SQL
- 對oracle metalink文件我們也要敢於質疑Oracle
- 服裝生產管理軟體鞋帽生產系統的優點
- 關於生產管理系統中的BOM!
- 關於生產系統鎖問題的排查
- Linux系統效能調優之效能分析Linux
- 生產經營管理之表帳單系統
- linux系統關於kernel.sem調優Linux
- CentOS 7.8作業系統安裝(用於生產)CentOS作業系統
- Linux優化之IO子系統監控與調優Linux優化
- Linux系統調優Linux
- 馬司系統調優
- 產品的生態系統
- 印度軟體開發優勢:成本、質量、生產力
- 【sql調優】系統資訊統計SQL
- 生產服務GC調優實踐基本流程總結GC
- (3)Linux效能調優之Linux檔案系統Linux
- Java生產環境效能監控與調優—基於JDK命令列工具的監控JavaJDK命令列
- 用彩色Uml做需求分析產生的疑問
- 杭州ERP生產管理系統開發的應用與優勢
- 探討基於資訊系統的專案型生產管理
- oracle優化之生產系統不改程式碼解決SQL效能問題的幾種方法Oracle優化SQL
- 同職位女員工薪酬高於男性?谷歌薪資調查受多方質疑谷歌
- APS高階計劃排程系統和生產排產系統
- 龍芯筆記本: 將投產龍芯筆記本採用Linux系統受質疑(轉)筆記Linux
- Linux系統調優介紹Linux
- Linux系統效能調優技巧Linux
- SMT生產管理系統(E-PMS)
- CentOS 7.8安裝PostgreSQL(生產系統)CentOSSQL
- 說說生產系統索引的重建索引
- 看板系統(精益生產)介紹...
- 生產環境sql語句調優實戰第二篇SQL
- 生產環境sql語句調優實戰第三篇SQL
- 生產環境sql語句調優實戰第四篇SQL
- 生產環境sql語句調優實戰第五篇SQL
- 生產環境sql語句調優實戰第六篇SQL