簡體   English   中英

如何解決Oracle SQL語句的性能問題

[英]How do I troubleshoot performance problems with an Oracle SQL statement

我有兩個插入語句,幾乎完全相同,它們在同一個Oracle實例上以兩個不同的模式運行。 insert語句看起來並不重要 - 我在這里尋找故障排除策略。

兩種模式都有99%相同的結構。 一些列的名稱略有不同,除了它們是相同的。 insert語句幾乎完全相同。 一個解釋計划的成本為6,另一個的解釋計划的成本為7.兩個插入語句集中涉及的表具有完全相同的索引。 已經為兩個模式收集了統計數據。

一個insert語句在5秒內插入12,000條記錄。

另一個insert語句在4分19秒內插入25,000條記錄。

插入的記錄數是正確的。 執行時間的巨大差異讓我感到困惑。 鑒於解釋計划中沒有任何突出的問題,您將如何確定導致運行時間差異的原因?

(我在Windows機器上使用Oracle 10.2.0.4)。

編輯:問題最終成為一個低效的查詢計划,涉及笛卡爾合並,不需要這樣做。 明智地使用索引提示和散列連接提示解決了這個問題。 現在需要10秒鍾。 Sql Trace / TKProf給了我方向,因為我向我展示了計划中每個步驟花了多少秒,以及生成了多少行。 因此TKPROF告訴我: -

Rows     Row Source Operation
-------  ---------------------------------------------------
  23690  NESTED LOOPS OUTER (cr=3310466 pr=17 pw=0 time=174881374 us)
  23690   NESTED LOOPS  (cr=3310464 pr=17 pw=0 time=174478629 us)
2160900    MERGE JOIN CARTESIAN (cr=102 pr=0 pw=0 time=6491451 us)
   1470     TABLE ACCESS BY INDEX ROWID TBL1 (cr=57 pr=0 pw=0 time=23978 us)
   8820      INDEX RANGE SCAN XIF5TBL1 (cr=16 pr=0 pw=0 time=8859 us)(object id 272041)
2160900     BUFFER SORT (cr=45 pr=0 pw=0 time=4334777 us)
   1470      TABLE ACCESS BY INDEX ROWID TBL1 (cr=45 pr=0 pw=0 time=2956 us)
   8820       INDEX RANGE SCAN XIF5TBL1 (cr=10 pr=0 pw=0 time=8830 us)(object id 272041)
  23690    MAT_VIEW ACCESS BY INDEX ROWID TBL2 (cr=3310362 pr=17 pw=0 time=235116546 us)
  96565     INDEX RANGE SCAN XPK_TBL2 (cr=3219374 pr=3 pw=0 time=217869652 us)(object id 272084)
      0   TABLE ACCESS BY INDEX ROWID TBL3 (cr=2 pr=0 pw=0 time=293390 us)
      0    INDEX RANGE SCAN XIF1TBL3 (cr=2 pr=0 pw=0 time=180345 us)(object id 271983)

請注意操作為MERGE JOIN CARTESIAN和BUFFER SORT的行。 讓我看到這一點的是生成的行數(超過200萬!),以及每次操作花費的時間(與其他操作相比)。

插入減速的主要元凶是索引,約束和oninsert觸發器。 做一個沒有盡可能多的測試,你可以刪除,看看它是否很快。 然后介紹它們,看看哪一個導致問題。

我見過系統,它們在批量插入之前刪除索引並在最后重建 - 而且速度更快。

首先要意識到的是,正如文檔所說 ,您看到的成本是相對於其中一個查詢計划的。 2種不同解釋的成本無法比較。 其次,成本基於內部估計。 與Oracle一樣努力,這些估計並不准確。 特別是當優化器行為不當時。 您的情況表明,根據Oracle,有兩個查詢計划在性能上非常接近。 但實際上,它的表現卻截然不同。

您要查看的實際信息是實際的解釋計划本身。 這告訴您Oracle究竟如何執行該查詢。 它有很多技術性的gobbeldy-gook,但你真正關心的是知道它從最縮進的部分開始工作,並且在每一步它根據少量規則之一進行合並。 這將告訴您在兩個實例中Oracle的做法有何不同。

接下來是什么? 那么有很多策略來調整壞的陳述。 如果你在Oracle 10g中,我建議的第一個選擇是嘗試他們的SQL調優顧問 ,看看更詳細的分析是否會告訴Oracle其方式的錯誤。 然后它可以存儲該計划,您將使用更有效的計划。

如果你不能這樣做,或者如果那不起作用,那么你需要進入諸如提供查詢提示,手動存儲的查詢輪廓等之類的事情。 這是一個復雜的話題。 這是真正的DBA有用的地方。 如果你不這樣做,那么你會想要開始閱讀文檔 ,但要注意有很多東西需要學習。 (Oracle也有一個SQL調優類,或者至少曾經是非常好的。但它並不便宜。)

為了解決另一個問題,我已經提出了我要檢查的一般事項清單,以提高性能:

最喜歡的性能調整技巧

......作為核對表可能會有所幫助,即使它不是特定於Oracle的。

我同意之前的海報,SQL Trace和tkprof是一個很好的起點。 我還強烈推薦“ 優化Oracle性能 ”一書,該書討論了跟蹤執行和分析輸出的類似工具。

只有您可以訪問這些工具時,SQL Trace和tkprof才有用。 我所做的大多數大型公司都不允許開發人員訪問Oracle unix ID下的任何內容。

我相信您應該能夠通過首先了解所提出的問題並閱讀每個查詢的解釋計划來確定問題。 很多時候我發現最大的區別是有些表和索引尚未分析。

提供查詢調優的一般技術的另一個很好的參考是Dan Tow的SQL Tuning一書。

當sql語句的性能不如預期/期望時,我做的第一件事就是檢查執行計划。

訣竅是檢查不符合預期的事情。 例如,您可能會發現表掃描,您認為索引掃描應該更快,反之亦然。

oracle優化器有時會出錯的地方是估計一個步驟將返回多少行。 如果執行計划需要2行,但是您知道它將更像2000行,則執行計划必然不是最佳的。

有兩個要比較的陳述,你可以明顯地比較兩個執行計划,看看它們的不同之處。

從這個分析中,我提出了一個我認為應該更適合的執行計划。 這不是一個確切的執行計划,只是對我發現的一些重要更改,例如:它應該使用Index X或Hash Join而不是嵌套循環。

接下來要想辦法讓Oracle使用該執行計划。 通常使用Hints或創建附加索引,有時會更改SQL語句。 然后當然測試改變的聲明

a)仍然做它應該做的事情

b)實際上更快

使用b,確保測試正確的用例非常重要。 典型的陷阱是返回第一行與返回最后一行之間的差異。 大多數工具會在可用時立即顯示第一批結果,沒有直接指示,還有更多工作要做。 但是如果你的實際程序在繼續下一個處理步驟之前必須處理所有行,那么當第一行出現時它幾乎是無關緊要的,只有當最后一行可用時它才有意義。

如果找到更好的執行計划,最后一步是讓數據庫在實際程序中實際使用它。 如果您添加了索引,這通常可以立即使用。 提示是一個選項,但如果庫創建您的sql語句,那些可能會有問題,那些不支持提示。 作為最后的手段,您可以保存並修復特定sql語句的執行計划。 我會避免這種方法,因為它很容易被遺忘,並且在一年左右的時間里,一些可憐的開發人員會為了這個問題而煩惱,為什么語句以一年前可能適用於數據的方式執行,而不是當前數據......

分析oI還強烈推薦“優化Oracle性能”一書,該書討論了跟蹤執行和輸出的類似工具。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM