2012-02-03 4 views
2

Мне нужно удалить только первое появление записи. У этого есть ПК (preld_item, IDENTITY).Удалить очень медленно

Это очень медленно УДАЛИТЬ ..

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) 

Благодаря

EDIT:

  • Стол имеет более чем 5 миллионов строк
  • id_preliquidacion имеет кластерный индекс (рк)

EDIT 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 

Это работает лучше, но по-прежнему медленно

EDIT 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

+0

yep, у них есть некластеризованный индекс, без того, что подзапрос тоже очень медленный – Marcos

ответ

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), этот fied является «идентификатором строки» – Marcos

+1

@Marcos - Итак? Не знаете, как это повлияет на мой ответ? Это должно иметь ту же семантику, что и исходный запрос, но без самостоятельного присоединения. Вы можете изменить 'DELETE FROM T' на' SELECT * FROM T' для проверки работоспособности и посмотреть, как работает производительность. –

+1

+1 красивый код :) – vulkanino

0

Изменить IN с помощью =, так как подзапрос возвращается только по строке. (для начала).

+0

Это не будет причиной того, что запрос выполняется медленно, но все равно хорошо, если вы ожидаете только одной строки. –

+0

Это не обязательно возвращает только 1 строку. Он возвращает 1 строку на комбинацию 'id_sds_linea_equipo, id_concepto', которая соответствует предложению' having'. –

+0

@martin, вы правы, спасибо. – vulkanino

0

Не уверен, что это относится к вашему делу (из-за предложения HAVING), но ORDER BY p.preld_item DESC LIMIT 1 может быть намного быстрее, чем максимальный агрегат.

+0

проблема не в подзапросе, это повторяет более 10 тыс. Строк в секундах ... когда я запускаю все удаление очень медленно – Marcos

+1

@Marcos - Что выглядит ли план выполнения? –

Смежные вопросы