2012-02-03 160 views
2

我需要刪除第一次出現的記錄。這有一個PK(preld_item, IDENTITY)。刪除非常慢

這是非常緩慢的DELETE ..

DELETE pd 
FROM preliquidaciones_deta pd 
WHERE pd.preld_item IN (SELECT MAX(p.preld_item) 
         FROM preliquidaciones_deta p 
         WHERE p.id_preliquidacion = '216' 
         GROUP BY p.id_sds_linea_equipo, 
            p.id_concepto 
         HAVING COUNT(p.id_sds_linea_equipo) > 1) 

感謝

編輯:

  • 表已超過500萬行
  • id_preliquidacion有一個聚集索引(PK )

編輯2: @vulkanino我想在你的答案和我修改刪除...

DECLARE @loPreldItem INT 
DECLARE curItems CURSOR FOR (select max(p.preld_item) 
    from preliquidaciones_deta p 
    where p.id_preliquidacion = '216' 
    group by p.id_sds_linea_equipo, p.id_concepto 
    having count(p.id_sds_linea_equipo) > 1) 

OPEN curItems 
FETCH NEXT FROM curItems INTO @loPreldItem 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    DELETE FROM preliquidaciones_deta WHERE preld_item = @loPreldItem 
    FETCH NEXT FROM curItems INTO @loPreldItem 
END 
CLOSE curItems 
DEALLOCATE curItems 

這個工作最好的,但繼續緩慢

編輯3:的執行計劃先刪除

delete from preliquidaciones_deta where preld_item in ( select max(preld_item) from preliquidaciones_deta where id_preliquidacion = '216' group by id_sds_linea_equipo, id_concepto, preld_nse, preld_linea having count(id_preliquidacion) > 1) 
    |--Assert(WHERE:(CASE WHEN NOT [Expr1018] IS NULL THEN (0) ELSE CASE WHEN NOT [Expr1019] IS NULL THEN (1) ELSE NULL END END)) 
     |--Nested Loops(Left Semi Join, OUTER REFERENCES:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item]), DEFINE:([Expr1019] = [PROBE VALUE])) 
      |--Nested Loops(Left Semi Join, OUTER REFERENCES:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item]), DEFINE:([Expr1018] = [PROBE VALUE])) 
      | |--Clustered Index Delete(OBJECT:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[PK_preliquidaciones_deta]), OBJECT:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[IX_id_sds]), OBJECT:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[IX_id_sds_linea_equipo])) 
      | | |--Top(ROWCOUNT est 0) 
      | |   |--Sort(DISTINCT ORDER BY:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item] ASC)) 
      | |    |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1007]) OPTIMIZED) 
      | |     |--Filter(WHERE:([Expr1006]>(1))) 
      | |     | |--Compute Scalar(DEFINE:([Expr1006]=CONVERT_IMPLICIT(int,[Expr1023],0))) 
      | |     |   |--Stream Aggregate(GROUP BY:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[id_sds_linea_equipo], [data_dealernet_lucom].[dbo].[preliquidaciones_deta].[id_concepto], [data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_nse], [data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_linea]) DEFINE:([Expr1023]=Count(*), [Expr1007]=MAX([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item]))) 
      | |     |    |--Sort(ORDER BY:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[id_sds_linea_equipo] ASC, [data_dealernet_lucom].[dbo].[preliquidaciones_deta].[id_concepto] ASC, [data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_nse] ASC, [data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_linea] ASC)) 
      | |     |     |--Clustered Index Scan(OBJECT:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[PK_preliquidaciones_deta]), WHERE:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[id_preliquidacion]='216')) 
      | |     |--Clustered Index Seek(OBJECT:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[PK_preliquidaciones_deta]), SEEK:([data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item]=[Expr1007]) ORDERED FORWARD) 
      | |--Clustered Index Scan(OBJECT:([data_dealernet_lucom].[dbo].[liquidaciones_deta].[PK_liquidaciones_deta]), WHERE:([data_dealernet_lucom].[dbo].[liquidaciones_deta].[preld_item]=[data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item])) 
      |--Table Scan(OBJECT:([data_dealernet_lucom].[dbo].[liquidaciones_diferidas]), WHERE:([data_dealernet_lucom].[dbo].[liquidaciones_diferidas].[preld_item]=[data_dealernet_lucom].[dbo].[preliquidaciones_deta].[preld_item])) 
+0

如何對任何其他列的contidions出現或者像preld_item,id_sds_linea_equipo,d_concepto這樣的分組標準,他們是否有非聚集索引? – Mithrandir 2012-02-03 13:55:35

+0

是的,他們有一個非聚集索引,沒有這個子查詢也很慢 – Marcos 2012-02-03 14:32:59

回答

4

你可以試試這個替代(如你的國家,就不會有超過2行每id_sds_linea_equipo, id_concepto這有相同的語義原始查詢)

WITH T 
    AS (SELECT *, 
       RN = ROW_NUMBER() OVER 
           (PARTITION BY id_sds_linea_equipo, id_concepto 
             ORDER BY preld_item) 

     FROM preliquidaciones_deta 
     WHERE id_preliquidacion = '216') 
DELETE FROM T 
WHERE RN > 1 
+0

不錯的選擇,但表中有一個PK(preld_item,IDENTITY),這個是「行標識符」 – Marcos 2012-02-03 14:36:27

+1

@Marcos - 那麼?不知道這是如何影響我的答案?這應該與原始查詢具有相同的語義,但沒有自加入。您可以將'DELETE FROM T'更改爲'SELECT * FROM T'來進行完整性檢查並查看性能如何。 – 2012-02-03 14:37:45

+1

+1漂亮的代碼:) – vulkanino 2012-02-03 14:49:16

0

更改IN=由於子查詢僅在行上返回。 (開始)。

+0

這不會是查詢速度慢的原因,但如果你只希望單行,這是一件好事。 – 2012-02-03 13:55:57

+0

它不一定只返回1行。它會根據符合'having'子句的'id_sds_linea_equipo,id_concepto'組合返回1行。 – 2012-02-03 14:02:11

+0

@馬丁你說得對,謝謝。 – vulkanino 2012-02-03 14:28:37

0

不知道它是否適用於您的情況(由於HAVING子句),但ORDER BY p.preld_item DESC LIMIT 1可能比最大聚合速度快得多。

+0

問題不是子查詢,這會在幾秒鐘內回退超過10k行...當我運行整個刪除非常緩慢 – Marcos 2012-02-03 14:03:11

+1

@Marcos - 什麼執行計劃是什麼樣的? – 2012-02-03 14:09:47