2014-01-08 41 views
-1

我相對新的SQL和我有一個需要永遠運行的語句。非常大的表上的Oracle sql語句

SELECT 
    sum(a.amountcur) 
FROM 
    custtrans a 
WHERE 
    a.transdate <= '2013-12-31'; 

我是一個大桌子,但statemnt大約需要6分鐘! 任何想法爲什麼?

+1

後解釋相同的計劃。它給更多的燈光 – SriniV

+6

1.永遠定義。是秒,分鐘還是小時? 2.永遠不要中繼隱式數據類型轉換。在你的情況下,使用'to_date()'函數將表示日期的字符字面值轉換爲'data'數據類型的值。所以你的謂詞可能看起來像這樣:'where a.transdate <= to_date('2013-12-31','yyyy-mm-dd')'或'where a.transdate <= date'2013-12-31' '。另外,提供更多有關您的表有多大的信息總是個好主意,執行計劃是什麼,是否有任何索引等等。 –

+0

@NicholasKrasnov你讀了我的想法:) – SriniV

回答

1

確保表中有一個transdate索引。

create index custtrans_idx on custtrans (transdate); 

此外,如果該字段定義爲表中的一個日期,然後做

SELECT sum(a.amountcur) 
    FROM custtrans a 
    WHERE a.transdate <= to_date('2013-12-31', 'yyyy-mm-dd'); 
+1

當他選擇「一切直到一個星期前」,這個索引可能會比它幫助更多的傷害,因爲查詢仍然會讀取99%的數據表和頂部的索引。 –

+0

這是一個不正確的陳述。 Oracle將讀取b-tree索引(log n^n速度),只獲取相關的rowid,然後訪問該表。 –

+0

話雖如此,你的帖子與索引跨兩列是更好的,因爲oracle可以做一個索引只掃描。 –

1

如果表是真的大,查詢必須掃描與transdate每一行如下。

即使您在transdate上有一個索引,並且它有助於儘早停止掃描(可能不會),但如果匹配行的數量非常大,則需要相當長的時間來掃描所有數據並將這些值相加。

爲了加快速度,您可以計算部分總和。對於每個傳遞的月份,假設您的數據是歷史數據,過去不會更改。然後,您只需要掃描custtrans 1-2個月,然後快速掃描每月總計的表格並添加結果。

0

一種選擇是在where子句中使用的列上創建索引(如果您希望通過使用索引列檢索僅10-15%的行,這會很有用)。

另一種選擇是對錶格進行分區,如果它有數百萬行。在這種情況下,如果您嘗試檢索70-80%的數據,則無法提供幫助。

最好的選擇是首先分析您的要求,然後做出選擇。

無論何時處理日期函數,最好使用to_date()函數。不要依賴隱式數據類型轉換。

+0

什麼是「你的桌子」或「你的交易」? –

+0

如果您選擇所有表數據的90%,那麼分區不會改變任何性能。 –

+0

-1 ..首先不應該只是創建一個索引。首先要獲得更多的信息。您應該瞭解時間在哪裏,需要掃描以獲取結果的數據量以及數據在表中的位置(索引有助於消除塊訪問......行的百分比相對不重要) – Craig

2

你的選擇,當你發佈,將讀取整個表的99%(2013-12-31只是一個星期前,我假設大多數條目是在該日期之前,只有很少之後)。如果你的表有很多大的列(比如varchar2(4000)),當oracle掃描表時,所有的數據也會被讀取。因此,您可能每行只讀幾個KB,以獲取您需要的30個字節,用於datacur和transdate。

如果您有這種情況。創建transdate和amountcur組合索引:

CREATE INDEX myindex ON custtrans(transdate, amountcur) 

隨着組合索引,Oracle可以讀取索引以滿足您的查詢,不必觸摸主表中的所有,這可能會導致相當少的數據需要從磁盤讀取。

+0

LOBS在默認情況下存儲在實際表格之外。因此,除非您選擇任何LOB列,否則不會從光盤讀取它們。 –

+0

@ Wernfried:對,謝謝。更正了我的帖子。 –

+0

加1 - 這是最有效和最快的索引。底層表不需要觸及。唯一可能的更快的方法是分割索引。 –

0

儘量只在列amountcur創建索引:

CREATE INDEX myindex ON custtrans(amountcur) 

在這種情況下,Oracle將讀取很可能只是指數(索引全掃描),沒有別的。

更正,如評論中所述。它必須是一個綜合指數:

CREATE INDEX myindex ON custtrans(transdate, amountcur) 

但也許這是一個有點沒用的,只是一個單一的SELECT語句創建一個索引。

+0

Oracle仍然必須讀取查詢以滿足WHERE子句,因爲transdate不在索引中。 – Craig

+0

是的,你是對的。在這種情況下,它必須是一個複合索引。我會改變我的帖子 –