2014-07-23 26 views
0

這是我的SQL查詢與我得到的所有的重複,而是一個(最新的):SQL語句佔用大量時間,可以優化它嗎?

SELECT d.C_ContactID, d.C_EmailAddress, d.C_DataSourceID, d.C_DateCreated 
FROM duplicates as d 
WHERE d.C_DateCreated !=(select max(d2.C_DateCreated) 
FROM duplicates d2 
WHERE d2.C_DataSourceId = d.C_DataSourceId) 

是否有可能以某種方式優化呢?不幸的是,在30萬條記錄中,花費了+ - 40分鐘。

方法,其中的查詢是:

public ArrayList<Record> get() throws SQLException, 
     ClassNotFoundException { 
    Statement st = DBConnect.DBC.con.createStatement(); 
    String sql = ("select d.C_ContactID, d.C_EmailAddress, d.C_DataSourceID, 
d.C_DateCreated " 
      + "from duplicates as d " 
      + "where d.C_DateCreated !=(select max(d2.C_DateCreated) " 
      + "from duplicates d2 where d2.C_DataSourceId = d.C_DataSourceId)"); 
    ResultSet rs = st.executeQuery(sql); 
    DBConnect.DBC.con.commit(); 
    while (rs.next()) { 

     int contactID = rs.getInt("C_ContactID"); 
     String email = rs.getString("C_EmailAddress"); 
     String dataSourceID = rs.getString("C_DataSourceID"); 
     String dateCreated = rs.getString("C_DateCreated"); 
     duplicate = new Record(contactID, email, dataSourceID, dateCreated); 
     duplicates.add(duplicate); 
    } 
    rs.close(); 
    st.close(); 

    return duplicates; 
} 
+0

你在該表上有任何索引嗎? –

+0

你在使用哪種SQL? – Steve

+0

你的RDBM是什麼?另外將執行計劃添加到您的問題。 –

回答

2

您將通過創建duplicates(C_DataSourceId, C_DateCreated)索引開始:

create index duplicates_DataSourceId_DateCreated on duplicates(C_DataSourceId, C_DateCreated); 

如果您使用的是支持窗口功能的數據庫,然後我會改寫這個作爲:

SELECT d.C_ContactID, d.C_EmailAddress, d.C_DataSourceID, d.C_DateCreated 
FROM (select d.*, max(C_DateCreated) over (partition by C_DataSourceId) as maxdc 
     from duplicates d 
    ) d 
WHERE d.C_DateCreated <> maxdc; 

這是值得做的比較,因爲索姆etimes窗口函數具有高效的實現。

而且,如果你有索引,查詢的效率更高一點的版本是:

SELECT d.C_ContactID, d.C_EmailAddress, d.C_DataSourceID, d.C_DateCreated 
FROM duplicates d 
WHERE EXISTS (select 1 
       from duplicates 2 
       where d2.C_DataSourceId = d.C_DataSourceId and 
        d2.C_DateCreated > d.C_DateCreated 
      ); 

這是說擺脫重複的所有行那裏是另一行(具有相同源),有創建一個更大的日期。略微的優勢是,這不必看所有的值得到max()。它只需要找到第一個。主要業績改善將成爲綜合指數。

+0

你會介意告訴我如何做索引,因爲我不知道它是什麼,但我會檢查它。謝謝,我也會將它標記爲答案。 –

+0

我試過你的查詢,可能我的SQLite不支持窗口函數。但感謝那個索引。 –

+0

您的整個答案是完美的,我會將其標記爲正確的,非常感謝! –

1

爲列C_DateCreated和C_DataSourceId創建索引。這將減少執行查詢的時間。請參閱此鏈接瞭解如何創建索引。 http://www.tutorialspoint.com/mysql/mysql-indexes.htm

+0

這個問題被標記爲SQLite,而不是MySQL。索引和計劃者的行爲會有所不同。 – Bruno

0

在T-SQL的答案是這樣的,但我不認爲SQLite支持窗口函數(留下完整的答案爲後人雖然):

您可以使用窗口函數來標記每個與它在常用C_DataSourceIDs組中的位置相同的行,然後使用CTE選擇不在位置1的行。

with ordered as (
    select 
     d.C_ContactID, 
     d.C_EmailAddress, 
     d.C_DataSourceID, 
     d.C_DateCreated, 
     row_number() over (
      partition by 
       d.C_DataSourceID 
      order by 
       d.C_DateCreated 
     ) as rownum 
    from 
     duplicates 
) select 
    C_ContactID, 
    C_EmailAddress, 
    C_DataSourceID, 
    C_DateCreated 
from 
    ordered 
where 
    rownum != 1; 

隨着指數(C_DataSourceID, C_DateCreated)這將只需要在桌子上,而不是自單通道加入,你必須在你的查詢。

+0

你確定SQLite支持CTE嗎? – Bruno

+0

Bah,錯過了標籤,並認爲我在看C#,因此假定T-SQL。較新的SQLite確實支持CTE,但不清楚窗口函數。 – Steve

+0

啊,是的,[你是對的](http://sqlite.org/lang_with.html)。不過,我看不到有關窗口功能的任何信息。 – Bruno