Два радикально разных запроса против 4 млн записей выполняются одновременно - один использует грубую силу - PullRequest
4 голосов
/ 01 января 2011

Я использую SQL Server 2008. У меня есть таблица с более чем 3 миллионами записей, которая связана с другой таблицей с миллионом записей.

Я провел несколько дней, экспериментируя с различными способами запроса.эти таблицы.У меня есть два радикально разных запроса, каждый из которых занимает 6 секунд на моем ноутбуке.

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

Вторая получает все возможные совпадения, а затем удаляет неправильные совпадения с помощью запроса EXCEPT, который использует два выделенных индекса для нахождения низкого и высокого совпадений.

Логически, одинбудет ожидать, что грубая сила будет медленной, а индексы быстрой.Не так.И я много экспериментировал с индексами, пока не добился наилучшей скорости.

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

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

Запрос грубой силы:

SELECT      ProductID, [Rank]
FROM        (
            SELECT      p.ProductID, ptr.[Rank], SUM(CASE
                            WHEN p.ParamLo < si.LowMin OR
                            p.ParamHi > si.HiMax THEN 1
                            ELSE 0
                            END) AS Fail
            FROM        dbo.SearchItemsGet(@SearchID, NULL) AS si
                        JOIN dbo.ProductDefs AS pd
            ON          pd.ParamTypeID = si.ParamTypeID
                        JOIN dbo.Params AS p
            ON          p.ProductDefID = pd.ProductDefID
                        JOIN dbo.ProductTypesResultsGet(@SearchID) AS ptr
            ON          ptr.ProductTypeID = pd.ProductTypeID
            WHERE       si.Mode IN (1, 2)
            GROUP BY    p.ProductID, ptr.[Rank]
            ) AS t
WHERE       t.Fail = 0

alt text

Запрос об исключении на основе индекса:

with si AS (
    SELECT      DISTINCT pd.ProductDefID, si.LowMin, si.HiMax
    FROM        dbo.SearchItemsGet(@SearchID, NULL) AS si
                JOIN dbo.ProductDefs AS pd
    ON          pd.ParamTypeID = si.ParamTypeID
                JOIN dbo.ProductTypesResultsGet(@SearchID) AS ptr
    ON          ptr.ProductTypeID = pd.ProductTypeID
    WHERE       si.Mode IN (1, 2)
)
SELECT      p.ProductID
FROM        dbo.Params AS p
            JOIN si
ON          si.ProductDefID = p.ProductDefID
EXCEPT
SELECT      p.ProductID
FROM        dbo.Params AS p
            JOIN si
ON          si.ProductDefID = p.ProductDefID    
WHERE       p.ParamLo < si.LowMin OR p.ParamHi > si.HiMax

alt text

Мой вопрос: какой из планов выглядит более эффективным?Я понимаю, что это может измениться с ростом моих данных.

РЕДАКТИРОВАТЬ:

Я обновил индексы и теперь имею следующий план выполнения для второго запроса:

alt text

Ответы [ 4 ]

3 голосов
/ 01 января 2011

Доверьтесь оптимизатору.

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

Не беспокойтесь о том, как вы могли бы реализовать такой поиск.

В очень редких случаях вам может понадобиться дополнительно заставить запрос использовать определенные индексы (с помощью подсказок), но это, вероятно, <0,1% запросов. </p>


В ваших опубликованных планах ваша "оптимизированная" версия вызывает сканирование по двум индексам вашей (я полагаю) таблицы параметров (PK_Params_1, IX_Params_1). Не видя запросов, трудно понять, почему это происходит, но если вы сравниваете одно и то же сканирование таблицы («грубая сила») и два, легко понять, почему второе не более эффективно.


Думаю, я попробую:

        SELECT      p.ProductID, ptr.[Rank]
        FROM        dbo.SearchItemsGet(@SearchID, NULL) AS si
                    JOIN dbo.ProductDefs AS pd
        ON          pd.ParamTypeID = si.ParamTypeID
                    JOIN dbo.Params AS p
        ON          p.ProductDefID = pd.ProductDefID
                    JOIN dbo.ProductTypesResultsGet(@SearchID) AS ptr
        ON          ptr.ProductTypeID = pd.ProductTypeID

LEFT JOIN Params p_anti
    on p_anti.ProductDefId = pd.ProductDefID and
         (p_anti.ParamLo < si.LowMin or p_anti.ParamHi > si.HiMax)


        WHERE       si.Mode IN (1, 2)

AND p_anti.ProductID is null

        GROUP BY    p.ProductID, ptr.[Rank]

т.е. ввести анти-объединение, которое исключает нежелательные результаты.

1 голос
/ 02 января 2011

Имеет ли 6 секунд на ноутбуке = 0,006 секунд на производственном оборудовании?Часть ваших запросов, которая беспокоит меня, - это сканирование кластерного индекса, показанное в плане запроса.По моему опыту, всякий раз, когда план запроса включает в себя сканирование CI, это означает, что запрос будет работать медленнее только при добавлении данных в таблицу.

Что дают две функции, поскольку, как кажется, они являются причиной таблицысканы?Можно ли сохранить данные в БД и обновить LoMin и HiMax по мере добавления строк.

Глядя на два плана выполнения, ни один из них не очень хорош.Посмотрите, как далеко налево широкие линии.Широкие линии означают, что есть много рядов.Нам нужно уменьшить количество строк ранее в процессе, чтобы мы не работали с такими большими хеш-таблицами, большими сортировками и вложенными циклами.

Кстати, сколько строк в вашем источнике и сколько строк включено внабор результатов?

1 голос
/ 01 января 2011

В SQL Server Management Studio поместите оба запроса в одно и то же окно запросов и получите план запросов для обоих сразу.Он должен определить планы запросов для обоих и дать вам «процент от общего пакета» для каждого.Запрос с меньшим процентом от общего пакета будет более эффективным.

0 голосов
/ 02 января 2011

Спасибо всем за ваш вклад и помощь.

Прочитав то, что вы написали, экспериментируя и покопавшись в плане выполнения, я обнаружил, что ответ переломный момент .

Слишком много записей возвращено для ордера на использование индекса.

См. здесь (Кимберли Трипп).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...