Який алгоритм стоїть за оператором EXCEPT?


10

Який внутрішній алгоритм роботи оператора Except під обкладинками SQL Server? Чи внутрішньо він займає хеш кожного ряду і порівнює?

Девід Лозінкі провів дослідження, SQL: Найшвидший спосіб вставити нові записи там, де його ще не існує. Він показав, за винятком, що заява є найшвидшим для великих рядків; уважно підходить до наших результатів нижче.

Припущення: я думаю, що лівий приєднання було б найшвидшим, оскільки він порівнює лише 1 стовпець, за винятком, як би, найдовший, оскільки він повинен порівнювати всі стовпці.
За допомогою цих результатів наше мислення за винятком того, що автоматично та внутрішньо займає хеш кожного ряду? Я переглянув, крім плану виконання, і він використовує деякий хеш.

Передумови: Наша команда порівнювала дві таблиці купи. Таблиця A Рядки, які не знаходяться в таблиці B, були вставлені в таблицю B.

У таблицях купи (із застарілої текстової файлової системи) відсутні первинні ключі / путівники / ідентифікатори. Деякі таблиці мали повторювані рядки, тому ми знайшли хеш кожного ряду та видалили дублікати та створили ідентифікатори первинного ключа.

1) Спочатку ми запустили виключно оператор, за винятком (хеш-колонка)

select * from TableA
Except
Select * from TableB,

2) Потім ми провели ліве з'єднання порівняння між двома таблицями на HashRowId

select * 
FROM dbo.TableA A
left join dbo.TableB B
    on A.RowHash =  B.RowHash
where B.Hash is null

напрочуд, Вставка за винятком виписки була найшвидшою.

Результати насправді співпадають з результатами тестування Девіда Лозінксі

введіть тут опис зображення


Відповіді:


10

Який внутрішній алгоритм роботи оператора Except під обкладинками SQL Server?

Я б не сказав, що існує спеціальний внутрішній алгоритм для EXCEPT. Тому A EXCEPT Bщо двигун бере різні (за необхідності) кортежі з A і віднімає рядки, які відповідають B. Не існує спеціальних операторів плану запитів. Відмінність і віднімання реалізуються за допомогою типових операторів, які ви побачили б із сортуванням або з об'єднанням. Вкладені вкладені петлі, об'єднання об'єднань та хеш-з'єднання підтримуються. Щоб показати це, я кину 15 мільйонів рядів у пару купи:

DROP TABLE IF EXISTS dbo.TABLE_1;

CREATE TABLE dbo.TABLE_1 (
    COL1 BIGINT NULL,
    COL2 BIGINT NULL
);

INSERT INTO dbo.TABLE_1 WITH (TABLOCK)
SELECT TOP (15000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), NULL
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);


DROP TABLE IF EXISTS dbo.TABLE_2;

CREATE TABLE dbo.TABLE_2 (
    COL1 BIGINT NULL,
    COL2 BIGINT NULL
);

INSERT INTO dbo.TABLE_2 WITH (TABLOCK)
SELECT TOP (15000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), NULL
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);

Оптимізатор приймає звичайні рішення на основі витрат щодо того, як реалізувати сортування та з'єднання. З двома купами я отримую хеш-з'єднання, як очікувалося. Ви можете природно побачити інші типи приєднання, додавши індекси або змінивши дані в будь-якій таблиці. Нижче я змушую злиття та з'єднання циклу з підказками лише для ілюстративних цілей:

приєднується

Чи внутрішньо він займає хеш кожного ряду і порівнює?

Ні. Він реалізується як будь-яке інше з'єднання. Одна відмінність полягає в тому, що NULL розглядаються як рівні. Це особливий тип порівняння , який ви можете побачити в плані виконання: <Compare CompareOp="IS">. Однак ви можете отримати той самий план з T-SQL, який не включає EXCEPTключове слово. Наприклад, наступний план має такий самий план EXCEPTзапиту, що і запит, що використовує хеш-з'єднання:

SELECT t1.*
FROM
(
    SELECT DISTINCT COL1, COL2
    FROM dbo.TABLE_1
) t1
WHERE NOT EXISTS (
    SELECT 1
    FROM dbo.TABLE_2 t2
    WHERE (t1.COL1 = t2.COL1 OR (t1.COL1 IS NULL AND t2.COL1 IS NULL))
    AND (t1.COL2 = t2.COL2 OR (t1.COL2 IS NULL AND t2.COL2 IS NULL))
);

Відмінність XML від планів виконання лише виявляє поверхневі відмінності навколо псевдонімів і подібних речей. Залишки зонда для приєднання хешу роблять порівняння рядків. Вони однакові для обох запитів:

введіть тут опис зображення

Якщо у вас все ще виникають сумніви, я запустив PerfView з найвищою доступною частотою вибірки, щоб отримати стеки викликів для запиту EXCEPTта запиту без нього. Ось результати поруч:

введіть тут опис зображення

Реальної різниці немає. Стоси викликів там посилання хешування є присутніми через хеш-збіги в плані. Якщо я додаю індекси для природного об'єднання, ви не побачите жодних посилань на хешування в стеках викликів:

введіть тут опис зображення

Будь-яке хешування, що виникає, пов’язане з реалізацією операторів хеш-відповідності. Немає нічого особливого, EXCEPTщо призводить до спеціального внутрішнього хеш-порівняння.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.