SQL 2000 UNION ALL разрушает оптимизацию запросов

У меня есть хранимая процедура, которая нормально работает менее чем за секунду. Пользователям нужны были данные из другой таблицы в этом запросе, поэтому я объединил эти данные с UNION ALL и кучей фиктивных столбцов, отсутствующих в новой таблице.

Он отлично работал при тестировании, но когда мы развернули его на сервере SQL 2000, он начал получать тайм-ауты. Старый запрос выполняется менее чем за секунду, а два новых запроса выполняются менее чем за секунду, но когда они объединяются с помощью UNION ALL, время запроса истекает.

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

CREATE PROCEDURE dbo.SearchHistory
(
    @Criteria1 bigint,
    @Criteria2 int,
    @Criteria3 varchar(10)
)
AS
BEGIN
    -- Part 1
    SELECT
        A,
        NULL AS B,
        0 AS C,
        D
    FROM TableA
    WHERE @Criteria1 IS NULL
    AND @Criteria3 IS NULL
    AND (A = @Criteria2 OR @Criteria2 IS NULL)

UNION ALL

    -- Part 2
    SELECT
        A,
        NULL AS B,
        0 AS C,
        E
    FROM TableA
    WHERE @Criteria1 IS NULL
    AND @Criteria3 IS NULL
    AND (A = @Criteria2 OR @Criteria2 IS NULL)

UNION ALL

    -- Part 3
    SELECT
        A,
        B,
        C,
        D
    FROM TableB
    WHERE (F = @Criteria1 OR @Criteria1 IS NULL)
    AND (A = @Criteria2 OR @Criteria2 IS NULL)
    AND (G = @Criteria3 OR @Criteria3 IS NULL)
END

В приведенном выше примере @Criteria1 не равен нулю, поэтому части 1 и 2 возвращают 0 строк, а часть 3 возвращает только 3 строки. Но если я закомментирую части 1 и 2, она сразу же завершится; если я оставлю их, я получу тайм-аут.

Как убедить SQL Server не возиться со своим планом выполнения в такой ситуации?


person Bryce Wagner    schedule 18.05.2011    source источник
comment
Какой план выполнения он дает вам с UNION ALL? Кроме того, что, если вы просто вставите @table_variable в 3 отдельных утверждения и выберете из них в конце?   -  person Martin Smith    schedule 19.05.2011
comment
(Я думаю, что есть синтаксическая ошибка из-за отсутствия обязательной запятой в списке выбора; это фактический код?)   -  person    schedule 19.05.2011
comment
Помогает ли изменение процедуры на CREATE PROCEDURE dbo.SearchHistory WITH RECOMPILE (...?   -  person Biff MaGriff    schedule 19.05.2011
comment
Кроме того, попробуйте погуглить что-то под названием "обнюхивание параметров" - у меня такое чувство, что план выполнения испорчен...   -  person M.R.    schedule 19.05.2011


Ответы (2)


Я думаю, что ваша проблема связана с обнюхиванием параметров SQL Server.

http://elegantcode.com/2008/05/17/sql-parameter-sniffing-and-what-to-do-about-it/

http://blogs.msdn.com/b/queryoptteam/archive/2006/03/31/565991.aspx

Я сталкивался с этим несколько раз. Есть несколько способов обойти это. Например. используйте WITH RECOMPILE, как предложил @Biff MaGriff. Самый простой способ исправить это — преобразовать все ваши входные параметры в локальные параметры и использовать локальные.

person Blazes    schedule 19.05.2011
comment
WITH RECOMPILE истечет время ожидания всех запросов, а не только там, где @Criteria1 не равен NULL. Я еще не пробовал локальные переменные, слишком много других вещей происходит, но я все еще собираюсь попробовать. - person Bryce Wagner; 24.05.2011

На этот вопрос нельзя ответить, не увидев планы выполнения (пожалуйста, разместите их в виде изображений, по одному для каждой части и одно для запроса на объединение). Обходной путь — использовать временную таблицу, в которую вы вставляете части по отдельности. Однако лучшим решением было бы исправить запрос в первую очередь.

person usr    schedule 21.05.2011