Почему эти похожие запросы используют разные фазы оптимизации (обработка транзакций и быстрый план)?


12

Пример кода в этом элементе подключения

Показывает ошибку где

SELECT COUNT(*)
FROM   dbo.my_splitter_1('2') L1
       INNER JOIN dbo.my_splitter_1('') L2
         ON L1.csv_item = L2.csv_item

Возвращает правильные результаты. Но следующее возвращает неверные результаты (в 2014 году с использованием нового Оценщика мощности)

SELECT
    (SELECT COUNT(*)
    FROM dbo.my_splitter_1('2') L1
     INNER JOIN dbo.my_splitter_1('') L2
        ON L1.csv_item = L2.csv_item)

Так как он некорректно загружает результаты для L2 в общую катушку подвыражения, то воспроизводит результат этого для результата L1.

Мне было любопытно, почему разница в поведении между двумя запросами. Флаг трассировки 8675 показывает, что работает тот, кто работает, search(0) - transaction processingи тот, кто не работает search(1) - quick plan.

Поэтому я предполагаю, что доступность дополнительных правил преобразования лежит в основе различий в поведении (отключение BuildGbApply или GenGbApplySimple, кажется, исправляет это).

Но почему два плана для этих очень похожих запросов сталкиваются с разными фазами оптимизации? Из того, что я прочитал, search (0)требуется как минимум три таблицы, и это условие, безусловно, не выполняется в первом примере.

Ответы:


7

Каждый этап имеет начальные условия. «Наличие как минимум трех ссылок на таблицы» - это одно из начальных условий, о котором мы говорим, когда приводим простые примеры, но не единственное.

Как правило, только базовые объединения и объединения разрешены для входа в поиск 0; скалярные подзапросы, полусоединения и т. д. препятствуют входу в поиск 0. Этот этап действительно предназначен для очень распространенных форм запросов типа OLTP. Правила, необходимые для изучения менее распространенных вещей, просто не включены. Ваш пример запроса имеет скалярный подзапрос, поэтому он не может войти.

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

Баг с GenGbApplySimpleнекрасивым. Эта форма плана всегда была возможной, но отклонялась по соображениям стоимости до тех пор, пока не вступило в силу изменение 100-рядной предполагаемой мощности таблицы. Можно форсировать проблемную форму плана в CE до 2014 года с помощьюUSE PLAN подсказки.

Вы правы в том, что новый элемент Connect является той же проблемой, о которой сообщалось ранее .

Чтобы привести пример, следующий запрос подходит для поиска 0:

DECLARE @T AS table (c1 integer NULL);

SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY U.c1) 
FROM 
(
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
) AS U;

Небольшое изменение для включения скалярного подзапроса означает, что он сразу переходит к поиску 1:

DECLARE @T AS table (c1 integer NULL);

SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -- Changed!
FROM 
(
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
) AS U;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.