2014-09-17 3 views
1

У меня есть переменная таблицы, которую я использую для сбора записей из нескольких таблиц, которые должны быть обработаны позже в моем запросе.Ускоренный SQL УДАЛИТЬ ГДЕ Нужны IN/EXISTS

Это выглядит немного как это:

DECLARE @Prices TABLE ( 
    ProductId INT, 
    Price MONEY, 
    Fee INT, 
    Discount INT, 
    IsSpecialPrice BIT 
) 

Теперь, после сбора связанных цен записей из нескольких таблиц (около 400K записей), я должен удалить только несколько записей. Для продуктов, для которых у меня есть как минимум 2 записи (один или несколько с IsSpecialPrice = 0 и один с IsSpecialPrice = 1), мне нужно удалить все записи, где IsSpecialPrice = 0.

Теперь с помощью УДАЛИТЬ ГДЕ И УДАЛИТЬ ГДЕ СУЩЕСТВУЕТСЯ слишком долго, чтобы избавиться от нескольких записей. Итак, я ищу более быстрый тип запроса.

Прямо сейчас это то, что я использую:

DELETE P1 
FROM @Prices P1 
WHERE P1.IsSpecialPrice = 0 AND EXISTS (SELECT P2.ProductId FROM @Prices P2 WHERE P2.ProductId = P1.ProductId AND P2.IsSpecialPrice = 1) 

Я пытался как WHERE IN и WHERE EXISTS, но оба так же медленно.

+1

И какие индексы существуют/пытались ли вы создать, чтобы ускорить процесс? –

+0

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

+3

Оптимизаторы запросов делают то же самое –

ответ

3

а как насчет присоединения?

DELETE P1 
FROM @Prices P1 join (
    SELECT DISTINCT ProductId 
    FROM @Prices 
    WHERE IsSpecialPrice = 1 
) P2 on P1.ProductId = P2.ProductId 
WHERE P1.IsSpecialPrice = 0 

я сделал тест на стол с 500k строк и завершен в 2sec удаление 90k строка, это огромный шаг вперед по сравнению с нескончаемым exists.

+0

Это тип соединения, который работает очень быстро! Спасибо – Tys

1

Это ваш запрос:

DELETE P1 
    FROM @Prices P1 
    WHERE P1.IsSpecialPrice = 0 AND 
      EXISTS (SELECT 1 
        FROM @Prices P2 
        WHERE P2.ProductId = P1.ProductId AND P2.IsSpecialPrice = 1 
       ); 

Обычный способ ускорить это было бы добавить индексы: @Prices(IsSpecialPrice) и @Prices(ProductId, IsSpecialPrice). Увы, вы не можете добавлять индексы в переменные таблицы, если вы не используете SQL Server 2014 (новая функция).

Альтернативой было бы хранить это в явной временной таблице и добавлять индексы в эту таблицу. Итак, используйте #Prices, а не @Prices для таблицы.

+0

Как насчет ограничения 'UNIQUE' на' (IsSpecialPrice, ProductId) '? IIRC, уникальные ограничения выполняются индексами, даже уникальными ограничениями на табличные переменные, поэтому их можно использовать в версиях SQL Server, где возможность явно создавать индекс не поддерживается. (Я предполагаю, что 'ProductId' уникален.) – hvd

0

Я считаю, присоединяется почти всегда быстрее, так что я хотел бы написать запрос в качестве такого

DELETE P1 
FROM @Prices P1 
INNER JOIN @Prices P2 ON P2.ProductId = P1.ProductId AND P2.IsSpecialPrice = 1 
WHERE P1.IsSpecialPrice = 0 

Если это еще не дает желаемый результат, необходимо сделать их временные таблицы и индексировать их соответствующим образом поскольку переменные таблицы не позволяют индексировать.

+0

Использование соединения было правильным вариантом, хотя этот не работал. Это было так же медленно, как и мои другие варианты. Но тот, которого предложил Паоло, был именно тем, что мне нужно! – Tys

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