Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> Откат транзакций в SQL 2005 / 2008
SHADE
сообщение 23.07.2009 - 20:36

Bill rulz ^^
******
орден IV степени
Группа: Участник
Сообщений: 1418
Регистрация: 28.09.2003
Пользователь №: 24


На сколько я помню в MSSQL'е всегда можно откатить любую сделанную на БД транзакцию.

Вот сценарий:

1. В 10:00 делается апдейт некой таблицы, который апдейтит все записи
SQL
UPDATE MyTable SET Value = 1

2. С 10:00 до 11:00 в таблице происходят какие-то изменения
3. В 11:00 нужно откатить апдейт, сделанный в 10:00

Вопрос, возможно ли так сделать и как это делается, если известно что апдейт был сделан ровно в 10:00?

Сообщение отредактировано SHADE - 23.07.2009 - 20:40
Перейти в начало страницы
 
+Цитировать сообщение
leah
сообщение 23.07.2009 - 22:50

Постоялец форума
*****

Группа: Модератор
Сообщений: 967
Регистрация: 17.08.2004
Пользователь №: 4400


Цитата(SHADE @ 23.07.2009 - 21:36) *
На сколько я помню в MSSQL'е всегда можно откатить любую сделанную на БД транзакцию.

Вот сценарий:

1. В 10:00 делается апдейт некой таблицы, который апдейтит все записи
SQL
UPDATE MyTable SET Value = 1

2. С 10:00 до 11:00 в таблице происходят какие-то изменения
3. В 11:00 нужно откатить апдейт, сделанный в 10:00

Вопрос, возможно ли так сделать и как это делается, если известно что апдейт был сделан ровно в 10:00?


Нет, такие изменения откатить нельзя. Это противоречит самой сути связности данных в базе данных ().

Откат транзакции подразумевает немного не то, что ты написал. А вот что:
1) открываем транзакцию
2) изменяем последовательно несколько записей в таблице(ах)
3) в процессе этого понимаем, что данные уже изменил кто-то другой и мы модифицируем на основе устаревших данных
4) откатываем транзакцию..

Но можно откатить всю базу данных, все таблицы и данные - вернуть на тот момент времени, когда была поставлена контрольная точка и сохранен журнал транзакций. При этом нужно иметь полный слепок базы данных и журнал транзакций до момента отката.


Из твоей ситуации обычно выходят программным путем, создавая собственный лог изменения своих данных в отдельной таблице (так как у всех свои данные и восстанавливать их связанность база данных не должна, она должна следить за связанностью и только, а бизнес сущности, что несут сами данные, не ее дело).
Например, у нас есть таблица счетов клиентов, где происходит апдейт текущего состояния счета. При каждом апдейте счета клиента мы прихраниваем предыдущее значение в отдельную таблицу триггером или отдельным запросом в рамках ТРАНЗАКЦИИ.
Например можно обойтись такими двумя запросами (таблица BALANCE - актуальные данные, BALANCE_LOG логирование каждого действия в этой таблице или нескольких):
SQL
select Customer_id, Debit, Credit, getdate() into BALANCE_LOG from BALANCE where Customer_id=1234567
update BALANCE set Debit=10000, Timestamp=getdate() where Customer_id=1234567

Ну вот теперь можно вычислить баланс на каждый момент времени и восстановить его :-)

Если этого не делать в транзакции, то два одновременных апдейта одного счета создадут рассогласованность данных в обеих таблицах.

Сообщение отредактировано leah - 23.07.2009 - 23:01
Перейти в начало страницы
 
+Цитировать сообщение
SHADE
сообщение 24.07.2009 - 02:21

Bill rulz ^^
******
орден IV степени
Группа: Участник
Сообщений: 1418
Регистрация: 28.09.2003
Пользователь №: 24


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

Цитата(leah @ 23.07.2009 - 23:50) *
Но можно откатить всю базу данных, все таблицы и данные - вернуть на тот момент времени, когда была поставлена контрольная точка и сохранен журнал транзакций. При этом нужно иметь полный слепок базы данных и журнал транзакций до момента отката.

Думаю это и есть то что нужно.

Вобщем есть реально живая ситуация. По тем или иным причинам на живой базе был выполнен скрипт который ввел ее в невалидное состояние, и коснулось это нескольких таблиц. Скрипт подзасрал данные. Приложение в таком состоянии проработало некоторое время, потом проблема вскрылась и нужно откатить изменения.

Получается, если взять мой пример из первого поста, чтобы откатить на 10:00 нужно поднять какой-то более ранний бэкап а потом накатить на него изменения из журнала транзакций. А вот можно ли как-то сделать это например только для одной таблицы, чтобы откатить банальный косяк вроде UPDATE'а без условий WHERE? Причем именно стредствами БД, без развешивания триггеров на изменение, логирующих эти изменения еще куда-то.

Сообщение отредактировано SHADE - 24.07.2009 - 02:23
Перейти в начало страницы
 
+Цитировать сообщение
leah
сообщение 24.07.2009 - 11:50

Постоялец форума
*****

Группа: Модератор
Сообщений: 967
Регистрация: 17.08.2004
Пользователь №: 4400


Цитата(SHADE @ 24.07.2009 - 03:21) *
Получается, если взять мой пример из первого поста, чтобы откатить на 10:00 нужно поднять какой-то более ранний бэкап а потом накатить на него изменения из журнала транзакций. А вот можно ли как-то сделать это например только для одной таблицы, чтобы откатить банальный косяк вроде UPDATE'а без условий WHERE? Причем именно стредствами БД, без развешивания триггеров на изменение, логирующих эти изменения еще куда-то.


Нет, отдельные таблицы восстановить нельзя. Мы обычно делали по другому. Восстанавливали dump на отдельную базу данных, накатывали логи транзакций, затем через bcp (или что там теперь для этого есть) прихранивали нужные таблицы и заливали их в рабочую базу.

На счет триггеров - я их активный противник! Если можно обойтись несколькими предокмпилированными запросами (prepared statements), то лучше так и поступать! Триггеры плохо отлаживать, один триггер на одну таблицу, имеют кучу ограничений, их постоянно нужно включать/отключать при массовой заливке данных (при восстановлении например), они имеют тенденцию к блокированию записей/таблиц при некоторых условиях и зацикливанию, имеют тенденцию к непрогнозируемой нагрузке при ряде условий.. В общем - триггеры зло и костыли для SQL. А целостность данных лучше делать через ключи и ограничения...

PS. Надеюсь, дампы и логи транзакций имеются? А то ничего не выйдет :-( Причем должны быть ВСЕ промежуточные логи транзакций, которые делались после дампадо времени восстановления... Сначала нужно восстановить дамп, а затем его транзакционные логи в порядке их сохранения... Если хоть один промежуточный лог транзакций потерян, то ничего не получится и придется довольствоваться только дампом.

PPS. Надеюсь, база данных на очень большая :-) Процедура не быстрая...

Сообщение отредактировано leah - 24.07.2009 - 12:06
Перейти в начало страницы
 
+Цитировать сообщение
SHADE
сообщение 28.07.2009 - 22:45

Bill rulz ^^
******
орден IV степени
Группа: Участник
Сообщений: 1418
Регистрация: 28.09.2003
Пользователь №: 24


Цитата
Нет, отдельные таблицы восстановить нельзя. Мы обычно делали по другому. Восстанавливали dump на отдельную базу данных, накатывали логи транзакций, затем через bcp (или что там теперь для этого есть) прихранивали нужные таблицы и заливали их в рабочую базу.


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

А вот случись такое с другими данными то было бы уже хреново. Для тру секурности вообще нужно запретить делать все кроме селекта, а если нужно что-то менять - только програмным путем..
Перейти в начало страницы
 
+Цитировать сообщение

Ответить в данную темуНачать новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



RSS Текстовая версия Сейчас: 25.04.2024 - 20:49