У нас есть приложение, которое записывает журналы в таблицах Azure SQL. Структура таблицы следующая.Как уменьшить использование журнала транзакций SQL Server
CREATE TABLE [dbo].[xyz_event_history]
(
[event_history_id] [uniqueidentifier] NOT NULL,
[event_date_time] [datetime] NOT NULL,
[instance_id] [uniqueidentifier] NOT NULL,
[scheduled_task_id] [int] NOT NULL,
[scheduled_start_time] [datetime] NULL,
[actual_start_time] [datetime] NULL,
[actual_end_time] [datetime] NULL,
[status] [int] NOT NULL,
[log] [nvarchar](max) NULL,
CONSTRAINT [PK__crg_scheduler_event_history] PRIMARY KEY NONCLUSTERED
(
[event_history_id] ASC
)
)
Таблица хранится в виде кластерного индекса по scheduled_task_id
столбца (не уникальный).
CREATE CLUSTERED INDEX [IDX__xyz_event_history__scheduled_task_id] ON [dbo].[xyz_event_history]
(
[scheduled_task_id] ASC
)
The event_history_id
, сформированного приложением, это случайное (не последовательное) GUID. Приложение создает, обновляет и удаляет старые объекты из таблицы. Столбец log
обычно содержит 2-10 КБ данных, но в некоторых случаях он может вырасти до 5-10 МБ. К элементам обычно обращаются PK (event_history_id
), а наиболее часто используемый порядок сортировки - event_date_time desc
.
Проблема, которую мы видим после того, как мы понизили уровень производительности для Azure SQL до «S3» (100 DTU), преодолевает ограничения скорости транзакций. Это можно отчетливо увидеть в таблице sys.dm_exec_requests - будут записи с типом ожидания LOG_RATE_GOVERNOR
(msdn).
Происходит, когда БД ожидает ввода квоты в журнал.
операции я заметил, что вызывают большое влияние на скорость журнала являются делеции xyz_event_history
и обновления в log
колонке. Обновления сделаны следующим образом.
UPDATE xyz_event_history
SET [log] = COALESCE([log], '') + @log_to_append
WHERE event_history_id = @id
модель восстановления для баз данных SQL Azure является FULL
и не может быть изменена.
Вот статистика физического индекса - есть много страниц, которые пересекали 8 К за пределы строки.
TableName AllocUnitTp PgCt AvgPgSpcUsed RcdCt MinRcdSz MaxRcdSz xyz_event_history IN_ROW_DATA 4145 47.6372868791698 43771 102 7864 xyz_event_history IN_ROW_DATA 59 18.1995058067705 4145 11 19 xyz_event_history IN_ROW_DATA 4 3.75277983691623 59 11 19 xyz_event_history IN_ROW_DATA 1 0.914257474672597 4 11 19 xyz_event_history LOB_DATA 168191 97.592290585619 169479 38 8068 xyz_event_history IN_ROW_DATA 7062 3.65090190264393 43771 38 46 xyz_event_history IN_ROW_DATA 99 22.0080800593032 7062 23 23 xyz_event_history IN_ROW_DATA 1 30.5534964170991 99 23 23 xyz_event_history IN_ROW_DATA 2339 9.15620212503089 43771 16 38 xyz_event_history IN_ROW_DATA 96 8.70488015814184 2339 27 27 xyz_event_history IN_ROW_DATA 1 34.3711391153941 96 27 27 xyz_event_history IN_ROW_DATA 1054 26.5034840622683 43771 28 50 xyz_event_history IN_ROW_DATA 139 3.81632073140598 1054 39 39 xyz_event_history IN_ROW_DATA 1 70.3854707190511 139 39 39
- Есть ли способ, чтобы уменьшить использование журнала транзакций?
- Как SQL Server регистрирует транзакции, как в примере выше? Это просто «старое» плюс «новое» значение? (Что бы предположительно сделать добавление маленькие кусочки данных часто весьма неэффективным с точки зрения размера журнала транзакций)
UPDATE (апрель, 20): Я сделал некоторые эксперименты с предложениями в ответах и был впечатлен разница в том, что INSERT
вместо UPDATE
делает.
согласно следующей MSDN статьи о журнальной внутренних транзакциях SQL сервера (https://technet.microsoft.com/en-us/library/jj835093(v=sql.110).aspx):
Входа запись для модификации данных записи либо логическая операция выполнена или они записывают до и после изображений изменённых данных , Перед снимком - копия данных перед выполнением операции ; последующее изображение является копией данных после операции .
Это автоматически делает сценарий с UPDATE ... SET X = X + 'more'
крайне неэффективной с точки зрения использования журнала транзакций - это требует «до образа» захвата.
Я создал простой тестовый набор, чтобы протестировать оригинальный способ добавления данных в столбец «log» в сравнении с тем, как мы просто вставляем новую часть данных в новую таблицу. Результаты, которые я получил довольно удивительно (на самом деле, я не слишком опытен с парнем SQL Server).
Тест прост: 5'000 раз добавить 1'024 символа длинной части журнала - всего 5 МБ текста в результате (не так уж плохо, как можно было бы подумать).
FULL recovery mode, SQL Server 2014, Windows 10, SSD
UPDATE INSERT Duration 07:48 (!) 00:02 Data file grow ~8MB ~8MB Tran. Log grow ~218MB (!) 0MB (why?!)
Всего 5000 обновления, которые добавляют 1KB данных может болтаться SQL Server в течение 8 минут (вау!) - Я не ожидал, что!
Я думаю, что оригинальный вопрос решается в данный момент, но следующие из них поднял:
-
Почему журнал транзакций растут выглядит линейным (не квадратные, как мы можем ожидать, когда просто захват «до» и «после» изображений)?Из диаграммы видно, что количество предметов в секунду растет пропорционально квадрату - это как и ожидалось, если накладные расходы линейно растут с количеством вставленных элементов. - Почему в случае, если журнал транзакций вставок имеет тот же размер, что и перед любыми вставками? Я просмотрел журнал транзакций (с Dell's Toad) для случая со вставками и выглядит как только последние 297 элементов находятся там - возможно, журнал транзакций усечен, но почему, если это
FULL
режим восстановления?
ОБНОВЛЕНИЕ (21 апреля). DBCC LOGINFO
выход для кейс с INSERT
- до и после. Физический размер файла журнала соответствует выходу - ровно 1 048 576 байт на диске. Почему он выглядит, как журнал транзакций остается неподвижным?
RecoveryUnitId FileId FileSize StartOffset FSeqNo Status Parity CreateLSN 0 2 253952 8192 131161 0 64 0 0 2 253952 262144 131162 2 64 0 0 2 253952 516096 131159 0 128 0 0 2 278528 770048 131160 0 128 0
RecoveryUnitId FileId FileSize StartOffset FSeqNo Status Parity CreateLSN 0 2 253952 8192 131221 0 128 0 0 2 253952 262144 131222 0 128 0 0 2 253952 516096 131223 2 128 0 0 2 278528 770048 131224 2 128 0
Для тех, кто заинтересован я записал «sqlserv.exe» деятельность с использованием Process Monitor - я могу видеть, что файл переписывается снова и снова - выглядит как лечит SQL Server старые элементы журнала, как больше не нужны по некоторым причинам: https://dl.dropboxusercontent.com/u/1323651/stackoverflow-sql-server-transaction-log.pml.
ОБНОВЛЕНИЕ (24 апреля). Кажется, я, наконец, начал понимать, что там происходит, и хочу поделиться с вами. Вышеприведенное рассуждение верно в целом, но имеет серьезное предостережение, которое также порождает путаницу в отношении странного использования журнала транзакций с INSERT
с.
базы данных будет вести себя как в режиме SIMPLE восстановления до первой полной резервная копия не принимается (даже если он находится в режиме полного восстановления).
Мы можем рассматривать числа и диаграммы выше, действительны для SIMPLE
режима восстановления, и я должен повторить мое измерение для реальногоFULL
- они еще больше поразительной.
UPDATE INSERT Duration 13:20 (!) 00:02 Data file grow 8MB 11MB Tran. log grow 55.2GB (!) 14MB
описана вся хорошая практика, что вы должны рассмотреть http://dba.stackexchange.com/questions/29829/why-does-the-transaction-log-keep-growing-or-run-out-of-space –
@PiotrLasota, спасибо за это предложение, но поскольку мы используем Azure SQL, мы не отвечаем за управление резервными копиями журналов и тому подобное. Azure SQL также реализует модель FULL recovery. –
Избегайте обновлений, запись tlog для обновления содержит данные как для отмены, так и для повтора, то есть недавно обновленных данных, а также данных перед обновлением. Я бы, наверное, вставлял только в вашу ситуацию. – dean