Чим відрізняються ці два відкати SQL Server?


13

У SQL Server 2008 R2, чим вони відрізняються:

  1. Запустіть ALTERзаяву на кілька хвилин, а потім натисніть "Скасувати виконання". Для повного відкату потрібно кілька хвилин.

  2. Запустіть той самий ALTERоператор, але переконайтеся, що LDFфайл недостатньо великий для його успішного завершення. Після того, як LDFобмеження буде досягнуто і не дозволено «автоматичний ріст», виконання запиту негайно припиняється (або відбувається відкат) із цим повідомленням про помилку:

The statement has been terminated.
Msg 9002, Level 17, State 4, Line 1
The transaction log for database 'SampleDB' is full. 
To find out why space in the log cannot be reused, see the 
log_reuse_wait_desc column in sys.databases

Чим ці два різні в наступних пунктах?

  1. Чому другий «відкат» миттєвий? Я не зовсім впевнений, чи можна це назвати відкатом. Я здогадуюсь, що журнал транзакцій пишеться по мірі прогресування виконання, і як тільки він зрозуміє, що не вистачає місця для повного виконання завдання, він просто зупиняється на якомусь повідомленні про закінчення, без комісій.

  2. Що відбувається, коли перший відкат займає стільки часу (це відкат однієї різьби)?
    2.1. Чи повертається SQL Server і скасовує записи, зроблені у LDFфайлі?
    2.2. Розмір LDFфайлу зменшується в кінці відката (від DBCC SQLPERF(LOGSPACE))

  3. Ще одне додаткове запитання: Під час другого сценарію SQL Server починає споживати LDFфайл досить швидко. У моєму випадку він збільшився з 18% до 90% в перші кілька хвилин (<4 хв.). Але як тільки він досяг 99%, він залишився там ще 8 хвилин, коли коливання використовувалося між 99,1% до 99,8%. Він піднімається (99,8%) і вниз (99,2%) і знову вгору (99,7%) і вниз (99,5%) кілька разів до помилки. Що відбувається за лаштунками?

Вдячні будь-які посилання MSDN, які могли б допомогти пояснити це.

За пропозицією Алі Разегі я додаю perfmon: Disk Bytes/sec

Сценарій 1:

Сценарій 1

Сценарій 2:

Сценарій 2


Просто короткий коментар: розмір файлу! = Простір, який використовується у файлі.
Аарон Бертран

@Aaron Так, я з цим знайомий. Я використовував DBCC SQLPERF (LOGSPACE) для вимірювання використання. Файл LDF залишався однаковим протягом усієї тривалості, оскільки я обмежив розмір файлу до 10 ГБ. Внутрішнє використання варіюється.
ToC

1
Я підозрюю, що другий відкат з'являється миттєво, оскільки про помилку повідомляється після завершення відкату. Це, мабуть, 8 хвилин, які ви спостерігаєте за 3., де використання LDF залишається досить постійним.
mustaccio

@mustaccio Я би погодився з вами, але артефакти спрямовані в інший бік. Якщо насправді відбувся відкат, то використання файлів журналу має бути повернуто до меншої кількості; і не залишатися на рівні 99,3% під час передачі повідомлення про помилку.
ТЦ

1
Я вважаю, що відкат займає місце в журналі. Коли журнал стає повним під час відката, БД стає підозрілим. Це більше не торкається. Це виглядає як миттєвий відкат, але відкат був відкладений, поки ви не зможете повернути базу даних в Інтернет (коли є місце на диску); Крім того, коли журнал стає повним, SQL Server може спробувати звільнити місце, встановивши контрольну точку, яка може пояснити сплески в IO-діяльності.
usr

Відповіді:


1

Як було зазначено вище, після проведення додаткових тестів я прийшов до обчислених висновків. Я підсумував їх усіх у публікації в блозі , але я скопію деякий вміст до цієї публікації для нащадків.

Концепція (на основі деяких тестів)

На сьогоднішній день у мене немає чіткого пояснення, чому це відбувається. Але далі мої оцінки на основі артефактів, зібраних під час випробувань.

Відкат відбувається в обох сценаріях. Один - явний відкат (користувач натискає кнопку Скасувати), інший - неявний (сервер Sql приймає це рішення внутрішньо).

В обох сценаріях трафік, що надходить до файлу журналу, є послідовним. Дивіться зображення нижче:

Сценарій 1:

Сценарій 1:

Сценарій 2:

Сценарій 2

  • Одним артефактом, який підкріпив цю думку, є захоплення Sql Trace під час обох сценаріїв.

    • Сценарій 1 очевидний інакше, коли ми натискаємо «Скасувати», він відкочується назад.
    • У сценарії 2 повідомлення про помилку відображається після неявного виконання "відкату". У Sql Trace ми бачимо повідомлення про помилку «Журнал транзакцій для бази даних« SampleDB »заповнений» задовго до появи повідомлення на екрані. Отже, я здогадуюсь, що відкати трапляються в обох сценаріях, але повідомлення про помилку - сценарій 2 відображається після успішного та повного виконання відката.
  • Сценарій 2, здається, займає більше часу, оскільки він прогресує значно далі, тому відкат займає більше часу.

Пояснення:

  • Чому використання файлів журналу так сильно відрізняється?
    • Він збільшується до 90%, потім до 85%, потім до 99% і довго зависає там. Я бачу, як це відбувається кілька разів вгору і вниз: 99,2%, 99,8%, 99,1%, 99,7%. Чому це відбувається?
    • Одне з можливих пояснень полягає в тому, що може виникнути фоновий процес (щось на кшталт Log Flush), який очищає файл журналу кожні кілька хвилин. І кожен раз, коли він починається, деякі записи очищаються, що призводить до отримання більше вільного місця.

Будь-які ідеї, які допоможуть пояснити цю поведінку кращим чином, вітаються.


2
Перевірившись з Полом Рандалом, він підтвердив, що ви дійшли правильного висновку - відкат однаковий в обох випадках.
Пол Білий 9

0

Я спробував наступний експеримент і отримав подібні результати. В обох випадках fn_dblog () показує, що відбувається відкат, і, здається, це відбувається швидше в сценарії 2, ніж у сценарії 1.

До речі, я розмістив і MDF, і LDF на одному і тому ж зовнішньому (USB 2.0) диску.

Мій початковий висновок полягає в тому, що в цій справі немає різниці в роботі відкату, і, ймовірно, будь-яка видима різниця швидкостей пов'язана з підсистемою вводу / виводу. Це лише моя робоча гіпотеза на даний момент.

Сценарій 1:

  • Створіть базу даних з файлом журналу, який починається на 1МБ, зростає в 4МБ шматки і має максимальний розмір 100МБ.
  • Відкрийте явну транзакцію, запустіть її протягом 10 секунд, а потім вручну скасуйте її в рамках SSMS
  • Подивіться на підрахунок fn_dblog () та розмір резерву журналу та перевірте DBCC SQLPERF (LOGSPACE)

Сценарій 2:

  • Створіть базу даних з файлом журналу, який починається на 1МБ, зростає в 4МБ шматки і має максимальний розмір 100МБ.
  • Відкрийте явну транзакцію, виконайте її, поки в журналі не з’явиться повна помилка
  • Подивіться на підрахунок fn_dblog () та розмір резерву журналу та перевірте DBCC SQLPERF (LOGSPACE)

Результати монітора ефективності:

Сценарій 1: *** Сценарій 1 ***

Сценарій 2: *** Сценарій 2 ***

Код:

ВИКОРИСТАННЯ [майстер];
ПОВЕРНУТИСЯ

ЯКЩО DATABASEPROPERTYEX (N'SampleDB ', N'Version')> 0
ПОЧАТОК
    ALTER DATABASE [SampleDB] SET SINGLE_USER
        З ПОВЕРНЕНОЮ НЕЗАДАЧНОЮ;
    DROP DATABASE [SampleDB];
КІНЧ;
ПОВЕРНУТИСЯ

СТВОРИТИ ДАННУ [SampleDB] НА ПЕРШИЧНІЙ 
( 
      NAME = N'SampleDB '
    , FILENAME = N'E: \ data \ SampleDB.mdf ' 
    , SIZE = 3 Мб 
    , FILEGROWTH = 1 Мб 
)
ЗАЛОГІНИТИСЯ 
( 
      NAME = N'SampleDB_log '
    , FILENAME = N'E: \ data \ SampleDB_log.ldf '
    , SIZE = 1 Мб 
    , MAXSIZE = 100 Мб 
    , FILEGROWTH = 4 Мб 
);
ПОВЕРНУТИСЯ

USE [SampleDB];
ПОВЕРНУТИСЯ

- Додайте таблицю
СТВОРИТИ СТОЛЮ dbo.test
(
    c1 CHAR (8000) НЕ НЕЗАЄМНЕ ЗАМОВЛЕННЯ ('a', 8000)
) НА [ПЕРШИЙ];
ПОВЕРНУТИСЯ

- Переконайтесь, що ми не є псевдопростою моделлю відновлення
РЕЗУЛЬТАТА ДАТАБАЗА зразокDB
ДИСК = 'NUL';
ПОВЕРНУТИСЯ

- Резервне копіювання файлу журналу
BACKUP LOG SampleDB
ДИСК = 'NUL';
ПОВЕРНУТИСЯ

- Перевірте використаний простір журналу
DBCC SQLPERF (LOGSPACE);
ПОВЕРНУТИСЯ

- Скільки записів видно з fn_dblog ()?
ВИБІР * ВІД fn_dblog (NULL, NULL); - Близько 9 у моєму випадку

/ **********************************
             СЦЕНАРІЯ 1
********************************** /
- Відкрийте нову транзакцію і потім поверніть її назад
ПОЧАТОК ТРАНЗАКЦІЯ

    ВСТАВЛЯЄТЬСЯ в dbo.test ЗАМЕЧАННІ ЦІННОСТІ;
    GO 10000 - Нехай запускається протягом 10 секунд, а потім натисніть кнопку Скасувати у вікні запитів SSMS

    - Скасувати транзакцію
    - На закінчення має пройти пару секунд


- Не потрібно відмовляти транзакцію, оскільки скасування вже зробило це для вас.
- Просто спробуйте. Ви отримаєте цю помилку
- Msg 3903, рівень 16, стан 1, рядок 1
- Запит ROSLBACK TRANSACTION не має відповідного BEGIN TRANSACTION.
РОЗВ'ЯЗАННЯ ТРАНЗАКЦІЯ;

- Який використаний простір журналу? Вище 100%.
DBCC SQLPERF (LOGSPACE);
ПОВЕРНУТИСЯ

- Скільки записів видно з fn_dblog ()?
ВИБІР * 
ВІД fn_dblog (NULL, NULL); - Близько 91 926 у моєму випадку

- Загальний запас журналу, показаний fn_dblog ()?
SELECT SUM ([Резерв журналу]) AS [Загальний резерв журналу]
ВІД fn_dblog (NULL, NULL); - Близько 88,72 Мб


/ **********************************
             СЦЕНАРІЯ 2
********************************** /
- Здуйте БД і почніть спочатку
ВИКОРИСТАННЯ [майстер];
ПОВЕРНУТИСЯ

ЯКЩО DATABASEPROPERTYEX (N'SampleDB ', N'Version')> 0
ПОЧАТОК
    ALTER DATABASE [SampleDB] SET SINGLE_USER
        З ПОВЕРНЕНОЮ НЕЗАДАЧНОЮ;
    DROP DATABASE [SampleDB];
КІНЧ;
ПОВЕРНУТИСЯ

СТВОРИТИ ДАННУ [SampleDB] НА ПЕРШИЧНІЙ 
( 
      NAME = N'SampleDB '
    , FILENAME = N'E: \ data \ SampleDB.mdf ' 
    , SIZE = 3 Мб 
    , FILEGROWTH = 1 Мб 
)
ЗАЛОГІНИТИСЯ 
( 
      NAME = N'SampleDB_log '
    , FILENAME = N'E: \ data \ SampleDB_log.ldf '
    , SIZE = 1 Мб 
    , MAXSIZE = 100 Мб 
    , FILEGROWTH = 4 Мб 
);
ПОВЕРНУТИСЯ

USE [SampleDB];
ПОВЕРНУТИСЯ

- Додайте таблицю
СТВОРИТИ СТОЛЮ dbo.test
(
    c1 CHAR (8000) НЕ НЕЗАЄМНЕ ЗАМОВЛЕННЯ ('a', 8000)
) НА [ПЕРШИЙ];
ПОВЕРНУТИСЯ

- Переконайтесь, що ми не є псевдопростою моделлю відновлення
РЕЗУЛЬТАТА ДАТАБАЗА зразокDB
ДИСК = 'NUL';
ПОВЕРНУТИСЯ

- Резервне копіювання файлу журналу
BACKUP LOG SampleDB
ДИСК = 'NUL';
ПОВЕРНУТИСЯ

- Тепер підірвемо файл журналу в межах нашої транзакції
ПОЧАТОК ТРАНЗАКЦІЯ
    ВСТАВЛЯЄТЬСЯ в dbo.test ЗАМЕЧАННІ ЦІННОСТІ;
    GO 10000

- Відкат ніколи не спрацьовує. Спробуй це. Ви отримаєте помилку.
- Msg 3903, рівень 16, стан 1, рядок 1
- Запит ROSLBACK TRANSACTION не має відповідного BEGIN TRANSACTION.
РОЗВ'ЯЗАННЯ ТРАНЗАКЦІЯ;

- Чи заповнений файл журналу на 100%? 
DBCC SQLPERF (LOGSPACE);

- Скільки записів видно з fn_dblog ()?
ВИБІР * 
ВІД fn_dblog (NULL, NULL); - Близько 91 926 у моєму випадку
ПОВЕРНУТИСЯ

- Загальний запас журналу, показаний fn_dblog ()?
SELECT SUM ([Резерв журналу]) AS [Загальний резерв журналу]
ВІД fn_dblog (NULL, NULL); - 88,72 Мб
ПОВЕРНУТИСЯ

Дякую за детальні тести. Після проведення додаткових тестів я прийшов до подібного висновку. Отже, я написав допис у блозі . Для мене сценарій 2 займає більше часу, тому що обсяг роботи, виконаної в сценарії 2, до того, як сервер Sql зрозуміє, що необхідність відката більше, ніж сценарій 1.
ТЦ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.