Планы запросов с фильтрами растровых изображений иногда сложно прочитать. Из статьи 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
:
Также вам может пригодиться второй тест Поля Уайта в « Хеш-соединениях на обнуляемых столбцах ».
Существуют некоторые несоответствия в том, как применяется сокращение строк. Я мог видеть это только в плане, по крайней мере, с тремя таблицами. Однако сокращение ожидаемых строк кажется разумным при правильном распределении данных. Предположим, что объединенный столбец в таблице фактов имеет много повторяющихся значений, которых нет в таблице измерений. Фильтр растровых изображений может удалить эти строки до того, как они достигнут соединения. Для вашего запроса оценка уменьшена до 1. Как строки распределяются по хеш-функции, дает хороший совет:
Исходя из этого, я подозреваю, что у вас есть много повторяющихся значений для Object1.Column21
столбца. Если повторяющиеся столбцы Object4.Column19
не попадают в гистограмму статистики, тогда SQL Server может получить оценку количества элементов очень неправильно.
Я думаю, что вы должны быть обеспокоены тем, что возможно улучшить производительность запроса. Конечно, если запрос соответствует времени отклика или требованиям SLA, дальнейшее изучение может не стоить. Однако, если вы хотите продолжить исследование, есть несколько вещей, которые вы можете сделать (кроме обновления статистики), чтобы получить представление о том, выберет ли оптимизатор запросов лучший план, если у него будет больше информации. Вы можете поместить результаты объединения между Database1.Schema1.Object10
и Database1.Schema1.Object11
во временную таблицу и посмотреть, продолжите ли вы получать соединения с вложенными циклами. Вы можете изменить это объединение на LEFT OUTER JOIN
так, чтобы оптимизатор запросов не уменьшил количество строк на этом шаге. Вы можете добавить MAXDOP 1
подсказку к вашему запросу, чтобы увидеть, что происходит. Вы могли бы использоватьTOP
вместе с производной таблицей, чтобы соединение было последним, или вы можете даже закомментировать соединение из запроса. Надеюсь, этих предложений достаточно, чтобы вы начали.
Что касается элемента подключения в вопросе, крайне маловероятно, что он связан с вашим вопросом. Эта проблема не имеет отношения к плохим оценкам строк. Это связано с условием гонки в параллелизме, которое заставляет слишком много строк обрабатываться в плане запроса за кулисами. Здесь, похоже, ваш запрос не выполняет никакой дополнительной работы.