2009-06-02 113 views
1

數據庫甲骨文優化查詢涉及日期計算

Table1 
Id 
Table2Id 

... 

Table2 
    Id 
    StartTime 
    Duration //in hours 

查詢

select * from Table1 join Table2 on Table2Id = Table2.Id 
where starttime < :starttime and starttime + Duration/24 > :endtime 

此查詢目前正在約2秒運行是太長。在Start_time + duration/24上有一個id列的索引和一個函數索引。在Sql Developer中,查詢計劃顯示沒有使用索引。查詢返回475行,用於測試開始和結束時間。表2有〜800k行表1有〜200k行

如果從查詢中刪除持續時間/ 24計算,替換爲靜態值,則查詢時間減半。這不會檢索到完全相同的數據,但會讓我相信該部門很昂貴。

我還測試了向Table2中添加endtime列,該列填充了(starttime + duration/24)該列是通過單個更新預填充的,如果它將在生產中使用,我將通過更新觸發器填充它。

select * from Table1 join Table2 on Table2Id = Table2.Id 
where starttime < :starttime and endtime > :endtime 

該查詢將在大約600ms內運行,並且它使用聯接索引。由於具有冗餘數據的附加列,它不那麼理想。

有沒有使這個查詢更快的方法?

+0

根據顯示的查詢,您將檢索Table2中不在給定範圍內的所有記錄。奇怪,但沒問題。你的統計數據是否是最新的?也許優化器有錯誤的信息,並正在選擇一個不好的計劃?你想解決什麼問題?你需要Table2中的數據,還是你需要Table1中的所有東西?對數據分佈有何評論? Oracle版本(可能有一個功能可以/不能用於幫助)? – 2009-06-02 16:58:05

+0

Oracle 10g統計信息是最新的。我的聯接倒退了,真正的表格翻譯不好。 – 2009-06-02 18:05:55

+0

您是否至少運行過SQL * Plus AUTOTRACE或EXPLAIN PLAN(更好的是,跟蹤事件10046)。要調優查詢,首先需要_important_首先知道Oracle正在花費多少時間進行操作。 – spencer7593 2009-06-02 20:38:13

回答

3

創建在兩個開始時間的函數索引和表達starttime + Duration/24

create index myindex on table2(starttime, starttime + Duration/24); 

上查詢的整個謂詞的化合物指數應選擇,而單獨地索引的優化很可能決定反覆表由訪問基於這些索引之一的掃描的rowid實際上比全表掃描要慢。

通過確保您在綁定變量中傳遞DATE,還要確保您沒有進行從varchar到日期的隱式轉換。

嘗試降低optimizer_index_cost_adj系統參數。我相信默認值是100.嘗試將其設置爲10並查看是否選擇了您的索引。

考慮按starttime分區表。

1

如果where子句的選擇性不是很好,Oracle將不會使用索引。如果返回的行數是表中總行數的百分比(該百分比會變化,因爲oracle將計算讀取索引以及讀取表的成本),將使用索引。

此外,索引列在where子句中修改時,索引將被禁用。例如,UPPERCASE(some_index_column)會禁用some_index_column上索引的使用。這就是starttime + Duration/24>:endtime不使用索引的原因。

你可以試試這個

select * from Table1 join Table2 on Table1.Id = Table2.Table1Id 
where starttime < :starttime and starttime > :endtime - Duration/24 

這應該允許使用索引的和沒有必要額外列。

1

您有兩個範圍謂詞(大於/小於)的標準。索引範圍掃描可以從索引中的一個點開始,結束於另一個點。

對於起始時間和「Starttime + duration/24」的複合索引,由於前導列是starttime,謂詞「小於綁定值」,因此它將從索引的最左邊開始(最早的起始時間)並且範圍掃描所有行直到開始時間達到極限的點。對於每個匹配項,它可以針對綁定值計算索引上「Starttime + duration/24」的計算值並傳遞或拒絕該行。我懷疑表中的大部分數據都是舊的,所以大多數條目都有一箇舊的開始時間,並且最終會掃描大部分索引。

對於「開始時間+持續時間/ 24」和開始時間的複合索引,由於前導列是函數,謂詞是「大於綁定值」,因此它將在索引的中途開始並一直工作到結束。對於這些匹配中的每一個,它都可以根據綁定值評估索引的開始時間並傳遞或拒絕該行。如果enddate傳入的是最近的,我懷疑這實際上涉及的索引被掃描的數量要小得多。

即使沒有開始時間作爲索引的第二列,「Starttime + duration/24」上的現有基於功能的索引仍應該有用並且被使用。檢查解釋計劃以確保綁定值是日期或轉換爲日期。如果已轉換,請確保使用適當的格式掩碼(例如,'1/Jun/09'的輸入值可能會轉換爲0009年,所以Oracle將看到該條件非常寬鬆,並且傾向於不使用索引 - 加上結果可能是錯誤的)。

「在Sql Developer中,查詢計劃顯示沒有使用索引。」如果索引沒有用於查找table2行,我懷疑優化器認爲table2的大部分/全部都會返回[顯然它不是',按你的號碼]。我猜想,儘管table1的大部分都會被返回,因此你的謂詞都沒有進行很多過濾。正如我上面所說,我認爲「少於」謂詞不是有選擇的,但「大於」應該是。看看解釋計劃,特別是ROWS值,看看Oracle認爲什麼

PS。調整值意味着優化器更改其估計的基礎。如果一個旅程策劃者說你需要六個小時的旅行,因爲它假設平均速度爲50,如果你告訴它平均假設爲100,那麼它會有三個小時。它實際上不會影響你旅行的速度,或者實際上旅行需要多長時間。 所以你只想改變這個值,使它更準確地反映你的數據庫(或會話)的實際值。