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

Вдаваться в подробности, что такое динамическое обновления, как оно полезно и как оно вредно я не буду, так как статей на эту тему уже много, так же как и способов ее решения. Просто расскажу о своем опыте и о требовании для разработчиков 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/2024 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 перед обновлением //infostart.ru/public/327674/

 

41 Comments

  1. Lord_Michael

    (1) patimka, кэш чистить далеко не всегда помогает в силу того, что изменения в базу зачастую уже записаны и записаны как раз с ошибкой. кэш поможет, только если все сохранилось, а у пользователя нет изменений.

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

    вопрос автору: обязательно в master процедуры добавлять или можно в любую другую базу? я не силен в языке запросов, так что можно пояснения по поводу имен объектов и что где храниться в итоге?

    Reply
  2. ChiginAV

    Отличная идея!

    Можно пойти еще дальше и автоматизировать создание бэкапов этих таблиц путем создания триггера.

    https://technet.microsoft.com/ru-ru/library/ms189799%28v=sql.105%29.aspx

    Это не противоречит лицензионному соглашению 1С и не нужно будет руками запускать обработку

    Reply
  3. ekaruk

    Шикарно.

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

    Reply
  4. Kondratenko.as

    (2) Lord_Michael, Поместить процедуры можно куда угодно,важно чтобы к ним был доступ. Помещать их в рабочую базы не рекомендую , так как к примеру при загрузки данных средствами 1С (dtшник) ваша процедура затрется. А в мастере она будет в надежной сохранности. В итоги при сохранение, данные хранятся в DatabasesSystem DatabasesmasterTablesdbo.Config_Backup

    где dbo.Config_Backup — это таблица , полностью скопированная с таблицы dbo.Config вашей рабочей базы

    Reply
  5. Kondratenko.as

    (3) ChiginAV, По началу так и хотели сделать,но в действительности реализовать не получилось. Дело в том что 1С использует SQL как хранилище данных , а сам процесс динамического обновления производит платформа и в SQL пишутся данные уже по факту. Отловить триггером этот механизм в платформе не получится, единственное что вы можете это получить момент когда таблица начнет меняться. Но для восстановления нужна таблица до изменения , поскольку остановить процесс записи в нее нельзя, а попытка замедлить этот процесс приводила к ошибкам в платформе. Да и сам процесс копирование записей занимает время, у меня это от 3 до 8 секунд ( Комплексная Автоматизация — 25847 строк в таблице Config и необходимо помнить,что каждая запись не просто текстовые данные, к примеру ячейка [BinaryData] — по сути архивированный файл с описанием метаданного ,а они бывают относительно тяжелыми, к примеру: запись содержащая файл с конфигурацией поставщика от Комплексной Автоматизации весит 261 МБ ).

    Reply
  6. German

    (6) Kondratenko.as, http://main.1c-ei.ru/Home/help/object_config/depot работает именно на триггерах

    Reply
  7. vslimv

    (7) German, Вещь конечно хорошая но и денег стоит)

    Reply
  8. Kondratenko.as

    (7) German, Ну по презентации не понятно как именно она работает. А ссылка интересная,на досуги по изучаю. Но по мне ручной контроль этого менее трудозатратный. И скорее всего при разработке «Хранилища» были задействованы люди знающие как работает этот механизм в платформе 1С. В примере была предоставлена конфигурация ЗУП она довольно простая , разумней было бы показать примеры на УПП и уже на ней говорить о скорости работы. Я пробовал ставить триггер на изменение таблицы и копировал всю ее,а в «Хранилище» скорее всего сохраняется только измененные объекты. Распаковать и получить структуру конфигурации это не проблема V8Unpack20 в свободном доступе причем с его помощью можно не только распаковывать, но и обратно запаковать метаданное и поместить его в SQL , вопрос только в том на сколько это корректно и правильно. На мой взгляд о прямой записи в SQL стоит всерьез говорить только когда 1с выпустит API. 1С бывает сама внезапно перестает работать и сваливаться в дамп 🙂

    Reply
  9. German

    (8) vslimv,

    Вещь конечно хорошая но и денег стоит)

    Само собой 🙂

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

    почти 10 лет на промышеннЫХ базах используется

    Reply
  10. AlX0id

    Неужели ж оно настолько часто происходит, что прям вот такая автоматизация нужна?

    Просто восстановить конфиг из суточного бэкапа раз в год — не вариант?

    Reply
  11. Kondratenko.as

    (11) AlX0id, Происходит не так часто, но поскольку компания работает 24/7 то простой не кому не нужен, а если простой по вине программистов то время простоя вычитается из их жалования:-). Вся проблема во времени восстановления. А динамически обновляемся в день раз 4-5 точно.

    Reply
  12. kalaratra

    (11) AlX0id, У кого-то раз в год) А кому-то не так везет)))

    Reply
  13. kalaratra

    Однажды согрешила, 17 раз подряд динамически обновила) Повезло что ничего не упало)

    Reply
  14. Fox-trot

    судя по тексту храгимок есть вероятность восстановления конфига соседней базы. то есть если выполнить бекап одной базы, то с легкостью мона восстановить в другой

    Reply
  15. Kondratenko.as

    (15) Fox-trot, Данный пример был создан для одной рабочей базы,чтоб можно было сделать вызов из любой базы,а не только из рабочей…

    Reply
  16. AlX0id

    (12) Kondratenko.as,

    Ну мы тоже не редко обновляемся демонически. Необходимость пересадки конфы возникала лишь пару раз за последние пять лет (тьфу-тьфу-тьфу).

    // ЗЫ. Вот прям сегодня вылезла «Нарушена целостность конфигурации» при старте конфигуратора у одного из клиентов. Сглазил чо ли.. Вроде обошлось отключением/подключением ИБ на сервере 1С..

    Reply
  17. Fox-trot

    (16) ну так а я те про что. сохраняешь в одной, восстанавливаешь в другой ))

    Reply
  18. Kondratenko.as

    (18) Fox-trot, Понятно, я тебя не правильно понял. Я думал ты как на ошибку указывал:).

    Reply
  19. narus1

    На мой взгляд, это все костыли. Если база данных находится на MS SQL сервере выше или 2005 и база данных имеет Full логирование и бекапы трензакт лога то можно воспользоваться официальной инструкцией msdn.microsoft.com и восстановить базу до момента нажатия на кнопочку «обновить базу данных». Ну, а по поводу очистки таблицы конфигурации это не всегда спасает.

    Reply
  20. zoytsa

    интересная идея!

    (20) narus1,

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

    Reply
  21. narus1

    Согласен если это делает автомат. Но мне интересно посмотреть тому человеку в глаза который после динамического обновления не запускает предприятие, и к тому же 1с вылетает при самом обновлении. То есть если у тя при этом работают 100 клиентов в этом есть смысл. Как говориться вернуть в зад :-).

    Reply
  22. Zhilyakovdr

    Добрый день!

    В хранимой процедуре для создания копий лучше использовать

    IF OBJECT_ID( ‘dbo.Config_Backup’ ) IS NOT NULL
    drop table [dbo].[Config_Backup];

    вместо

    truncate table [dbo].[Config_Backup];

    т.к. в случае с truncate вылетит ошибка если таблицы еще не созданы.

    Reply
  23. AllexSoft

    а у нас просто память течет на 1С Сервере после динамического обновления) потом юзеров выкидывает с ошибкой типа Недостаточно памяти на сервере) хотя там памяти этой еще завались

    Reply
  24. gaglo

    (12) А можно поточнее раскрыть «не так часто» (ну, если не тайна)?

    У нас система всего лишь 12/5, сотня пользователей, обновления раз 10 в неделю (по дням неравномерно), страшное случилось 1 раз за 5 лет.

    Reply
  25. Kondratenko.as

    (25) gaglo, «не так часто» — Стабильно 1 раз в полгода)

    Reply
  26. Kondratenko.as

    (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

    Показать

    Reply
  27. Puk2

    (24) AllexSoft, версия платформы не 8.3.5.1383 случайно? Там есть баг с утечкой памяти рабочего процесса, в одной из наших организаций наблюдался.

    Reply
  28. AllexSoft

    (28) Puk2, 8.2.19 ) ту же беду наблюдал на 8.3.4.*, на последних 8.3.4 вроде убрали (ну во всяком случае так дико течь перестала)

    Reply
  29. Zhilyakovdr

    (27) Kondratenko.as, можно и не дропать, но тогда предварительно, при первом запуске, необходимо убрать truncate иначе вылетит с ошибкой т.к. при первом запуске нет еще таблицы для очистки.

    Reply
  30. Kondratenko.as

    (30) Zhilyakovdr, Согласен с вами,просто я когда создавал таблицу, ее сразу и заполнял)

    Reply
  31. Zhilyakovdr

    (31) Kondratenko.as, а зачем ее специально создавать…. MS SQL ее сам создаст…..

    Reply
  32. Zhilyakovdr

    У кого нибудь получилось написать триггер?

    Reply
  33. Kondratenko.as

    (33) Zhilyakovdr, Ссылка на статью по триггеру http://infostart.ru/public/327674/

    Reply
  34. hiduk

    Товарищи а с postgresql будет работать?

    Reply
  35. Fox-trot

    (35) hiduk, нуна лишь малость допилить

    Reply
  36. s1cret

    Мне помогло для Postgresql :

    Первые 2 пункта позволяют войти в конфигуратор, 3й пункт позволяет сохранять конфигурацию.

    1) delete fr om configsave where FileName = ‘commit’

    2) delete from configsave wh ere FileName = ‘dbStruFinal’

    3) C:UserskubAppDataLocal1C1cv8 удаление всех папок кроме logs

    Reply
  37. svk

    Эта проблема только на Скуле бывает?? На ПостГре такое возможно??

    Reply
  38. МихаилМ
  39. fish249

    Полезная статья, надо будет испытать.

    Reply
  40. sonGodv

    Хорошо. Однако если последствия ДО вылезли например через неделю. Как вариант у пользователя начала форма справочника номенклатура некорректно отображаться. Чистка кэша пользователя помогает но потом снова появляется, хотя ДО более не делалось

    Reply
  41. pavel_pss

    спасибо. за идею.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *