2016-04-16 6 views
10

У нас есть приложение, которое записывает журналы в таблицах 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?!) 

enter image description here

Всего 5000 обновления, которые добавляют 1KB данных может болтаться SQL Server в течение 8 минут (вау!) - Я не ожидал, что!

Я думаю, что оригинальный вопрос решается в данный момент, но следующие из них поднял:

  1. Почему журнал транзакций растут выглядит линейным (не квадратные, как мы можем ожидать, когда просто захват «до» и «после» изображений)? Из диаграммы видно, что количество предметов в секунду растет пропорционально квадрату - это как и ожидалось, если накладные расходы линейно растут с количеством вставленных элементов.
  2. Почему в случае, если журнал транзакций вставок имеет тот же размер, что и перед любыми вставками? Я просмотрел журнал транзакций (с 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 

real FULL recovery mode UPDATE stats

+0

описана вся хорошая практика, что вы должны рассмотреть http://dba.stackexchange.com/questions/29829/why-does-the-transaction-log-keep-growing-or-run-out-of-space –

+0

@PiotrLasota, спасибо за это предложение, но поскольку мы используем Azure SQL, мы не отвечаем за управление резервными копиями журналов и тому подобное. Azure SQL также реализует модель FULL recovery. –

+0

Избегайте обновлений, запись tlog для обновления содержит данные как для отмены, так и для повтора, то есть недавно обновленных данных, а также данных перед обновлением. Я бы, наверное, вставлял только в вашу ситуацию. – dean

ответ

3

Вы нарушаете один из основных арендаторов нормальной формы с полем журнала. Швы лог-поля должны содержать добавочную последовательность информации, относящейся к первичной. Исправление состоит в том, чтобы прекратить это делать.

1 Создайте стол. xyz_event_history_LOG (event_history_id, log_sequence #, журнал)

2 остановки делать обновление в поле журнала в [xyz_event_history], а не делать вставки в xyz_event_history_LOG

Количество данных в журнале транзакций будет уменьшаться ЗНАЧИТЕЛЬНО.

+0

Можете ли вы предоставить ссылки на авторитетные источники или сведения о внутренних документах транзакций SQL Server? –

+0

@ EugeneD.Gubenkov вы можете просто попробовать его в своей локальной среде? – cassandrad

+0

@cassandradied, что я наконец нашел время, чтобы посмотреть - см. Сообщение об обновлении! –

1

Журнал транзакций содержит все изменения в базу данных в порядке, они были сделаны, так что если вы обновляете подряд несколько раз, вы получите несколько записей в эту строку. Он сохраняет все значение, старое и новое, поэтому вы считаете, что несколько небольших обновлений для большого типа данных, таких как nvarchar (max), будут неэффективными, вам будет лучше хранить обновления в отдельных столбцах, если они будут только небольшими значения.

+0

Точно! Цените свой ответ! –

Смежные вопросы