2010-02-23 58 views
3

突然(但不幸的是,我不知道什麼時候「突然」發生,我知道它在過去的某個時間點運行良好)我的一個查詢開始花費7+秒而不是毫秒來執行。我有1個本地表和3個表通過數據庫鏈接訪問。 3個遠程表連接在一起,其中一個與我的本地表連接。Oracle LEADING提示 - 爲什麼這是必需的?

本地表的where子句只需要幾個毫秒來自行執行,並且只返回幾個(最多10或100個)記錄。這3個遠程表之間有數十萬甚至數百萬條記錄,如果我適當地加入它們,我會得到數十或數十萬條記錄。

我只與遠程表連接,以便我可以提取與本地表中的每條記錄相關的幾條數據。

然而,似乎發生的事情是Oracle首先將遠程表連接在一起,然後將我的本地表連接到最後的那個混亂。這總是一個壞主意,尤其是考慮到現在存在的數據集,所以我在查詢中添加了一條/*+ LEADING(local_tab remote_tab_1) */提示,現在它返回毫秒數。

我比較瞭解釋計劃,並且它們幾乎完全相同,除了一個遠程表上的單個BUFFER SORT

我想知道什麼可能會導致Oracle以錯誤的方式處理這個問題?這是索引問題嗎?我應該尋找什麼?

+1

你試過分析你的表('dbms_stats.gather_table_stats')嗎? –

+0

+1,有趣 – DCookie

回答

5

在選擇執行計劃時,oracle會估計不同計劃的成本。該估計的一個重要信息是行數將從執行計劃的某個步驟返回。 Oracle試圖估計那些使用'統計'的信息,即關於表包含多少行的信息,列包含多少個不同的值;這些值是如何均勻分佈的。

這些統計數據就是這樣的統計數據,他們可能是錯的,這是oracle優化器誤判最重要的原因之一。

因此,收集評論中描述的新統計數據可能會有所幫助。查看該dbms_stats軟件包的文檔。有很多不同的方式可以調用該軟件包。

2

一個共同的問題我遇到的是,加入許多表的查詢,其中加入從一端到另一端形成產業鏈,如:

SELECT * 
FROM tableA, tableB, tableC, tableD, tableE 
WHERE tableA.ID0 = :bind1 
AND tableA.ID1 = tableB.ID1 
AND tableB.ID2 = tableC.ID2 
AND tableC.ID3 = tableD.ID3 
AND tableD.ID4 = tableE.ID4 
AND tableE.ID5 = :bind2; 

通知優化器會如何選擇開車來自tableA的查詢(例如,如果ID0上的索引具有良好的選擇性)或來自tableE(如果tableE.ID5上的索引更具選擇性)。

桌子上的統計數據可能會導致這兩種方案之間的選擇在刀口上平衡;有一天它運行良好(從表A駕駛),第二天收集到新的數據,突然之間從tableE駕駛的替代計劃成本較低並且被選中。

在這種情況下,將領先的提示是一種方式輕推回原來的計劃(即從TableA的驅動),而口述太多的優化器(即不強制優化器來選擇任何特定的連接方法)。

2

你正在做分佈式查詢優化,這是一個棘手的野獸。可能是你的表的統計數據是最新的,但現在遠程系統的表格已經不合時宜或已經改變。或者遠程系統添加/刪除/修改索引,這打破了你的計劃。 (這是一個很好的理由認爲複製 - 這樣你就可以控制指標和統計反對)

也就是說,基數Oracle的估計是在執行計劃的主要推動力。 10053痕跡分析(喬納森劉易斯的基於成本的Oracle基礎知識手冊中有從8i到10.1的精彩例子)可以幫助揭示爲什麼你的陳述現在被破壞以及LEADING提示如何修復它。

DRIVING_SITE提示可能是,如果你知道你總是希望本地表先前的遠程站點後會被加入了一個更好的選擇;它會明確你的意圖,而不會像LEADING暗示那樣推動計劃。

1

也許是不相關的,但我曾經在遠程表已經改爲單表視圖類似的情況。當它是一個表時,分佈式查詢優化器'看到'它有一個索引。當它成爲一個視圖時,它不能再看到索引,並且無法花費在遠程對象上使用索引的計劃。

那是幾年前。我在here時記錄了我的分析。

1

RI,

很難確保有關的性能問題的原因沒有看到SQL。

當Oracle查詢是之前表現良好,突然開始執行不好,它通常涉及到兩個問題之一:

A)統計已經過時了。這是最簡單和最快速的檢查,即使你有一個應該照顧它的家務清理過程...總是仔細檢查。

B)數據量/數據模式的改變。

在您的情況下,跨多個數據庫運行分佈式查詢會使Oracle更難以管理它們之間的性能。是否可以將這些表放在一個數據庫中,也許可以將一個數據庫中的單獨模式所有者?

提示是出了名的脆弱,因爲甲骨文是在沒有義務遵循提示。當數據量或模式發生一些變化時,Oracle可能會忽略該提示並執行它認爲最好的選擇(即最差;-)。

如果你不能把這些表都在一個數據庫中,那麼我建議你看看向上突破查詢到兩個語句:在子SELECT

  1. INSERT到外部數據複製到一個全局臨時表你當前的數據庫。
  2. 從全局臨時表中選擇與其他表加入。

您將完全控制上述步驟1的性能,而不訴諸提示。這種方法通常可以很好地擴展,因此您需要花時間進行性能調整。我已經看到這種方法解決了許多複雜的性能問題。

爲Oracle創建一個全新的表格,或插入的記錄堆的開銷,比大多數人預期小得多。定義一個全局臨時表可進一步降低這種開銷。

Matthew