Чому ці подібні запити використовують різні фази оптимізації (обробка транзакцій проти швидкого плану)?


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 рядків не передбачала змінної кардинальності таблиці. Можна USE PLAN, наприклад, натякнути проблематичну форму плану на CE до 2014 року .

Ви неправі щодо того, що новий елемент 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.