T-SQL Restore Database на самом деле отложенный 100 проценто
От: VladCore  
Дата: 13.01.25 13:56
Оценка:
Обнаружил такое интересное вредное поведение в такой древней операции как Restore Database

Если сразу после restore сделать
Select count(1) From [Any Table] Where 1=2

то профайлер показывает ровно то количество чтений страниц у этого select сверху, сколько весит таблица. Вместо нуля.
Получается при любом select в том числе такой как выше, sql server вычитывает всю таблицу целиком

При этом для backup сделаны все условия что бы такого не происходило. Бекап полный и ровно один. При бекапе любые транзакции отсутствуют гарантированно в том числе на чтение. Плюс у базы при бекапе включена Simple Recovery Mode еще при создании.

Другими словами в бекапе всё максимально целостное.

Как это можно настроить?
Есть ли что то типа dbcc что бы это убрать?

Ну и самое главное. Если будет запрос который некий index seek будет использовать то этот очередной запрос тоже весь индекс вычитает полностью при первом вызове после restore?
Отредактировано 13.01.2025 14:50 VladCore . Предыдущая версия . Еще …
Отредактировано 13.01.2025 13:59 VladCore . Предыдущая версия .
Отредактировано 13.01.2025 13:57 VladCore . Предыдущая версия .
Re: T-SQL Restore Database на самом деле отложенный 100 проц
От: RushDevion Россия  
Дата: 14.01.25 10:31
Оценка:
VC>то профайлер показывает ровно то количество чтений страниц у этого select сверху, сколько весит таблица. Вместо нуля.
Физических же чтений (physical reads) имеется ввиду? Это ожидаемо.

VC>Получается при любом select в том числе такой как выше, sql server вычитывает всю таблицу целиком

Если в запросе есть count, то да, приходится читать всю таблицу или индекс.

VC>При этом для backup сделаны все условия что бы такого не происходило. Бекап полный и ровно один ...

Непонятно, как это должно помочь.

VC>Ну и самое главное. Если будет запрос который некий index seek будет использовать то этот очередной запрос тоже весь индекс вычитает полностью при первом вызове после restore?

Да. Ну а как по другому-то?
Вот у тебя БД, которую только что восстановили из бэкапа.
MSSQL о ней ничего не знает: нет ни страниц в дисковом кэшэ (т.к. операций чтения еще не было), ни какой-либо статистики по запросам.
И его просят посчитать count(1) на таблице.
Как он будет это делать?
Вот если бы count хранился где-то в метаданных таблицы, тогда все было бы просто — прочитали с диска ровно одну страницу с метаданными и достали count.
Но, увы, в MSSQL count так не хранит.
Поэтому, серверу придется последовательно пройтись по всем страницам таблицы (ну или индекса, если он есть и видится более подходящим) и просуммировать количество строк.
Очевидно, что страницы при этом нужно зачитывать с диска (physical reads), т.к. в кэше их еще нет.

VC>Есть ли что то типа dbcc что бы это убрать?

Прогнать типовые запросы после восстановления из бэкапа.
Это прогреет дисковый кэш.
Отредактировано 14.01.2025 10:33 RushDevion . Предыдущая версия .
Re[2]: T-SQL Restore Database на самом деле отложенный 100 проц
От: BlackEric http://black-eric.lj.ru
Дата: 14.01.25 20:50
Оценка:
Здравствуйте, RushDevion, Вы писали:

VC>>Ну и самое главное. Если будет запрос который некий index seek будет использовать то этот очередной запрос тоже весь индекс вычитает полностью при первом вызове после restore?

RD>Да. Ну а как по другому-то?

В идеале, конечно, планировщик должен понимать, что условие Where 1=2 всегда ложно и возвращать 0, но пока он еще до этого не дорос.
Так что только прогрев кеша после рестора.
https://github.com/BlackEric001
Re: T-SQL Restore Database на самом деле отложенный 100 проценто
От: RushDevion Россия  
Дата: 14.01.25 22:58
Оценка: 41 (1)
Прошу прощения, слона то я и не приметил. Как-то упустил из вида условие `where 1=2`.

Тогда, действительно, поведение странное.
Потому что, должен срабатывать contradiction detection и query plan должен схлопнуться до SELECT <= Constant Scan.

А какая версия MSSQL?

И что будет, если вот так попробовать:
select count(1) From [Any Table] Where 1=2 OPTION(RECOMPILE)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.