Това е втората статия от поредицата, посветена на регистъра на транзакциите на SQL Server и неговите специфики. Тук ще разгледаме подробностите за записа в дневника.
Регистрационни записи
Регистрационните записи са ядрото на механизмите за регистриране и възстановяване. Записът в дневника описва една промяна в база данни. По този начин всяка промяна в база данни има регистрационен запис или записи в дневника, които помагат да се опише тази конкретна промяна. Въпреки че не е необходимо да разбирате подробности за записите в регистрационния файл, за да разберете какво се случва с регистрирането и възстановяването, тези подробности са изключително интересни.
Регистрационният запис има уникален регистрационен номер, който дефинирахме в първата статия. Поредният номер на дневника позволява записът в дневника да бъде намерен в дневника на транзакциите. В допълнение, всяка страница с файл с данни има LSN в заглавката на страницата, който идентифицира най-новия регистрационен запис, чиято промяна е отразена на страницата. Това е от решаващо значение за възстановяването при срив.
Регистрационните записи за едновременни транзакции се смесват в дневника на транзакциите в зависимост от това кога са възникнали във времето. Регистрационните записи се съхраняват в регистрационни блокове в буферния пул, докато не бъдат изхвърлени на диск.
Няма нерегистрирани операции в потребителски или системни бази данни. Има обаче изключение:в tempdb операциите за съхранение на версии и работни файлове не се регистрират. Регистрационните записи никога не се движат в регистъра на транзакциите.
Какво е вътре в регистрационен запис?
Информацията в регистрационния запис позволява той да бъде повторен (превъртане напред) или отменен (връщане назад). Тази способност на регистрационен запис е от решаващо значение за позволяване на транзакциите да бъдат връщани назад и за работа по възстановяване. Регистрационните записи съдържат много полета, в зависимост от типа на дневника. Има някои общи полета между всички записи, включително:
- Типът на регистрационния запис
- започнете запис в регистъра на транзакциите
- запис в регистъра на транзакциите за записване
- разпределяне на страница чрез промяна на растерното изображение за разпределение
- вмъкване на ред
- изтриване на ред
- промяна на ред
- Контекстът на регистрационния запис , ако има.
- Идентификационният номер на транзакцията, част от който е записът в регистрационния файл Ако някой. Повечето регистрационни записи са част от транзакции.
- Дължината на записа в дневника . Регистрационните записи обикновено имат фиксиран размер и след това в зависимост от количеството данни, които са в дневника, ще има и променлива част.
- LSN на предишния регистрационен запис в същата транзакция . Ако някой. LSN е по същество указател към предишния запис в дневника на транзакциите, който е генериран от тази конкретна транзакция. Тази верига от предишни LSN позволява връщането на тази конкретна транзакция, тъй като връщането се извършва в обратен ред, започвайки от най-новия запис в регистрационния файл.
- Обемът на запазеното пространство в регистрационните файлове в случай че регистрационният запис трябва да бъде отменен.
Резервиране на място в регистрационния файл
Всеки регистрационен запис, който се генерира в предната част на транзакцията, трябва да запази свободно място в регистъра на транзакциите, за да позволи връщането на записа в дневника, без да се налага дневникът на транзакциите да нараства.
Механизмът за резервиране на пространство в регистрационни файлове е много консервативен, винаги запазва достатъчно място и обикновено повече, само в случай, че възникне неочаквана ситуация. Например, актуализация или изтриване на компресирана таблица ще запази повече място от подобна актуализация или изтриване в некомпресирана таблица. Това се случва, защото връщането назад на актуализацията на компресираната таблица може да се наложи да се справи с това, че актуализираният ред вече не е на компресирана страница и така ще трябва да запише колони с пълна ширина в регистрационния запис вместо компресирани данни.
Типове записи на регистрационни файлове
Има много видове регистрационни записи, включително:
- LOP_FORMAT_PAGE Операцията за форматиране на страницата – е мястото, където страницата е била форматирана, което означава, че е създадена заглавката. Регистрационният запис ще регистрира поне заглавката на страницата и евентуално още малко съдържание на страницата, ако страницата е създадена и попълнена като част от операция като изграждане на индекс или повторно изграждане)
- LOP_MODIFY_ROW Тази операция променя малка част от съществуващи данни.
- LOP_SET_BITS Този запис в регистрационния файл се отнася за битови карти за разпределение.
- LOP_INSERT_ROWS и LOP_DELETE_ROWS
- LOP_SET_FREE_SPACE Отнася се за PFS – разпределението на растерната карта, която следи статусите на разпределение на страниците.
Всички регистрационни записи, които ще направят промяна в страница с данни или индексна страница в табличен индекс, включват :
- Идентификационният номер на разпределителната единица
- Идентификационният номер на страницата и идентификаторът на слота на записа на страницата, който по същество е базиран на нула идентификатор на записа на данните или индексния запис на страницата.
- Последното изображение или изображението преди и след изображението на променените данни. Може да има няколко набора от тях в един запис в дневника. Остатъчните изображения позволяват повторение. Изображенията преди позволяват отмяна.
Регистриране на заключване
Някои регистрационни записи включват растерна карта, чиито ключалки са били задържани, когато е настъпила описаната промяна. Растерното изображение съдържа:
- Брой на броя ключалки.
- Какъв тип и режим на заключване – например заключване на страница в режим X.
- Какво е включено заключване
По време на възстановяването при срив и при дублиране на база данни/група за наличност тези ключалки ще бъдат придобити за всички регистрационни записи, които ще бъдат отменени. Това позволява функцията за бързо възстановяване в Enterprise Edition от SQL Server 2005 нататък.
Регистрационни записи в транзакции
Всички транзакции генерират поне три регистрационни записа, винаги в следната последователност:
- LOP_BEGIN_XACT – включва информация като SPID, име на транзакцията и начален час. Всички транзакции, стартирани от SQL Server, имат имена за описване на операцията (напр. AllocFirstPage, DROPOBJ)
- Други записи за транзакцията.
- LOP_COMMIT_XACT – ако транзакцията се ангажира.
- LOP_ABORT_XACT – ако транзакцията се върне назад.
И двете включват крайния час за транзакцията.
Регистрационните записи в транзакция се свързват обратно чрез LSN. Това означава, че следващият регистрационен запис, който се генерира за транзакция, има LSN на предишния регистрационен запис, който е генериран за тази конкретна транзакция. Това позволява на транзакцията да бъде върната правилно. Някои записи в дневника изобщо не са транзакционни, включително:
- Промени в свободното пространство на PFS (невъзможно за съгласуване с други транзакции)
- Диференциални промени в растерното изображение (само еднопосочна промяна)
Проверка на регистрационните записи
Има два начина за разглеждане на регистрационните записи. Можете да използвате функцията DBCC LOGINFO, но се препоръчва да използвате функцията fn_dblog с таблична стойност. Има изключително прост синтаксис:
SELECT * FROM fn_dblog (startLSN, endLSN); GO
Това е изключително мощна функция, защото:
- връща табличен набор от резултати, който може лесно да се управлява.
- позволява използването на сложни предикати.
- сканира целия регистър на транзакциите в активната част на регистрационния файл, от началото на най-старата незаети транзакция до най-новия запис в регистъра. Това може да бъде отменено с помощта на флаг за проследяване 2537
Полетата startLSN и endLSN обикновено се предават като NULL
Ето демонстрацията:
USE DBTest2014 GO SET NOCOUNT ON; GO --Set the SIMPLE recovery mode with no auto-stats -- to avoid unwanted log records ALTER DATABASE DBTest2014 SET RECOVERY SIMPLE; ALTER DATABASE DBTest2014 SET AUTO_CREATE_STATISTICS OFF; CREATE TABLE [TEST_TABLE] ([C1] INT, [C2] INT, [C3] INT); INSERT INTO [TEST_TABLE] VALUES (1,1,1); GO --Clear out the log CHECKPOINT; GO -- Implicit transaction INSERT INTO [TEST_TABLE] VALUES (2,2,2); GO SELECT * FROM fn_dblog(null, null); GO
Ето съкратения набор от резултати. Всъщност fn_dblog връща разнообразие от различни записи като дължина на записа в регистрационния файл, битове на флаг, резерв на дневник, AllocUnitId, PageID, SlotID, LSN на предишна страница и други.
Промяна на съдържанието на ред
Промените в регистрационните файлове се регистрират по два начина:като LOP_MODIFY_ROW или LOP_MODIFY_COLUMNS запис. Без значение кой метод се използва, той ще регистрира байтовете, които действително се променят. Например, промяната на INT стойност от 1 на 24 регистрира само един байт промяна, тъй като другите три нулеви байта не са се променили. SQL Server ще използва LOP_MODIFY_ROW регистрационен запис, ако има една част от реда, който се актуализира. Частта се дефинира, както следва:всяка колона с променлива дължина в реда е „част“ и цялата област с фиксирана ширина на реда е „порция“, дори ако множество колони се актуализират, но само ако байтовете са актуализираните са на 16 байта или по-малко един от друг в реда.
LOP_MODIFY_ROW съдържа:
- Преди изображение
- След изображение
- Индексни ключови колони, ако е приложимо
- Заключване на растерна карта
LOP_MODIFY_COLUMNS съдържа:
- Масив от измествания преди и след
- Масив с дължина
- Индексни ключови колони, ако е приложимо
- Заключване на растерна карта
- Двойки изображения преди и след
Регистрационни записи за компенсации
Това е специален вид регистрационни записи, които се използват за подпомагане на връщане на транзакция. Когато транзакция се върне назад, промяната, описана от всеки запис в дневника в транзакцията, трябва да бъде отменена в базата данни. Отмяната започва с най-новия регистрационен запис за транзакцията и следва предишните LSN връзки до LOP_BEGIN_XACT регистрационния запис. За всеки запис в дневника:
- Извършете „анти-операцията“, която ще отмени ефекта от записа в дневника
- Генерирайте регистрационен запис, като го маркирате като КОМПЕНСАЦИОНЕН регистрационен запис, тъй като той компенсира регистрационния запис в предната част на транзакцията.
- Предишният LSN запис на COMPENSATION регистрационния запис сочи към регистрационния запис преди този, за който се компенсира. Това по същество води до това, че записът в дневника вече не е част от веригата от регистрационни записи за транзакцията.
- Запазеното пространство в регистъра за записа в дневника е освободено
Записите в регистъра на КОМПЕНСАЦИЯ не могат да бъдат отменени, а само преработени.
Отмяна на транзакция
Ето графично представяне на това, което се случва, когато транзакция се върне назад:
Нека разгледаме следния код:
USE DBTest2014 GO SET NOCOUNT ON; GO ALTER DATABASE DBTest2014 SET RECOVERY SIMPLE; ALTER DATABASE DBTest2014 SET AUTO_CREATE_STATISTICS OFF; CREATE TABLE [TEST_TABLE] ([C1] INT, [C2] INT, [C3] INT); INSERT INTO [TEST_TABLE] VALUES (1,1,1); INSERT INTO [TEST_TABLE] VALUES (2,2,2); GO --Clear out the log CHECKPOINT; GO -- Explicit transaction to insert a new record BEGIN TRAN; INSERT INTO [TEST_TABLE] VALUES (3,3,3); GO SELECT * FROM fn_dblog(null, null); GO --Roll it back ROLLBACK TRAN; GO SELECT * FROM fn_dblog(null, null);
Тук можем да видим специален регистрационен запис с описание „КОМПЕНСАЦИЯ“
Ако погледнем предишния LSN, можем да видим, че LOP_INSERT_ROWS което направихме, връзки към …0f40:0001 и това е транзакцията BEGIN, защото предната част на транзакцията се свързва обратно към предишния запис в дневника. LOP_DELETE_ROW Записът в регистъра на компенсациите не се свързва обратно към запис, за който компенсира – той се свързва към него (към записа в дневника на транзакциите BEGIN).
Така че DELEDE компенсира INSERT и го премахна от списъка с регистрационни записи. ВLOP_ABORT_XACT е сигналът, че транзакцията е приключила с връщане назад. Също така можете да видите това LOP_ABORT_XACT връзки към LOP_BEGIN_XACT.
Когато правим запис на компенсационен дневник, резервацията на място в регистрационния файл намалява [-74]. Така че всъщност връща малко пространство, което е запазено за предната част на транзакцията (LOP_INSERT_ROWS [178]). Както можете да видите, системата за резервиране на място в регистрационните файлове е много консервативна — INSERT запазва повече място, отколкото DELETE връща.
Отмяна и диференциално архивиране
Ако една база данни има пълно архивиране, тогава транзакция актуализира 100 000 записа, но транзакцията се връща назад, защо диференциалното архивиране прави толкова много данни? Със сигурност връщането на транзакцията означава, че нищо не се е променило? Частта от пъзела, която липсва тук, е, че връщането назад на транзакция не изтрива всички промени, направени от транзакцията. Както видяхме, връщането трябва да генерира записи в регистъра на компенсациите, тъй като връщането трябва да генерира други промени, за да компенсира предната част от транзакцията. Заглавките на всички засегнати страници са променени поне два пъти. Един за актуализиране на LSN на страницата за предната част на транзакцията и веднъж за актуализиране на LSN на страницата за частта за отмяна на транзакцията. И в двата случая актуализацията ще доведе до маркировката на степента като променена в диференциалното растерно изображение. Не го интересува каква е била промяната, просто нещо в степен се е променило. Няма начин да изключите тези екстенти от диференциалното архивиране.
Резюме
В тази статия разгледахме регистрационните записи. Регистрационните записи са ядрото на механизмите за регистриране и възстановяване. Всяка промяна в база данни има регистрационен запис, свързан с нея. Всеки запис в дневника описва малка промяна. Голяма промяна има множество регистрационни записи в една транзакция. Има много различни видове регистрационни записи и ние разгледахме няколко от тях.
Регистърът на транзакциите е по същество огромна тема и няколко статии не са достатъчни, за да разкрият всички подробности. Така че, ако искате да получите по-подробна информация, бих ви предложил да прочетете следната книга:SQL Server Transaction Log Management от Тони Дейвис и Гейл Шоу и тази статия:Управление на журнала на транзакциите.
Прочетете също:
Потопете се в дневника на транзакциите на SQL Server — част 1
Потопете се в дневника на транзакциите на SQL Server — част 2