Извечная проблема. Ошибка после динамического обновления (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/2026 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 не будет опубликован. Обязательные поля помечены *