Плани запитів з фільтрами растрових зображень іноді можуть бути складними для читання. З статті BOL для потоків переділу (міна акценту):
Оператор Repartition Streams споживає кілька потоків і виробляє кілька потоків записів. Вміст і формат запису не змінюються. Якщо оптимізатор запитів використовує растровий фільтр, кількість рядків у вихідному потоці зменшується.
Крім того, стаття про растрові фільтри також корисна:
Аналізуючи план виконання, що містить фільтрування растрових зображень, важливо зрозуміти, як дані протікають через план і де застосовується фільтрування. Фільтр растрових зображень та оптимізована растрова карта створюються на вхідній частині збірки (таблиці розмірів) хеш-з'єднання; однак фактична фільтрація, як правило, проводиться в операторі паралелізму, який знаходиться на вході зонда (таблиці фактів) хеш-з'єднання. Однак, коли фільтр растрових файлів базується на цілому стовпчику, фільтр може бути застосований безпосередньо до початкової операції таблиці або сканування індексу, а не оператора паралелізму. Ця методика називається рядовою оптимізацією.
Я вважаю, що це ви спостерігаєте за своїм запитом. Можна запропонувати порівняно просту демонстрацію, щоб показати оператору потоків перерозподілу, зменшуючи оцінку кардинальності, навіть коли оператор растрових зображень IN_ROW
суперечить таблиці фактів. Підготовка даних:
create table outer_tbl (ID BIGINT NOT NULL);
INSERT INTO outer_tbl WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;
create table inner_tbl_1 (ID BIGINT NULL);
create table inner_tbl_2 (ID BIGINT NULL);
INSERT INTO inner_tbl_1 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
INSERT INTO inner_tbl_2 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Ось запит, який не слід запускати:
SELECT *
FROM outer_tbl o
INNER JOIN inner_tbl_1 i ON o.ID = i.ID
INNER JOIN inner_tbl_2 i2 ON o.ID = i2.ID
OPTION (HASH JOIN, QUERYTRACEON 9481, QUERYTRACEON 8649);
Я завантажив план . Погляньте на оператора поблизу inner_tbl_2
:
Ви також можете скористатись другим тестом у Hash Joins на стовпчиках Nullable від Paul White.
У застосуванні скорочення рядків є деякі невідповідності. Мені це вдалося побачити лише в плані, принаймні, з трьох таблиць. Однак зменшення очікуваних рядків видається розумним при правильному розподілі даних. Припустимо, що стовпчик, що з'єднався в таблиці фактів, має багато повторених значень, яких немає у таблиці вимірів. Фільтр растрових зображень може усунути ці рядки до того, як вони дістаються до з'єднання. Для вашого запиту оцінка знижується аж до 1. Як розподіляються рядки між хеш-функцією, є хорошим підказом:
Виходячи з цього, я підозрюю, що у вас є багато повторених значень для Object1.Column21
стовпця. Якщо повторних стовпців не буде в гістограмі статистики, Object4.Column19
тоді SQL Server може оцінити кардинальність дуже неправильно.
Я думаю, що ви повинні бути стурбовані тим, що можливо покращити ефективність запиту. Звичайно, якщо запит відповідає часу відповіді або вимогам SLA, то, можливо, не варто додаткового дослідження. Однак, якщо ви хочете дослідити далі, ви можете зробити кілька речей (крім оновлення статистики), щоб зрозуміти, чи оптимізатор запитів обрав би кращий план, якби він мав кращу інформацію. Ви можете помістити результати з'єднання між Database1.Schema1.Object10
та Database1.Schema1.Object11
в темп-таблицю і побачити, чи продовжуєте отримувати вкладені петлі. Ви можете змінити це приєднання до LEFT OUTER JOIN
так, щоб оптимізатор запитів не зменшив кількість рядків на цьому кроці. Ви можете додати MAXDOP 1
підказку до запиту, щоб побачити, що відбувається. Ви можете використовуватиTOP
разом із похідною таблицею, щоб змусити приєднання тривати останнім, або ви навіть можете прокоментувати приєднання з запиту. Сподіваємось, цих пропозицій вистачить для початку роботи.
Що стосується елемента підключення у запитанні, то це вкрай малоймовірно, що воно пов'язане з вашим запитанням. Це питання не пов'язане з поганими оцінками рядків. Це пов'язано з умовою перегонів у паралелізмі, що спричиняє обробку занадто багато рядків у плані запитів поза кадром. Тут схоже, що ваш запит не виконує зайвих робіт.