Header RSS-подписка на обновления сайта eMail-подписка на обновления сайта

Версия сервера, версия базы данных и уровни совместимости. Часть 4/4.


366bef3a

  • Другие части статьи:
  • 1
  • 2
  • 3
  • 4
  • вперед »

Итого, что у нас с практической точки зрения? Допустим мы работаем на сервере 2008R2 и нам приносят mdf(а равно bak)-файл с базой версии Z. Тогда развитие сюжета по дальнейшей работе с этой базой может пойти по таким рельсам в зависимости от конкретного значения Z:

  • Z=661 — «подключи-и-работай», версия принесенной нам базы является «нативной», а значит серверу не требуется вообще никакой подготовки;
  • 539<=Z<661— «подключи-через-апгрейд», работа с базой возможна, но при подключении/восстановлении произойдет автоматический апгрейд;
  • Z<539 — «в мусор», версия принесенной нам базы не является совместимой с нашим сервером (слишком старая);
  • Z>661 — «в мусор», версия принесенной нам базы не является совместимой с нашим сервером (слишком новая);

Теперь давайте обратимся еще к одному вопросу отложенному нами в своем время: зачем в структуре DBINFO загрузочной страницы базы ее версия указывается дважды — в поле dbi_createVersion и в поле dbi_version. Думаю, самые внимательные читатели уже и сами все поняли: в поле dbi_createVersion версия проставляется в момент создания базы. После чего значение в этом поле не меняется ни при каких условиях, что бы с исходным mdf-файлом не случилось далее. Иными словами, dbi_createVersion это оригинальная версия базы. Поле же dbi_version отражает текущую версию базы данных и меняет свое значение при каждом новом апгрейде базы данных. Убедимся в этом на практике.

Автор взял для примера файл c:\sqlCMD.ru\North.mdf и сначала посмотрел известные нам байты по смещению 0x12064:

VersionInHEX2

Выводы вполне понятны:

  • текущая версия базы (поле dbi_version) — 0x263=611, т.е. база уже была проапгрейжена на сервере версии 2005;
  • оригинальная версия базы (поле dbi_createVersion) — 0x21b=539, т.е. оригинально база была создана на сервере версии 2000.

Далее автор попробовал подключить эту базу данных к своему тестовому серверу версии 2008R2:

1
2
3
4
USE master
GO
EXEC sp_attach_db @dbname = N'North',@filename1 = N'c:\sqlCMD.ru\North.mdf'
GO

Ответ сервера был таков:

New log file 'c:\sqlCMD.ru\North_log.LDF' was created.
Converting database 'North' from version 611 to the current version 661.
Database 'North' running the upgrade step from version 611 to version 621.
Database 'North' running the upgrade step from version 621 to version 622.
Database 'North' running the upgrade step from version 622 to version 625.
Database 'North' running the upgrade step from version 625 to version 626.
Database 'North' running the upgrade step from version 626 to version 627.
Database 'North' running the upgrade step from version 627 to version 628.
Database 'North' running the upgrade step from version 628 to version 629.
Database 'North' running the upgrade step from version 629 to version 630.
Database 'North' running the upgrade step from version 630 to version 631.
Database 'North' running the upgrade step from version 631 to version 632.
Database 'North' running the upgrade step from version 632 to version 633.
Database 'North' running the upgrade step from version 633 to version 634.
Database 'North' running the upgrade step from version 634 to version 635.
Database 'North' running the upgrade step from version 635 to version 636.
Database 'North' running the upgrade step from version 636 to version 637.
Database 'North' running the upgrade step from version 637 to version 638.
Database 'North' running the upgrade step from version 638 to version 639.
Database 'North' running the upgrade step from version 639 to version 640.
Database 'North' running the upgrade step from version 640 to version 641.
Database 'North' running the upgrade step from version 641 to version 642.
Database 'North' running the upgrade step from version 642 to version 643.
Database 'North' running the upgrade step from version 643 to version 644.
Database 'North' running the upgrade step from version 644 to version 645.
Database 'North' running the upgrade step from version 645 to version 646.
Database 'North' running the upgrade step from version 646 to version 647.
Database 'North' running the upgrade step from version 647 to version 648.
Database 'North' running the upgrade step from version 648 to version 649.
Database 'North' running the upgrade step from version 649 to version 650.
Database 'North' running the upgrade step from version 650 to version 651.
Database 'North' running the upgrade step from version 651 to version 652.
Database 'North' running the upgrade step from version 652 to version 653.
Database 'North' running the upgrade step from version 653 to version 654.
Database 'North' running the upgrade step from version 654 to version 655.
Database 'North' running the upgrade step from version 655 to version 660.
Database 'North' running the upgrade step from version 660 to version 661.

Интересно заметить, что апгрейд не только произошел (что было вполне ожидаемо), но и то, что процесс этот многоступенчатый. SQL Server не может «одним движением» конвертировать базу версии 611 в «нативную» (для SQL Server 2008R2) версию 661, а делает это пошагово. Каждый шаг — подъем версии до следующей ближайшей. И, еще раз обратите внимание, что процесс этот полностью «администраторо-независим». Последний не может ни отказаться от него, ни каким либо образом влиять на его шаги.

Хорошо, что у нас получилось с версиями после такого апгрейда? Смотрим структуру DBINFO:

1
2
dbcc traceon(3604)
dbcc page([North],1,9,3);

получаем:

...
DBINFO @0x0000000012DFA060

dbi_dbid = 6                         dbi_status = 28                      dbi_nextid = 2117582582
dbi_dbname = North                   dbi_maxDbTimestamp = 3100            dbi_version = 661
dbi_createVersion = 539              dbi_ESVersion = 0                    
dbi_nextseqnum = 1900-01-01 00:00:00.000                                  dbi_crdate = 2004-12-13 16:11:08.590
dbi_filegeneration = 2              
dbi_checkptLSN
...

Поле dbi_createVersion не изменилось и стабильно рапортует нам о том, что база была «в девичестве» создана на сервере 2000-й версии. Зато текущая версия (dbi_version) вполне себе поменялась и соответствует нативной версии базы данных на тестовом сервере автора.

Интересный момент заключается вот в чем. До показанного апгрейда некто работал с этой базой на сервере версии 2005, т.к. предыдущее значение поля dbi_version было, как мы видели чуть выше, 611. Что если автор сейчас отключит (detach) базу North на своем сервере (а он, напомню, имеет версию 2008R2) и вернет файл North.mdf «некту»? А произойдет, между прочим, довольно печальное событие: «некто» (если он не запасся резервной копией той же базы) не сможет больше работать со своей же базой! Ведь его 2005-й сервер будет просто «футболить» базу с непонятной ему версией 661, а «даунгрейд», как было пояснено, исключен если не теоретически, то уж практически точно. Теперь вы понимаете, почему автор во второй части статьи назвал неосмотрительное подключение mdf-файла «поломкой» базы данных? Конечно, «поломка» эта весьма условна, и это было сразу отмечено, но тем не менее в определенных сценариях, когда база должна в виде mdf-файла перемещаться между серверами (зачем ей именно перемещаться, а не копироваться, и почему это надо делать именно в формате mdf? автор и сам бы не отказался узнать ответы на эти вопросы...) последствия такой «поломки» могут быть поистине катастрофическими.

Итого, мы приходим к третьему правилу:

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

Интересно так же влияние всех описанных процессов на опцию уровня совместимости. С ней у нас случается вот какая «петрушка»: только что рассмотренный нами апгрейд версии базы данных не влияет на опции этой базы и, таким образом, не меняет значение уровня совместимости, раз последний есть не более чем одна из таких опций. Да, вот так: версия меняется автоматом, а уровень — нет. Скажем — та же самая база North. Когда ее создали на 2000-м сервере она по умолчанию получила уровень совместимости 80. При апгрейде базы на сервере 2005 уровень не менялся. Теперь автор «заапгрейдил» базу вообще до сервера 2008R2! А что у нас со значением уровня? Смотрим:

1
2
3
USE North
GO
SELECT compatibility_level FROM sys.databases WHERE name=DB_NAME()

и видим:

compatibility_level
80

Тонкий момент, который ставил в тупик не одно поколение SQL-администраторов. Не было бы логично поднимать до «родных» не только версию, но и уровень? Тут можно приводить аргументы как за, так и против, но перевесил такой: подключение/восстановление базы не должно менять значение ее внутренних опций. Ну, до некоторой степени — логично.

Тут еще встает интересный вопрос такого сорта: а что будет если мы попытаемся подключить/восстановить базу имеющей «нелегальное» (для данного сервера) значение уровня совместимости? То есть, сценарий примерно такой:

  • создали базу на сервере 7.0 — версия 515, уровень 70;
  • проапгрейдили её на сервере 2005 — версия стала 611, уровень не изменился;
  • вторично апгрейдим ту же базу на сервере 2008R2 — версия будет 661, а уровень?

Да — каким будет уровень? Последний сервер просто не понимает уровня совместимости 70, нет у него такого! Так вот в этом (и только этом!) случае уровень будет автоматически поднят до ближайшего валидного значения, коим в нашем примере будет значение 80. Однако, подчеркну еще раз, если у базы такой уровень совместимости, что целевой сервер его «понимает» — ничего и никогда автоматом сделано не будет, вся настройка базы после её подключения/восстановления ложится на администратора.

Наконец, еще один момент оставленный нами «на закуску», для как раз завершающего раздела статьи. Момент такой: как так получилось, что «нативной» версией баз данных сервера 2008-го (со вторым сервис паком, с «голой» версией этого сервера все в порядке) является число 662, а для версии сервера 2008R2 — 661? Разве это правильно, что «старший» сервер создает и работает с «младшими» базами данных? Это, будем откровенны, не только неправильно, но и приводит вот к таким вот сообщениям при попытке подключить базу сервера R2 к серверу 2008SP2:

The database cannot be opened because it is version 661. This server supports version 662 and earlier.
A downgrade path is not supported.

Причем никакого сочинительства или приблизительности тут нет, это самый что ни на есть прямой «копи-паст» сообщения реального сервера. Да, вот так все «несложно»: «не могу открыть базу версии 661, вот если бы ее версия была 662 или меньше»... Не удивительно, что от подобных сообщений впадают в бешенство даже самые эмоционально устойчивые администраторы — выглядит как издевательство. А случилось вот что.

Как уже неоднократно упоминалось в рамках данной работы в сервере 2005-й версии появились секционированные таблицы. Максимальное число таких секций на одну таблицу долгое время ограничивалось значением 1000 ровно. Вышли все четыре сервис-пака к серверу 2005, вышел сервер 2008-й и первый сервис пак к нему, вышел даже 2008R2... И лишь с выходом второго сервис-пака к версии 2008 указанный лимит был поднят до 15000. Аналогичный подъем максимального числа секций для сервера 2008R2 случился с выходом первого сервис-пака к нему. Если кому-то интересны подробности и технические нюансы именно увеличения максимального числа секций на таблицу, то для них Microsoft подготовил вполне вменяемый документ, который автор и рекомендует вниманию заинтересованных лиц (клик по ссылке приведет к загрузке на ваш диск документа в формате .docx с подробнейшей информацией по теме возросшего числа секций, правда на английском). В контексте же нашего обсуждения нам важен вот какой факт: даже 2008SP2 и 2008R2SP1 не имеют поддержки 15000 секций сразу же по окончании установки соответствующих сервис-паков. Они лишь приобретают возможность включить такую поддержку через системную хранимую процедуру sp_db_increased_partitions. Причем по умолчанию эта поддержка выключена. А структура mdf-файла, как не сложно себе вообразить, будет различной в зависимости от того активирована эта опция или нет. И мы приходим вот к такой маленькой табличке, поясняющей сноску к таблице основной и отвечающей на вопрос в этой самой сноске заданный: как так получается, что некоторые сервера имеют несколько (а точнее — по две) «нативных» версии базы? А вот так:

Вариации native версий баз данных для серверов версий 2008SP2 и 2008R2SP1
Версия сервера Native версия базы, если поддержка 15000 секций выключена Native версия базы, если поддержка 15000 секций включена
SQL Server 2008 with SP2 655 662
SQL Server 2008R2 with SP1 661 663

Видите? Для одного и того же сервера версия базы меняется в зависимости от включения/выключения опции! Если она выключена база имеет ту же версию что и на сервере без сервис пака, если включена — большую версию. Ну а дальнейшее понятно: если мы на 2008SP2 создали базу, включили для нее обсуждаемую опцию, а затем сделали такой базе detach, то получившийся файл ни в коем случае нельзя позволять подключать к серверу 2008R2 без сервис-паков — он не сможет с ней работать! Добились этого поднятием номера версии такой базы над номером версии базы более старшего сервера. И с этой стороны ситуацию закрыли: «голый» 2008R2 будет исправно сообщать, что мы ему подсовываем базу версии 662, а он, де, только с 661 и ниже умеет работать... Но вот обратную ситуацию не продумали, или, как минимум, продумали не до конца. Конечно же, сервер более младшей версии будь он хоть с каким сервис-паком никогда не «примет» никаких баз изначально «рожденных» на серверах старшей версии. А поэтому следовало исправить сообщение для 2008SP2 что бы тот сообщал о поддержке баз версий «662, 655 и меньших 655». То есть «вычленить» из сообщения приведенного чуть выше базы сервера 2008R2, с номером версии 661. Вот тогда бы довольные граждане-администраторы бодро расходились бы по форумам в поисках решения проблемы, где им бы незамедлительно сообщали простую вещь: базы со старшего сервера никогда не «поднять» на сервере младшем, точка. А поскольку исходное сообщение править поленились, то и начались крики-вопли на тему «это вообще что такое??».

По счастью, читателям блога sqlCMD.ru ломать голову над подобными «ребусами» не придется, автору хотелось бы верить, что проблема и причины ее породившие изложены достаточно понятно. Так же будет не лишним напоминание, что часть информации данной статьи, по указанным ранее причинам, не является официально подтвержденной, а есть лишь результат исследований и экспериментов различных энтузиастов SQL-сообщества, в том числе и автора данных строк. А поэтому указания на неточности и помарки в такой информации будут с благодарностью приняты автором и незамедлительно внесены им в текст данной монографии.

Автор традиционно благодарит всех своих читателей за внимание к его блогу, за письма и комментарии к статьям и желает всему SQL-сообществу быстрых запросов и согласованности в версиях баз данных и серверов. :) До новых встреч на блоге, увидимся, пока!

  • Другие части статьи:
  • 1
  • 2
  • 3
  • 4
  • вперед »