Сортировать разливы в базу данных tempdb, но предполагаемые строки равны фактическим строкам

14

На SQL Server 2016 с пакетом обновления 2 (SP2) с максимальной памятью, установленной на 25 ГБ, у нас есть запрос, который выполняется примерно 80 раз в минуту. Запрос проливает около 4000 страниц в базу данных tempdb. Это приводит к большому количеству операций ввода-вывода на диске в базе данных tempdb.

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

Я провел некоторое тестирование и выполнил следующие запросы к Tempdb:

select id --uniqueidentifier
from SortProblem
where [status] ='A'
order by SequenceNumber asc
option (maxdop 1)

Но если я выберу другой столбец, разливов не произойдет:

select startdate --datetime
from SortProblem
where [status] ='A'
order by SequenceNumber asc 
option (maxdop 1)

Поэтому я попытался «увеличить» размер столбца id:

select CONVERT(nvarchar(512),id)
from SortProblem
where [status] ='A'
order by SequenceNumber asc 
option (maxdop 1)

Тогда также никакого разлива не происходит.

Почему уникальный идентификатор не распространяется на базу данных tempdb, а на столбец времени данных нет? Когда я удаляю около 20000 записей, то при выборе столбца id также не происходит разливов.

С помощью следующего скрипта вы можете воспроизвести проблему:

CREATE TABLE SortProblem
  (
     id             UNIQUEIDENTIFIER,
     startdate      DATETIME,
     sequencenumber BIGINT,
     status         VARCHAR(50),
     PRIMARY KEY CLUSTERED(id)
  )

SET nocount ON;

WITH nums(num)
     AS (SELECT TOP 103000 ROW_NUMBER()
                             OVER (
                               ORDER BY 1/0)
         FROM   sys.all_objects o1,
                sys.all_objects o2)
INSERT INTO SortProblem
SELECT newid(),
       DATEADD(millisecond, num, GETDATE()),
       num,
       CASE
         WHEN num <= 100000 THEN 'A'
         WHEN num <= 101000 THEN 'B'
         WHEN num <= 102000 THEN 'C'
         WHEN num <= 103000 THEN 'D'
       END
FROM   nums

CREATE NONCLUSTERED INDEX [IX_Status]
  ON [dbo].[SortProblem]([status] ASC)
  INCLUDE ([sequencenumber]) 
Фредерик Вандерхаген
источник

Ответы:

14

Включить флаг трассировки 7470.

ИСПРАВЛЕНИЕ: Оператор сортировки выливается в базу данных tempdb в SQL Server 2012 или SQL Server 2014, когда предполагаемое количество строк и размер строки указаны правильно

Как я написал в ответ на вопрос о плане запроса :

Этот флаг трассировки исправляет недосмотр в расчете. Это довольно безопасно для использования, и по моему мнению должно быть включено по умолчанию. Изменение защищено флагом трассировки, чтобы избежать непредвиденных изменений плана.

Пол Уайт 9
источник