相差數十倍的SQL效能分析(r11筆記第98天)
今天處理開發同學提交的一個資料查詢需求,看起來是一個很常規的SQL,但是有一點不同的是,他們提供了兩份檔案,一份是一個id列表,大概有3000多個id值,另外一個份是個SQL檔案。
之前也處理過幾十萬,上百萬id值的情況,使得我原來開發中對於變動的敏感性依舊存在,所以我採用了另外一種靈活的方式,即外部表,外部表是資料庫外的資料存在,在資料庫依舊可以讀取訪問。
CREATE TABLE test_cn
(cn varchar2(50)
)
ORGANIZATION EXTERNAL
(TYPE ORACLE_LOADER
DEFAULT DIRECTORY ext_dir
ACCESS PARAMETERS
(
RECORDS DELIMITED BY NEWLINE
)
LOCATION ('data.txt')
); 而在這個基礎上執行的SQL語句也很簡短。
select uin,regDate,regIP,cert_number from accstat.test_certification_info where uin in(select cn from test.test_cn ) ; 這樣一來就達到了一種一勞永逸的效果,那就是後期如果開發同學繼續提供另外一個查詢,只要提供了id值,不管是多大,我都能輕鬆處理,不管是哪個業務的SQL我都能靈活套用。
但是問題來了,上面的SQL語句執行的時候,速度讓我很不滿意,因為持續了近2分鐘。
select uin,regDate,regIP,cert_number from accstat.test_certification_info where uin in(select cn from test.test_cn ) ;
Elapsed: 00:01:59.39為什麼很不滿意,是因為這個“表”中的主鍵是基於欄位uin的,竟然查詢速度這麼慢,實在不給面子。
INDEX_NAME COLUMN_NAME INDEX_TYPE UNIQUENES
------------------------------ ------------ ---------------------
PK_USER_CERTIFICATION_INFO1 UIN NORMAL UNIQUE對於這類問題我還是有不小的興趣,畢竟能夠順手最佳化最佳化也是不錯的體驗。我嘗試加了rownum,儘管這樣不夠嚴謹,但是輸出結果和時間還是和開始的差不多。
select uin,regDate,regIP,cert_number from
accstat.test_certification_info where uin in(select cn from test.test_cn
) and rownum<=4000 ;
Elapsed: 00:01:59.15可見Oracle最佳化器早就看穿了我的心思,我怎麼能夠耍點小聰明呢。
select uin,regDate,regIP,cert_number from accstat.test_certification_info where uin in(select cn from test.test_cn where rownum<=3200) ;
Elapsed: 00:00:00.29這樣一個查詢就能夠達到非一般的速度。
這是為什麼呢。要想得到一些更為細緻的問題,那我們就開啟trace來診斷一下,怎麼診斷呢,一種比較自然的思路那就是10053事件。
10053事件診斷SQL
開啟10053事件的步驟如下:
ALTER SESSION SET EVENTS='10053 trace name context forever, level 1';
explain
plan for select uin,regDate,regIP,cert_number from
accstat.test_certification_info where uin in(select cn from
test.test_cn ) ;
ALTER SESSION SET EVENTS '10053 trace name context off';其中能夠看到不少細節的資訊,我摘取出一小段來。
FPD: Considering simple filter push (pre rewrite) in query block SEL$1 (#0)
FPD: Current where clause predicates "TEST_CERTIFICATION_INFO"."UIN"=ANY (SELECT "TEST_CN"."CN" FROM "TEST"."TEST_CN" "TEST_CN")
try to generate transitive predicate from check constraints for query block SEL$1 (#0)
finally: "TEST_CERTIFICATION_INFO"."UIN"=ANY (SELECT "TEST_CN"."CN" FROM "TEST"."TEST_CN" "TEST_CN")
最後經過查詢轉換,得到的最終語句如下:
Final query after transformations:******* UNPARSED QUERY IS *******
SELECT
"TEST_CERTIFICATION_INFO"."UIN" "UIN",..... FROM "TEST"."TEST_CN"
"TEST_CN", ( (SELECT "ACC00_TEST_CERTIFICATION_INFO"."UIN" ...
"ACC35_TEST_CERTIFICATION_INFO")) "TEST_CERTIFICATION_INFO" WHERE
"TEST_CERTIFICATION_INFO"."UIN"=TO_NUMBER("TEST_CN"."CN")
kkoqbc: optimizing query block SEL$2 (#14) 可能看到這裡就有些懵了,這個test_certification_info其實是個檢視,裡面包含有12個物化檢視。其實這個簡單的查詢就好比是12個物化檢視和一個外部表的關聯查詢。
那麼為什麼子查詢使用了rownum之後,效率大大提升呢。這個可以從日誌中看出端倪,我們可以清楚的看到最佳化器預估的時候這個外部表的資料條數是179950,和現在的3000多條想去甚遠。
Table Stats::
Table: TEST_CN Alias: TEST_CN
#Rows: 179950 #Blks: 462 AvgRowLen: 21.00 ChainCnt: 0.00
Access path analysis for TEST_CN那麼為什麼最佳化器認為是179950條資料呢,這個和統計資訊還是密切相關,儘管外部表不佔用資料檔案的儲存,但是依然還是有一個基本的統計資訊。
SQL> select num_rows from dba_tables where table_name='TEST_CN';
NUM_ROWS
----------
179950可能有很多同學說,那就收集統計資訊,應該能夠解決這個問題。SQL> exec dbms_stats.gather_table_stats(ownname=>'TEST',TABNAME=>'TEST_CN');
PL/SQL procedure successfully completed. 然後再次嘗試,竟然還是很慢,檢視執行計劃發現裡面始終是走了全表掃描。
這個問題的一種快速解決方式就是使用子查詢中的rownum來限定,如果查詢的資料缺失夠多,走全表也不失為一種合理的方法。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-2135033/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 複雜SQL效能優化的剖析(一)(r11筆記第36天)SQL優化筆記
- 複雜SQL效能優化的剖析(二)(r11筆記第37天)SQL優化筆記
- 百倍效能的PL/SQL優化案例(r11筆記第13天)SQL優化筆記
- 一個SQL效能問題的優化探索(二)(r11筆記第38天)SQL優化筆記
- 閃回區報警引發的效能問題分析(r11筆記第11天)筆記
- 返京途中(r11筆記第61天)筆記
- MySQL引數對比淺析(r11筆記第97天)MySql筆記
- insert導致的效能問題大排查(r11筆記第26天)筆記
- 我的女兒二三事(r11筆記第87天)筆記
- 需要了解的pssh(r11筆記第28天)筆記
- 我眼中的寶雞景點(r11筆記第53天)筆記
- 我眼中的兵馬俑(r11筆記第55天)筆記
- MySQL中的undo截斷(r11筆記第89天)MySql筆記
- 使用shell自動化診斷效能問題(一)(r11筆記第41天)筆記
- MySQL中的半同步複製(r11筆記第65天)MySql筆記
- 出去吃頓飯容易嘛(r11筆記第5天)筆記
- 閃回原理測試(二)(r11筆記第23天)筆記
- MySQL 5.7 General Tablespace學習(r11筆記第34天)MySql筆記
- 德魯克人生五問(r11筆記第71天)筆記
- 關於責任和業務(r11筆記第60天)筆記
- MySQL Online DDL(二)(r11筆記第88天)MySql筆記
- 兩個資料庫的問題(r11筆記第4天)資料庫筆記
- 三十而立,立的是什麼?(r11筆記第70天)筆記
- MySQL中insert語句沒有響應的問題分析(r11筆記第21天)MySql筆記
- 使用SQL來分析資料庫引數(一)(r10筆記第68天)SQL資料庫筆記
- Java隨機演算法(一)(r11筆記第14天)Java隨機演算法筆記
- 寫在2016年底(r11筆記第30天)筆記
- 近期的學習計劃(2017.3)(r11筆記第95天)筆記
- Data Guard故障自動切換的想法(r11筆記第40天)筆記
- Oracle Data Guard延遲的幾個可能(r11筆記第69天)Oracle筆記
- 動態建立MySQL Group Replication的節點(r11筆記第84天)MySql筆記
- Oracle 12cR2初體驗(r11筆記第91天)Oracle筆記
- 軟體技術大會歸來(r11筆記第8天)筆記
- 使用sysbench壓力測試MySQL(一)(r11筆記第3天)MySql筆記
- 關於ssh命令的幾個使用小技巧(r11筆記第27天)筆記
- SQL Server效能分析引數 (轉)SQLServer
- 物化檢視實現的特殊資料複製(r11筆記第42天)筆記
- Oracle 12c資料字典的小問題(r11筆記第49天)Oracle筆記