2014-07-23 31 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