(«Любопытный случай…» раньше был частью нашей двухнедельной рассылки, но мы решили сделать его обычной записью в блоге, чтобы он мог выходить иногда чаще. Он рассказывает о чём-то интересном, с чем столкнулся один из нас при работе с клиентом, проведении тестов или в случайном вопросе от сообщества.)
В одном списке рассылки, на который я подписан, сегодня кто-то поинтересовался возможностью реализации восстановления таблицы в другую базу данных, в которой уже есть свои данные. Это интересное умственное упражнение, поэтому я написал ответ для списка, а потом подумал, что из него получится хорошая запись в блоге.
Восстановление таблицы в другую базу данных, где уже есть данные, на самом деле гораздо сложнее, чем может показаться.
Существует ряд проблем, включая:
- Что, если некоторые идентификаторы единиц распределения, используемые таблицей, уже используются в новой базе данных?
- Что, если некоторые идентификаторы страниц, используемые таблицей, уже используются в новой базе данных?
- Что, если таблица участвует в ограничениях внешнего ключа?
- Что, если таблица содержит данные FILESTREAM, и некоторые GUID FILESTREAM уже используются?
- Пришлось бы извлекать любые пользовательские типы данных и другие метаданные, связанные с таблицей.
Я могу придумать обходные пути для этих проблем, но проблема №2 очень сложна, поскольку потребовала бы изменения:
- Самих местоположений страниц, то есть обновления идентификатора страницы в её заголовке.
- Связей между страницами в двусвязном списке на каждом уровне индекса.
- Связей между страницами в нелистовых страницах индекса.
- Связей страниц в указателях перенаправления кучи и обратных указателей в каждой перенаправленной записи.
- Ссылок на страницы с текстом вне строки.
- Связей внутри текстовых деревьев.
- Содержимого IAM-страниц (карты распределения индекса).
Необходимо было бы вести отображение старых идентификаторов страниц в новые, чтобы можно было применить журнал транзакций, и обновления IAM-страниц были бы особенно трудными, как и операции LOP_MODIFY_COLUMNS (и всё, что касается заголовка страницы), поскольку пришлось бы определять, устанавливается или изменяется ли указатель на страницу.
И всё это нужно делать таким образом, чтобы при прерывании восстановления база данных не становилась неисправимо повреждённой.
Восстановление одной таблицы в новую базу данных было бы намного проще, но всё равно сложным, если вы хотите сократить используемое дисковое пространство, если только не восстанавливать в нечто вроде «разреженного» эквивалента моментального снимка базы данных (иначе, если у вас есть таблица размером, скажем, 10 ГБ, но одна из её страниц находится по смещению 400 ГБ в файле, вам потребовалось бы 400 ГБ места для этого файла).
Суть в том: я бы не стал задерживать дыхание в ожидании реализации любой из этих возможностей в SQL Server!
P.S.: Брент отметил, что решения от сторонних производителей, такие как LiteSpeed, выполняют восстановление одной таблицы в другую базу данных, о чём я не знал — я думал, они делают это только в ту же базу данных. И, судя по документации, они тоже не делают того, о чём я говорил выше, поскольку это было бы неосуществимо. Они извлекают страницы таблицы из резервной копии в отдельное место, а затем используют метаданные таблицы, чтобы по сути «выбрать» из временного местоположения и вставить в новую таблицу SQL Server, что позволяет избежать всей грязной работы с изменением идентификаторов страниц. Довольно круто!

Комментариев нет:
Отправить комментарий