gifts2017

Извечная проблема. Ошибка после динамического обновления (SQL)

Опубликовал Андрей Кондратенко (Kondratenko.as) в раздел Администрирование - Системное

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

Динамическое обновление - это, конечно, нехорошо, но порой других возможностей просто нет. К примеру, компания, работающая 24/7 с количеством людей, работающих в базе, от 100 человек. Когда всех выгнать из базы и провести обновление очень затратно и необходимо заранее это согласовывать, тогда приходится использовать динамическое обновление. Сама ошибка заключется в том, что в момент записи в таблицу «Config» что-то произошло, что помешало корректно закончить данную процедуру. И существует два основных способа лечения этой проблемы:

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

- Второй способ - перезаписать все данные в таблицы «Config»  из резервной копии вашей рабочей базы.

Второй способ более надежный, но была проблема в том, что необходимо было поднимать и разворачивать SQL-ный  бэкап, что занимало много времени.

И поэтому придумали простой и надежный механизм. Перед каждым динамическим обновлением просто сохранять таблицы «Config» и «ConfigSave» (Сохранять ConfigSave» не обязательно, мы делали, чтобы сохранить сделанные наработки в конфигурации).

Создал внешнюю обработку с двумя кнопками «Сохраниться перед динамическим обновлением»  и «Восстановить данные после ошибки динамического обновления».

Копка  «Сохраниться перед динамическим обновлением»   вызывает процедуру:

 

Процедура Сохраниться()
//Подключение к SQL        
            Connection=Новый COMОбъект("ADODB.Connection");
            Connection.ConnectionTimeOut =600;
            Connection.Open("Provider=SQLOLEDB.1;Password=Пароль;Persist Security Info=True;User ID=Пользовать;Initial Catalog=SQL_ИмяБазы;Data Source=SQL_Сервер");
            RecordSet=Новый COMОбъект("ADODB.Recordset");
            RecordSet.CursorLocation=3;
            RecordSet.LockType=2;
            Запрос="[master].[dbo].[sp_backup_config_tables]";
            RecordSet.Open(Запрос, Connection);
            //Сохраняем информацию о последнем обновлении
            СтруктураДанных=Новый Структура();
            СтруктураДанных.Вставить("Пользователь",ПараметрыСеанса.ТекущийПользователь);
            СтруктураДанных.Вставить("ДатаСохранения",ТекущаяДата());
            СтруктураДанных.Вставить("ИмяСервера",ИмяКомпьютера());
            ЗначениеВФайл (ПолноеИмяФайла,СтруктураДанных);
           
            ТекстИзменений="";
           
            Запрос="SELECT  [FileName] FROM [SQL_ИмяБазы].[dbo].[ConfigSave]";;
            RecordSet.Open(Запрос, Connection);
            Если RecordSet.RecordCount>0 Тогда
                        RecordSet.MoveFirst();
                        Пока НЕ RecordSet.EOF() Цикл;
                                   ТекстИзменений=ТекстИзменений+Символы.ПС+строка(RecordSet.Fields(0).Value);
                                   RecordSet.MoveNext();                               
                        КонецЦикла;
            КонецЕсли; 
            RecordSet.Close();
            Сообщить("Данные сохранены. Будут изменены таблици:"+ТекстИзменений);
КонецПроцедуры

Копка  «Восстановить данные после ошибки динамического обновления»   вызывает процедуру: 

 


Процедура Восстановить ()        
            //Подключение к SQL        
            Connection=Новый COMОбъект("ADODB.Connection");
            Connection.ConnectionTimeOut =6000;
            Connection.Open("Provider=SQLOLEDB.1;Password=Пароль;Persist Security Info=True;User ID=Пользовать;Initial Catalog=SQL_ИмяБазы;Data Source=SQL_Сервер");
            Command = Новый COMОбъект("ADODB.Command");
            Command.ActiveConnection = Connection;
            Command.CommandText ="[master]. [dbo].[sp_restore_config_tables]";
            Command.CommandType = 1;
            RecordSet = Новый ComОбъект("ADODB.RecordSet");
            RecordSet.CursorType = 3;
            RecordSet.LockType = 2;
            RecordSet = Command.Execute();
КонецПроцедуры


[master].[dbo].[sp_backup_config_tables] и [master]. [dbo].[sp_restore_config_tables] 

Это процедуры в SQl.

 

[master].[dbo].[sp_backup_config_tables]

SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
/*
** The system profile of the same type of agent will be used as a template for
** the parameters in this new user profile.
*/
ALTER procedure [dbo].[sp_backup_config_tables]
AS  SET NOCOUNT ON
 
truncate table [dbo].[Config_Backup];
 
truncate table [dbo].[ConfigSave_Backup];
 
insert into [dbo].[Config_Backup]
select * from SQL_ИмяБазы.[dbo].[Config];
 
insert into [dbo].[ConfigSave_Backup]
select * from SQL_ИмяБазы.[dbo].[ConfigSave];

  

 

[master]. [dbo].[sp_restore_config_tables]

USE [master]
GO
/****** Object:  StoredProcedure [dbo].[sp_restore_config_tables]    Script Date: 01/22/2015 11:48:09 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
/*
** The system profile of the same type of agent will be used as a template for
** the parameters in this new user profile.
*/
ALTER procedure [dbo].[sp_restore_config_tables]
AS
 SET NOCOUNT ON
 
truncate table SQL_ИмяБазы.[dbo].[Config];
 
truncate table SQL_ИмяБазы.[dbo].[ConfigSave];
 
insert into SQL_ИмяБазы.[dbo].[Config]
select * from [dbo].[Config_Backup];
 
insert into SQL_ИмяБазы.[dbo].[ConfigSave]
select * from [dbo].[ConfigSave_Backup]; 

  

При нажатии кнопки «Восстановить данные после ошибки динамического обновления» блокировать работу пользователей не надо. Те, которые уже работают, ничего не заметят, а новые зайти не смогут.

Если раньше такая ошибка считалась критичной и время восстановления занимало до 1 часа, то теперь оно сократилось до 5 минут.  

 

Update :

 

Статья о триггере , для сохранения таблицы Config перед обновлением http://infostart.ru/public/327674/

 

См. также

PowerTools от 1 000
Подписаться Добавить вознаграждение

Комментарии

1. Фатима Джабраилова (patimka) 22.01.15 09:55
Ну действительно, извечная проблема. Решение только такое - постараться не обновлять динамически, или если уж произошла проблема, то почистить кеш у пользователя, где проблема возникла.
2. Михаил Миронов (Lord_Michael) 22.01.15 10:13
(1) patimka, кэш чистить далеко не всегда помогает в силу того, что изменения в базу зачастую уже записаны и записаны как раз с ошибкой. кэш поможет, только если все сохранилось, а у пользователя нет изменений.

для скульных баз действительной хороший способ описан.

вопрос автору: обязательно в master процедуры добавлять или можно в любую другую базу? я не силен в языке запросов, так что можно пояснения по поводу имен объектов и что где храниться в итоге?
3. Антон Чигин (ChiginAV) 22.01.15 10:21
Отличная идея!
Можно пойти еще дальше и автоматизировать создание бэкапов этих таблиц путем создания триггера.
https://technet.microsoft.com/ru-ru/library/ms189799%28v=sql.105%29.aspx
Это не противоречит лицензионному соглашению 1С и не нужно будет руками запускать обработку
4. Евгения Карук (ekaruk) 22.01.15 10:43
Шикарно.
Очень понравилось название «Восстановить данные после ошибки динамического обновления»
5. Андрей Кондратенко (Kondratenko.as) 22.01.15 11:24
(2) Lord_Michael, Поместить процедуры можно куда угодно,важно чтобы к ним был доступ. Помещать их в рабочую базы не рекомендую , так как к примеру при загрузки данных средствами 1С (dtшник) ваша процедура затрется. А в мастере она будет в надежной сохранности. В итоги при сохранение, данные хранятся в Databases\System Databases\master\Tables\dbo.Config_Backup
где dbo.Config_Backup - это таблица , полностью скопированная с таблицы dbo.Config вашей рабочей базы
6. Андрей Кондратенко (Kondratenko.as) 22.01.15 11:44
(3) ChiginAV, По началу так и хотели сделать,но в действительности реализовать не получилось. Дело в том что 1С использует SQL как хранилище данных , а сам процесс динамического обновления производит платформа и в SQL пишутся данные уже по факту. Отловить триггером этот механизм в платформе не получится, единственное что вы можете это получить момент когда таблица начнет меняться. Но для восстановления нужна таблица до изменения , поскольку остановить процесс записи в нее нельзя, а попытка замедлить этот процесс приводила к ошибкам в платформе. Да и сам процесс копирование записей занимает время, у меня это от 3 до 8 секунд ( Комплексная Автоматизация - 25847 строк в таблице Config и необходимо помнить,что каждая запись не просто текстовые данные, к примеру ячейка [BinaryData] - по сути архивированный файл с описанием метаданного ,а они бывают относительно тяжелыми, к примеру: запись содержащая файл с конфигурацией поставщика от Комплексной Автоматизации весит 261 МБ ).
7. Герман (German) 22.01.15 12:05
8. Мищенко Вадим (vslimv) 22.01.15 12:46
(7) German, Вещь конечно хорошая но и денег стоит)
9. Андрей Кондратенко (Kondratenko.as) 22.01.15 12:48
(7) German, Ну по презентации не понятно как именно она работает. А ссылка интересная,на досуги по изучаю. Но по мне ручной контроль этого менее трудозатратный. И скорее всего при разработке "Хранилища" были задействованы люди знающие как работает этот механизм в платформе 1С. В примере была предоставлена конфигурация ЗУП она довольно простая , разумней было бы показать примеры на УПП и уже на ней говорить о скорости работы. Я пробовал ставить триггер на изменение таблицы и копировал всю ее,а в "Хранилище" скорее всего сохраняется только измененные объекты. Распаковать и получить структуру конфигурации это не проблема V8Unpack20 в свободном доступе причем с его помощью можно не только распаковывать, но и обратно запаковать метаданное и поместить его в SQL , вопрос только в том на сколько это корректно и правильно. На мой взгляд о прямой записи в SQL стоит всерьез говорить только когда 1с выпустит API. 1С бывает сама внезапно перестает работать и сваливаться в дамп :-)
10. Герман (German) 22.01.15 13:16
(8) vslimv,
Вещь конечно хорошая но и денег стоит)


Само собой :)

На мой взгляд о прямой записи в SQL стоит всерьез говорить только когда 1с выпустит API


почти 10 лет на промышеннЫХ базах используется
alexveraww; Evil Beaver; +2 Ответить
11. Алексей 1 (AlX0id) 22.01.15 13:23
Неужели ж оно настолько часто происходит, что прям вот такая автоматизация нужна?
Просто восстановить конфиг из суточного бэкапа раз в год - не вариант?
12. Андрей Кондратенко (Kondratenko.as) 22.01.15 13:29
(11) AlX0id, Происходит не так часто, но поскольку компания работает 24/7 то простой не кому не нужен, а если простой по вине программистов то время простоя вычитается из их жалования:-). Вся проблема во времени восстановления. А динамически обновляемся в день раз 4-5 точно.
13. Екатерина Тутубалина (kalaratra) 22.01.15 13:41
(11) AlX0id, У кого-то раз в год) А кому-то не так везет)))
14. Екатерина Тутубалина (kalaratra) 22.01.15 13:44
Однажды согрешила, 17 раз подряд динамически обновила) Повезло что ничего не упало)
15. Канат Джумадылов (Fox-trot) 22.01.15 14:45
судя по тексту храгимок есть вероятность восстановления конфига соседней базы. то есть если выполнить бекап одной базы, то с легкостью мона восстановить в другой
16. Андрей Кондратенко (Kondratenko.as) 22.01.15 14:55
(15) Fox-trot, Данный пример был создан для одной рабочей базы,чтоб можно было сделать вызов из любой базы,а не только из рабочей...
17. Алексей 1 (AlX0id) 23.01.15 01:15
(12) Kondratenko.as,
Ну мы тоже не редко обновляемся демонически. Необходимость пересадки конфы возникала лишь пару раз за последние пять лет (тьфу-тьфу-тьфу).

// ЗЫ. Вот прям сегодня вылезла "Нарушена целостность конфигурации" при старте конфигуратора у одного из клиентов. Сглазил чо ли.. Вроде обошлось отключением/подключением ИБ на сервере 1С..
18. Канат Джумадылов (Fox-trot) 23.01.15 09:58
(16) ну так а я те про что. сохраняешь в одной, восстанавливаешь в другой ))
19. Андрей Кондратенко (Kondratenko.as) 23.01.15 11:55
(18) Fox-trot, Понятно, я тебя не правильно понял. Я думал ты как на ошибку указывал:).
20. Руслан Носенко (narus1) 26.01.15 11:01
На мой взгляд, это все костыли. Если база данных находится на MS SQL сервере выше или 2005 и база данных имеет Full логирование и бекапы трензакт лога то можно воспользоваться официальной инструкцией msdn.microsoft.com и восстановить базу до момента нажатия на кнопочку "обновить базу данных". Ну, а по поводу очистки таблицы конфигурации это не всегда спасает.
21. andr bat (zoytsa) 26.01.15 13:57
интересная идея!

(20) narus1,
решение же как раз предлагается без потери данных, как в случае отката по всему логу транзакций - перетирается только таблица с конфигурацией

Kondratenko.as; +1 Ответить 1
22. Руслан Носенко (narus1) 27.01.15 14:54
Согласен если это делает автомат. Но мне интересно посмотреть тому человеку в глаза который после динамического обновления не запускает предприятие, и к тому же 1с вылетает при самом обновлении. То есть если у тя при этом работают 100 клиентов в этом есть смысл. Как говориться вернуть в зад :-).
23. Дмитрий Жиляков (Zhilyakovdr) 29.01.15 09:28
Добрый день!
В хранимой процедуре для создания копий лучше использовать
IF OBJECT_ID( 'dbo.Config_Backup' ) IS NOT NULL  
	drop table [dbo].[Config_Backup];

вместо
truncate table [dbo].[Config_Backup];

т.к. в случае с truncate вылетит ошибка если таблицы еще не созданы.
cleaner_it; +1 Ответить 1
24. Алексей Белоусов (AllexSoft) 29.01.15 10:06
а у нас просто память течет на 1С Сервере после динамического обновления) потом юзеров выкидывает с ошибкой типа Недостаточно памяти на сервере) хотя там памяти этой еще завались
25. Борис Скворцов (gaglo) 29.01.15 11:34
(12) А можно поточнее раскрыть "не так часто" (ну, если не тайна)?
У нас система всего лишь 12/5, сотня пользователей, обновления раз 10 в неделю (по дням неравномерно), страшное случилось 1 раз за 5 лет.
26. Андрей Кондратенко (Kondratenko.as) 29.01.15 12:57
(25) gaglo, "не так часто" - Стабильно 1 раз в полгода)
27. Андрей Кондратенко (Kondratenko.as) 29.01.15 13:06
(23) Zhilyakovdr, Зачем дропать? Вам тогда придется и создавать ее заново всякий раз , лишнее время тратить на выполнение

IF OBJECT_ID ('dbo.Config_Backup', 'TR') IS NULL
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CRE ATE   TABLE [dbo].[Config_Backup](
	[FileName] [nvarchar](128) NOT NULL,
	[Creation] [datetime] NOT NULL,
	[Modified] [datetime] NOT NULL,
	[Attributes] [smallint] NOT NULL,
	[DataSize] [int] NOT NULL,
	[BinaryData] [image] NOT NULL,
PRIMARY KEY CLUSTERED 
(
	[FileName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
...Показать Скрыть
28. Nick (Puk2) 29.01.15 13:45
(24) AllexSoft, версия платформы не 8.3.5.1383 случайно? Там есть баг с утечкой памяти рабочего процесса, в одной из наших организаций наблюдался.
29. Алексей Белоусов (AllexSoft) 29.01.15 13:48
(28) Puk2, 8.2.19 ) ту же беду наблюдал на 8.3.4.*, на последних 8.3.4 вроде убрали (ну во всяком случае так дико течь перестала)
30. Дмитрий Жиляков (Zhilyakovdr) 29.01.15 14:01
(27) Kondratenko.as, можно и не дропать, но тогда предварительно, при первом запуске, необходимо убрать truncate иначе вылетит с ошибкой т.к. при первом запуске нет еще таблицы для очистки.
31. Андрей Кондратенко (Kondratenko.as) 29.01.15 14:06
(30) Zhilyakovdr, Согласен с вами,просто я когда создавал таблицу, ее сразу и заполнял)
32. Дмитрий Жиляков (Zhilyakovdr) 29.01.15 15:12
(31) Kondratenko.as, а зачем ее специально создавать.... MS SQL ее сам создаст.....
33. Дмитрий Жиляков (Zhilyakovdr) 30.01.15 17:48
У кого нибудь получилось написать триггер?
34. Андрей Кондратенко (Kondratenko.as) 04.02.15 10:45
(33) Zhilyakovdr, Ссылка на статью по триггеру http://infostart.ru/public/327674/
Lord_Michael; kalaratra; +2 Ответить
35. Андрей Коваль (hiduk) 12.05.15 16:19
Товарищи а с postgresql будет работать?
36. Канат Джумадылов (Fox-trot) 18.05.15 07:33
(35) hiduk, нуна лишь малость допилить
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа