2011-05-02 42 views
8

我試圖優化在生產中花費很長時間的查詢。目標是根據匹配的字段值標準查找重複記錄,然後刪除它們。當前查詢通過t1.col1 = t2.col1上的內部連接使用自連接,然後使用where子句檢查值。檢查重複項時最佳自加入方法

select * from table t1 
inner join table t2 on t1.col1 = t2.col1 
where t1.col2 = t2.col2 ... 

什麼是更好的方法來做到這一點?或者是基於索引的全部相同?也許

select * from table t1, table t2 
where t1.col1 = t2.col1, t2.col2 = t2.col2 ... 

這張表有100m +行。

MS SQL,SQL Server 2008企業

select distinct t2.id 
    from table1 t1 with (nolock) 
    inner join table1 t2 with (nolock) on t1.ckid=t2.ckid 
    left join table2 t3 on t1.cid = t3.cid and t1.typeid = t3.typeid 
    where 
    t2.id > @Max_id and 
    t2.timestamp > t1.timestamp and 
    t2.rid = 2 and 
    isnull(t1.col1,'') = isnull(t2.col1,'') and 
    isnull(t1.cid,-1) = isnull(t2.cid,-1) and 
    isnull(t1.rid,-1) = isnull(t2.rid,-1)and 
    isnull(t1.typeid,-1) = isnull(t2.typeid,-1) and 
    isnull(t1.cktypeid,-1) = isnull(t2.cktypeid,-1) and 
    isnull(t1.oid,'') = isnull(t2.oid,'') and 
    isnull(t1.stypeid,-1) = isnull(t2.stypeid,-1) 

    and (
      (
       t3.uniqueoid = 1 
      ) 
      or 
      (
       t3.uniqueoid is null and 
       isnull(t1.col1,'') = isnull(t2.col1,'') and 
       isnull(t1.col2,'') = isnull(t2.col2,'') and 
       isnull(t1.rdid,-1) = isnull(t2.rdid,-1) and 
       isnull(t1.stid,-1) = isnull(t2.stid,-1) and 
       isnull(t1.huaid,-1) = isnull(t2.huaid,-1) and 
       isnull(t1.lpid,-1) = isnull(t2.lpid,-1) and 
       isnull(t1.col3,-1) = isnull(t2.col3,-1) 
      ) 
    ) 
+0

MS SQL?如果是這樣,哪個版本的SQL Server? – 2011-05-02 15:50:24

+0

@布魯諾抱歉,我更新了問題和標籤 – 2011-05-02 15:52:12

+0

@Mitch不是它加入同一張桌子的一張桌子。它怎麼不是一個自我加入? – 2011-05-02 15:56:54

回答

13

爲什麼自加入:這是一個總的問題。

希望你有在col1,col2上,索引...

--DELETE table 
--WHERE KeyCol NOT IN (
select 
    MIN(KeyCol) AS RowToKeep, 
    col1, col2, 
from 
    table 
GROUP BY 
    col12, col2 
HAVING 
    COUNT(*) > 1 
--) 

然而,這需要一定的時間。有look at bulk delete techniques

+0

+1 - 可能是運行速度最快的答案 – JNK 2011-05-02 16:00:17

+0

我更新了我的問題(列/表名已更改)。你的建議仍然有效嗎? – 2011-05-02 16:11:49

+0

@ Titan278:應該這樣做。不需要GROUP BY與ISNULL,你應該使用EXISTS進行table2/t3檢查(避免使用DISTINCT) – gbn 2011-05-02 16:19:42

1

您可以使用ROW_NUMBER()在一個表中找到重複的行。

您可以檢查here

+0

oooh。要在這個大小的桌子上討厭。我會使用合計 – gbn 2011-05-02 16:03:19

+0

是的,但是如果行完全相同,我認爲這種聚合不會起作用,至少是以一種簡單的方式。 – 2011-05-02 16:19:14

+0

你認爲沒有PK:你可以在PK之外有重複。 OP的更新顯示有一個PK,但仍然重複。它不會改變ROW_NUMBER會像狗一樣運行的事實。 – gbn 2011-05-02 16:22:43

0

要檢測是否有重複,你並不需要加入:

SELECT col1, col2 
FROM table 
GROUP BY col1, col2 
HAVING COUNT(*) > 1 

這應該是要快得多。

+0

在1億行表上?我不這麼認爲! – 2011-05-02 15:54:46

+0

@Mitch小麥:任何技術都會像100多萬行的狗一樣運行......特別是基於ROW_NUMBER的函數 – gbn 2011-05-02 15:58:52

+2

@Mitch:實際問題不是,「有沒有辦法寫出這個會在undex x秒內運行?」但是「爲了達到預期結果,最快的查詢是什麼」。 – Jay 2011-05-02 16:21:40

1

你給出的兩種方法應該是等價的。我認爲在這兩種情況下,大多數SQL引擎都會做同樣的事情。

而且,順便說一下,這是行不通的。您必須至少有一個不同的字段,否則每個記錄都會自行匹配。

你可能想嘗試更多的東西一樣:

select col1, col2, col3 
from table 
group by col1, col2, col3 
having count(*)>1 
1

對於具有100m +行的表,將優化使用GROUPBY函數和使用保持表。即使它翻譯成四個查詢。

第1步:創建一個拿着鑰匙:

SELECT col1, col2, col3=count(*) 
INTO holdkey 
FROM t1 
GROUP BY col1, col2 
HAVING count(*) > 1 

第2步:按全部重複條目到holddups中。這是必需的步驟4:

SELECT DISTINCT t1.* 
INTO holddups 
FROM t1, holdkey 
WHERE t1.col1 = holdkey.col1 
AND t1.col2 = holdkey.col2 

第3步:從原始表中刪除重複的行。

DELETE t1 
FROM t1, holdkey 
WHERE t1.col1 = holdkey.col1 
AND t1.col2 = holdkey.col2 

步驟4:將唯一行放回原始表。例如:

INSERT t1 SELECT * FROM holddups 
0

以我的經驗,SQL Server性能與OR條件非常糟糕。可能它不是自我加入,但與table3導致不良的表現。但是沒有看到這個計劃,我不確定。

在這種情況下,它可能會幫助到您的查詢拆分爲兩個:一個 用WHERE條件t3.uniqueoid = 1和一個帶有WHERE條件在表3其他conditons,然後用UNION ALL追加一個到另一個。