Создание плана выполнения SQL Server 2014 занимает много времени (быстро в старых версиях).

Я столкнулся с проблемой с запросом в SQL Server 2014. При первом запуске этого запроса требуется время для создания плана выполнения.

Странно то, что он отлично работал во всех предыдущих версиях SQL Server (2012, 2008 R2, 2008 и т. д.). Кажется, это связано с уникальным индексом одной из задействованных таблиц в сочетании с определенным количеством подзапросов в основном запросе.

Вот задействованные таблицы в запросе. Я сильно упростил таблицы по сравнению с оригиналами, но проблема осталась. Обратите внимание на уникальное ограничение для таблицы 2, похоже, это и является причиной проблемы. Неважно, уникальное ли это ограничение, уникальный индекс или даже первичный ключ в таблице 2, результат один и тот же.

IF OBJECT_ID('Table2') IS NOT NULL DROP TABLE [Table2]
IF OBJECT_ID('Table1') IS NOT NULL DROP TABLE [Table1]
CREATE TABLE [dbo].[Table1] ( [ReferencedColumn] [int] NOT NULL PRIMARY KEY)
CREATE TABLE [dbo].[Table2] ( [ReferencedColumn] [int] NOT NULL FOREIGN KEY REFERENCES [Table1] ([ReferencedColumn]), [IntColumn] [int] NOT NULL, [AnotherIntColumn] [int] NULL )
CREATE UNIQUE NONCLUSTERED INDEX [IX_Table2] ON [dbo].[Table2] ([ReferencedColumn], [IntColumn])

Если я затем выполню несколько подзапросов из таблицы с индексом в операторе select, для первого выполнения потребуется много времени (более 30 секунд в моих тестах).

SELECT  (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 1 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 2 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 3 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 4 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 5 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 6 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 7 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 8 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 9 ),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 10),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 11),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 12),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 13),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 14),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 15),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 16),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 17),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 18),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 19),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 20),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 21),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 22),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 23),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 24),
        (SELECT F2.IntColumn FROM Table2 F2 WHERE F2.[ReferencedColumn] = F.[ReferencedColumn] AND F2.IntColumn = 25)
FROM    Table1 F

Поскольку в таблицах нет строк, и поскольку запрос выполняется мгновенно после первого запуска, мне кажется, что это должен быть план выполнения, который требует много времени для генерации.

Однако, если вы сделаете одно из перечисленных ниже изменений, план выполнения будет сгенерирован мгновенно.

  • Удалить индекс
  • Удалить УНИКАЛЬНУЮ часть индекса
  • Добавить AnotherIntColumn в индекс
  • Установите уровень совместимости в базе данных на SQL Server 2012.

Стоит отметить, что генерируемый план выполнения одинаков во всех версиях, меняется только время его создания. План включает в себя множество операций "Вычисление скаляра", но я не вижу, в чем может быть проблема, когда тот же план генерируется моментально в 2012/2008.

Я тестировал его только на нескольких экземплярах SQL Server 2014 Enterprise и Web Edition, но предполагаю, что такое же поведение будет происходить и в других выпусках 2014 года.

У меня уже есть несколько способов решения проблемы (изменить индекс, изменить уровень совместимости, переписать запрос), но мне любопытно, почему такое большое падение производительности по сравнению со старыми версиями SQL Server?


person hej2    schedule 03.10.2014    source источник
comment
При первом запуске план запроса не кэшируется, поэтому SQL Server выполняет больше работы для выполнения расчетов/оценок. После первого запуска он использует кешированный план, сгенерированный после первого запуска, поэтому работает намного быстрее.   -  person Tanner    schedule 03.10.2014
comment
Я это понимаю, но почему на SQL Server 2014 это занимает так много времени? Это только в этой версии SQL Server в первый раз долго, в старых версиях нет.   -  person hej2    schedule 03.10.2014


Ответы (1)


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

Ваш запрос - это в значительной степени испытание на пытку. Есть лучшие способы написать это. Но я думаю, что вы выявили ошибку в новом оптимизаторе запросов. Отправьте отчет об ошибке в SQL Connect.

person Code Different    schedule 03.10.2014