Швидка операція ROLLBACK?


Відповіді:


14

Для SQL Server ви можете стверджувати, що операція фіксації - це не що інше, як запис LOP_COMMIT_XACT у файл журналу та звільнення блокування, що, звичайно, буде швидше, ніж ROLLBACK кожної дії, здійсненої вами транзакції з BEGIN TRAN.

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

Відкат - це зчитування послідовного файлу змін та застосування їх до сторінок даних в пам'яті. Початковий "твір" повинен був створити план виконання, придбати сторінки, об'єднати рядки тощо.

Редагувати: це залежить трохи ...

@JackDouglas вказав на цю статтю, яка описує одну з ситуацій, коли відкат може зайняти значно більше часу, ніж оригінальний процес. Прикладом є 14-годинна транзакція, яка неминуче використовує паралелізм, який вимагає 48+ годин для відкату, оскільки відкат - це переважно однопоточна передача. Ви, швидше за все, також неодноразово відбиваєте буферний пул, тому більше не обертаєте зміни на сторінках пам'яті.

Отже, переглянута версія моєї попередньої відповіді. На скільки повільніше відкат? Всі інші речі, що стосуються типової трансакції OLTP, це не так. Поза типовими межами може знадобитися більше часу, ніж "скасувати", ніж "зробити", але (це потенційний твістер язика?), Чому це буде залежати від того, як було зроблено "робити".

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

Створіть дві таблиці та упакуйте їх неефективно (витрачений простір на сторінку):

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
SET NOCOUNT ON;
GO

CREATE TABLE dbo.Foo
(
    col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)

CREATE TABLE dbo.Bar
(
    col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)
GO

INSERT dbo.Foo DEFAULT VALUES
GO 100000

INSERT dbo.Bar DEFAULT VALUES
GO 100000

Запустіть "поганий" запит на оновлення, вимірюючи час, необхідний для виконання робіт, і час, необхідний для видачі комісії.

DECLARE 
    @StartTime DATETIME2
    , @Rows INT

SET @Rows = 1

CHECKPOINT
DBCC DROPCLEANBUFFERS

BEGIN TRANSACTION

SET @StartTime = SYSDATETIME()

UPDATE
    dbo.bar
SET
    col2 = REPLICATE('B', 4000)
FROM
    dbo.bar b
INNER JOIN
    (
    SELECT TOP(@Rows)
        col1
    FROM
        dbo.foo
    ORDER BY
        NEWID()
    ) f
ON  f.col1 = b.col1
OPTION (MAXDOP 1)

SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())

SET @StartTime = SYSDATETIME()

COMMIT TRANSACTION

SELECT 'Commit', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO

Зробіть те ж саме знову, але видайте та відміряйте відкат.

    DECLARE 
    @StartTime DATETIME2
    , @Rows INT

SET @Rows = 1

CHECKPOINT
DBCC DROPCLEANBUFFERS

BEGIN TRANSACTION

SET @StartTime = SYSDATETIME()

UPDATE
    dbo.bar
SET
    col2 = REPLICATE('B', 4000)
FROM
    dbo.bar b
INNER JOIN
    (
    SELECT TOP(@Rows)
        col1
    FROM
        dbo.foo
    ORDER BY
        NEWID()
    ) f
ON  f.col1 = b.col1
OPTION (MAXDOP 1)

SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())

SET @StartTime = SYSDATETIME()

ROLLBACK TRANSACTION

SELECT 'Rollback', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO

З @ Rows = 1 я отримую досить послідовний:

  • 5500 мс для пошуку / оновлення
  • 3 мс
  • Відкат 1 мс

З @ рядками = 100:

  • Знайти / оновити 8500 мс
  • 15 міс
  • 15 м відкат

З @ рядками = 1000:

  • Знайти / оновити 15000 мс
  • 10 міс
  • 500 м відкату

Повернутися до початкового питання. Якщо ви вимірюєте час, витрачений на роботу, а також фіксацію, відкат виграє руки, оскільки більшість цієї роботи витрачається на пошук рядка для оновлення, а не на фактичну зміну даних. Якщо ви дивитесь на операцію фіксації поодиноко, то повинно бути зрозуміло, що фіксація дуже мало "працює" як така. Коміт - це "я закінчив".


2
"менше роботи" не обов'язково "швидше"
Джек Дуглас

Я знав, що begin tranпросто збільшує лічильник транзакцій. Якщо я вас зрозумів, rdbms виконує всі завдання (об'єднує рядки, генерує плани виконання ...) в COMMIT?
garik

3
Ні, вся робота робиться перед скоєнням. Сама операція фіксації робить порівняно мало.
Марк Сторі-Сміт

@Mark Я зробив декілька грубих і готових тестів, вставляючи 2м рядків і здійснюючи заміни або відкоти назад. Загальний час, включаючи відкат, коливався в межах від 10 до 30, порівняно з 6 до 14 за загальний час, включаючи фіксацію. YMMV, звичайно, але це вказує на те, що відкат бального парку майже такий же довший або довший, ніж оригінальна транзакція, принаймні в моєму середовищі.
Джек Дуглас

2
Якби ви вимірювали час виконання операції фіксації, я б очікував, що вона буде мінімальною, якщо одночасно не буде видано контрольний пункт (який є відокремленим і не пов'язаним). Такий мій погляд, фіксація робить дуже мало, тоді як відкат робить все, що відбулося перед фіксацією плюс ще трохи. Різниця у ваших тестах пропонує інші фактори, але я, безумовно, спробую скласти деякі сценарії пізніше.
Марк Сторі-Сміт

13

Для Oracle відкат може зайняти в багато разів більше часу, який знадобився для внесення змін, які повертаються назад. Це часто не має значення, оскільки

  1. Блокування не проводиться, коли транзакція відкочується назад
  2. Він обробляється фоновим процесом з низьким пріоритетом

Для SQL Server я не впевнений, чи ситуація така, але хтось скаже, якщо це не так ...

Щодо "чому", я б сказав, що це rollbackповинно бути рідкісним , як правило, тільки якщо щось пішло не так, і, звичайно, commitце буде набагато частіше - тому є сенс оптимізувати дляcommit


9

Відкат - це не просто "о, неважливо" - у багатьох випадках справді потрібно скасувати те, що вже було зроблено. Не існує правила, що операція відкату завжди буде повільнішою або завжди швидшою, ніж початкова операція, хоча навіть якщо оригінальна транзакція проходила паралельно, відкат є однопоточним. Якщо ви чекаєте, я вважаю, що найбезпечніше просто продовжувати чекати.

Це все змінюється, звичайно, і SQL Server 2019, і прискореним відновленням бази даних (що при штрафі, який також є змінним, дозволяє миттєвий відкат незалежно від розміру даних).


2
І у нас у всіх була така розмова, що "потрібні віки для відкату, давайте перезавантажимо її" в якийсь момент, так?
Марк Сторі-Сміт

Я бачив, як багато клієнтів це роблять. Деякі виходять відносно непошкодженими, іншим - набагато менше щастя.
Аарон Бертран

1
@ MarkStorey-Smith - Якщо ви перезавантажите середину відкату, чи не доведеться SQL Server продовжувати відкат при запуску?
Нік Чаммас

2
@ Нік це залежить - якщо, наприклад, відкат був заблокований перед перезавантаженням, наприклад, він може поводитись набагато швидше після перезавантаження служби, тому що цей інший процес був просто вбитий. У цьому сценарії багато "що робити" - коли ви перезавантажуєте сервер або перезапускаєте службу, щоб "виправити" проблему, напевно, є деякі набагато більш серйозні проблеми.
Аарон Бертран

2
@Nick, так, саме так і відбувається. Мій коментар мав бути "язиком у щоку", настільки, що вам неминуче доведеться пояснити це тригеру щасливого фолк, який хоче вдарити перезавантаження, коли щось не веде себе так, як очікувалося.
Марк Сторі-Сміт

8

Не всі транзакції дозволять виконувати свою діяльність набагато краще, ніж їх відкат. Один з таких випадків - операція видалення в SQL. Коли операція видаляє рядки, ці рядки позначаються як записи-привиди. Після видачі комісії та запуску завдання очищення записів привидів лише ці записи "видалено".

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


Хороший приклад того, як оптимізовані певні операції для відката.
Марк Сторі-Сміт

5

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

Основне питання полягає в тому, як ви звертаєтесь до макета на диску і як це впливає на фіксування та відкат Основні ДБ, які повертаються повільніше, ніж здійснюють, мають тенденцію переміщувати дані, особливо з кластеризованих таблиць, з основних структур даних та розміщувати їх у сегменті відкату при оновленні даних. Це означає, що для того, щоб скористатись, ви просто відкинете сегмент відкату, але щоб повернути назад, вам потрібно скопіювати всі дані назад.

Для PostgreSQL всі таблиці є куповими таблицями, а індекси - окремими. Це означає, що під час відкочування або вчинення жодних даних не потрібно переробляти. Це робить прихильність і відкат обох швидко.

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

Однак швидкість тут не є питанням оптимізації в PostgreSQL для операцій запису проти читання. Це небажання привілейовувати деякі операції з читання над іншими. Отже, PostgreSQL працює в середньому приблизно так само, як і інші db. Просто певні операції можуть бути швидшими або повільнішими.

Тому я думаю, що реальна відповідь полягає в тому, що базові дані оптимізовані для певних навантажень на стороні читання, і це призводить до проблем з боку запису. Зазвичай там, де виникає питання, комісії зазвичай, хоча і не завжди, віддають перевагу відмовам. Однак це залежить від наслідків виконання будь-якого (оновлення відрізняються від видалення).


Хороша відповідь, але одна незначна каламбур: "Для PostgreSQL всі таблиці є куповими таблицями, а індекси є окремими. Це означає, що під час прокрутки назад або введення даних жодних даних не потрібно переставляти", це не є причиною того, що дані не повинні бути переставленими, скоріше це тому, що "Основні ДБ, які котяться назад повільніше, ніж здійснюють, мають тенденцію переміщувати дані", і pg не робить, як ви згадували. Oracle також за замовчуванням зберігає купі: головна відмінність полягає в тому, що Oracle використовує 'скасувати' і повертає весь простір під час фіксації / відкоту, а не проходження маршруту 'вакуум'.
Джек Дуглас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.