Почему оператор конкатенации оценивает меньше строк, чем его входные данные?


20

В следующем фрагменте плана запроса кажется очевидным, что Concatenationдолжна быть оценка строки для оператора ~4.3 billion rowsили сумма оценок строки для двух входных данных.

Тем не менее, оценка ~238 million rowsпроизводится, что приводит к неоптимальным Sort/ Stream Aggregateстратегии , которая переливается сотни ГБ данных базе данных TempDb. Логически непротиворечивая оценка в этом случае привела бы к Hash Aggregateустранению разлива и значительно улучшила бы производительность запросов.

Это ошибка в SQL Server 2014? Существуют ли какие-либо действительные обстоятельства, при которых оценка ниже, чем исходные данные, может быть разумной? Какие обходные пути могут быть доступны?

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

Вот полный план запроса (анонимный). У меня нет доступа sysadmin к этому серверу для предоставления выходных данных QUERYTRACEON 2363или аналогичных флагов трассировки, но я могу получить эти выходные данные от администратора, если они будут полезны.

База данных находится на уровне совместимости 120 и поэтому использует новый SQL Server 2014 Cardinality Estimator.

Статистика обновляется вручную каждый раз при загрузке данных. Учитывая объем данных, мы в настоящее время используем частоту дискретизации по умолчанию. Возможно, что более высокая частота дискретизации (или FULLSCAN) может оказать влияние.

Ответы:


21

Чтобы процитировать Кэмпбелл Фрейзер на этом элементе подключения :

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

Чтобы немного расширить это, я хотел бы объяснить, что первоначальная оценка мощности (выполненная до начала оптимизации на основе затрат) дает более «согласованные» оценки мощности, поскольку обрабатывается все начальное дерево с каждым последующим оценка напрямую зависит от предыдущей.

Во время оптимизации на основе затрат части дерева плана (один или несколько операторов) могут быть изучены и заменены альтернативами, для каждого из которых может потребоваться новая оценка количества элементов . Не существует общего способа сказать, какая оценка будет в целом лучше другой, поэтому вполне возможно в итоге получить окончательный план, который выглядит «противоречивым». Это просто результат сшивания «кусочков планов» для формирования окончательной договоренности.

Все это говорит о том, что в новый оценщик мощности (CE), введенный в SQL Server 2014, были внесены некоторые подробные изменения, которые делают его несколько менее распространенным, чем в случае с оригинальным CE.

Помимо обновления до последнего Накопительного обновления и проверки того, что исправления оптимизатора с 4199 включены, вашими основными вариантами являются попытка изменения статистики / изменений индекса (с учетом предупреждений об отсутствующих индексах) и обновлений или выражение запроса по-другому. Цель состоит в том, чтобы приобрести план, который отображает поведение, которое вам требуется. Это может затем быть заморожено с помощью плана плана, например.

Анонимный план затрудняет оценку деталей, но я бы также внимательно посмотрел на растровые изображения, чтобы увидеть, являются ли они разновидностями «оптимизированный» (Opt_Bitmap) или пост-оптимизационный (Bitmap). Я также с подозрением отношусь к фильтрам.

Если счетчик строк хоть сколько-нибудь точен, это похоже на запрос, который может выиграть от columnstore. Помимо обычных преимуществ, вы можете воспользоваться динамическим выделением памяти для операторов пакетного режима ( может потребоваться флаг трассировки 9389 ).


7

Построение, по общему признанию, достаточно простого тестового стенда на SQL Server 2012 (11.0.6020) позволяет мне воссоздать план с двумя запросами с хеш-соответствием, которые объединяются через UNION ALL. Мой испытательный стенд не отображает неправильную оценку, которую вы видите. Возможно , это является проблемой SQL Server 2014 CE.

Я получил оценку 133,785 строк для запроса, который фактически возвращает 280 строк, однако этого следует ожидать, как мы увидим далее:

IF OBJECT_ID('dbo.Union1') IS NOT NULL
DROP TABLE dbo.Union1;
CREATE TABLE dbo.Union1
(
    Union1_ID INT NOT NULL
        CONSTRAINT PK_Union1
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , Union1_Text VARCHAR(255) NOT NULL
    , Union1_ObjectID INT NOT NULL
);

IF OBJECT_ID('dbo.Union2') IS NOT NULL
DROP TABLE dbo.Union2;
CREATE TABLE dbo.Union2
(
    Union2_ID INT NOT NULL
        CONSTRAINT PK_Union2
        PRIMARY KEY CLUSTERED
        IDENTITY(2,2)
    , Union2_Text VARCHAR(255) NOT NULL
    , Union2_ObjectID INT NOT NULL
);

INSERT INTO dbo.Union1 (Union1_Text, Union1_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;

INSERT INTO dbo.Union2 (Union2_Text, Union2_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;
GO

SELECT *
FROM dbo.Union1 u1
    INNER HASH JOIN sys.objects o ON u1.Union1_ObjectID = o.object_id
UNION ALL
SELECT *
FROM dbo.Union2 u2
    INNER HASH JOIN sys.objects o ON u2.Union2_ObjectID = o.object_id;

Я думаю, что причина заключается в отсутствии статистики для двух объединений, которые в результате UNIONed. SQL Server в большинстве случаев необходимо делать обоснованные предположения относительно избирательности столбцов в случае отсутствия статистики.

У Джо Сака есть интересное прочтение об этом здесь .

Для a UNION ALLможно с уверенностью сказать, что мы увидим точно общее количество строк, возвращаемых каждым компонентом объединения, однако, поскольку SQL Server использует оценки строк для двух компонентов UNION ALL, мы видим, что он добавляет итоговые оценочные строки из обоих запросы для получения оценки для оператора конкатенации.

В моем примере выше предполагаемое количество строк для каждой части UNION ALLсоставляет 66,8927, что при суммировании равно 133,785, что мы видим для примерного количества строк для оператора конкатенации.

Фактический план выполнения для запроса объединения выглядит следующим образом:

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

Вы можете увидеть «примерное» и «фактическое» количество строк. В моем случае добавление «оценочного» числа строк, возвращаемых двумя операторами совпадения хешей, в точности равно количеству, показанному оператором конкатенации.

Я бы попытался получить вывод из трассы 2363 и т. Д., Как рекомендовано в посте Пола Уайта, который вы показываете в своем вопросе. С другой стороны, вы можете попытаться использовать OPTION (QUERYTRACEON 9481)в запросе, чтобы вернуться к версии 70 CE, чтобы увидеть, устраняет ли это проблему.


1
Благодарю. Я определенно видел, что «причина в отсутствии статистики для двух полученных объединений, которые являются UNIONed», оказывают большое влияние на последующие объединения или объединения (которые происходят после UNION). По моему опыту, SQL 2014 справляется с этим лучше, чем SQL 2012. Вот простой тестовый скрипт, который я использовал в прошлом, например: gist.github.com/anonymous/1497112d8b25ab8fb782a04569959c68 Однако я не думаю, что оператору конкатенации потребуется такая же информация о распределении значений, что и объединению может понадобиться.
Джефф Паттерсон

Я согласен с вами, что сцепление не должно нуждаться в статистике для точного выполнения. Он должен просто иметь возможность надежно добавлять оценки входящих строк, чтобы получить точное представление о количестве строк, которые он будет выводить. Как показывает @PaulWhite в своем ответе, это не всегда так. Для меня это может показаться простым, но на самом деле это не так. Я очень рад, что вы задали вопрос так же, как вы, я только хотел бы, чтобы вам не нужно было анонимизировать план - было бы интересно увидеть фактический запрос.
Макс Вернон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.