При некорректной свертке информационной базы 1С:Предприятие 7.7 (особенно в редакции «Торговля и Склад») часто возникает критическая ситуация: документы прошлых периодов помечаются на удаление прямыми запросами к СУБД, но физические записи в таблицах движений регистров остаются нетронутыми. В результате база данных перестает проходить стандартную процедуру «Тестирование и исправление» (ТиИ), аварийно завершаясь с ошибкой «Недостаточно свободной памяти» или сообщая: «Документ ... не проводился - некорректная запись о движениях регистра». Кроме того, при переносе баз на MS SQL Server могут возникать ошибки вида «Нарушена структура таблицы SC...». Разберем по шагам, как исправить эти проблемы, очистить зависшие движения прямыми запросами и вернуть базу к стабильной работе.
Проанализируем механику работы платформы 1С 7.7 на MS SQL Server, чтобы понять истоки проблемы:
1cv7s.exe является 32-битным приложением. В архитектуре Windows одному такому процессу доступно не более 2 Гб виртуального адресного пространства, независимо от того, сколько физической оперативной памяти установлено на сервере (даже если там 12 Гб или больше). Во время проверки служебных данных ТиИ строит в оперативной памяти графы ссылочной целостности. При сотнях тысяч «висячих» записей движений лимит в 2 Гб мгновенно исчерпывается._1SJOURN состояние документа определяется полем CLOSED (младший бит CLOSED & 1 = 1 означает проведенность), а также колонками RF<ID_Регистра>, в которых хранятся флаги формирования движений по конкретным регистрам. Если снять признак проведения, но оставить строки в таблицах движений (RA...), платформа фиксирует логическое нарушение целостности данных.1Cv7.DDS (например, если файл 1Cv7.MD обновлялся простой подменой без корректного сохранения в Конфигураторе). При попытке штатной реструктуризации платформа может полностью очистить проблемный справочник.Рассмотрим наиболее быстрый способ очистки движений у непроведенных и помеченных на удаление документов. Использование штатных методов СделатьНепроведенным() или Удалить() на базах большого объема занимает десятки часов. Для выполнения очистки напрямую в СУБД применим компоненту 1С++ и объект ODBCRecordset.
Разберем готовый алгоритм обхода всех регистров конфигурации и удаления записей движений, принадлежащих непроведенным документам:
вРекордСет = СоздатьОбъект("ODBCRecordset");
Состояние("Начинаем чистку регистров у непроведенных документов...");
Для СЦ = 1 По Метаданные.Регистр() Цикл
вМетаРегистр = Метаданные.Регистр(СЦ);
вИдент = вМетаРегистр.Идентификатор;
ТекстЗапроса = "
|DELETE FROM $Регистр." + вИдент + "
|WHERE IDDOC IN (
| SELECT
| рег.IDDOC
| FROM
| $Регистр." + вИдент + " as рег (NOLOCK)
| INNER JOIN _1SJourn as жОбщий (NOLOCK) ON рег.IDDOC = жОбщий.IDDOC
| WHERE
| жОбщий.CLOSED & 1 = 0
| GROUP BY
| рег.IDDOC
|)
|";
Попытка
вРекордСет.ВыполнитьИнструкцию(ТекстЗапроса);
Исключение
Сообщить("Ошибка при очистке регистра " + вИдент + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Сообщить("Очистка движений непроведенных документов успешно завершена.");
Посмотрим на пример удаления движений по документам, которые строго предшествуют дате свертки (срез исторических данных):
вРекордСет = СоздатьОбъект("ODBCRecordset");
вРекордСет.УстановитьТекстовыйПараметр("ВыбДата", ДатаСвертки);
Для СЦ = 1 По Метаданные.Регистр() Цикл
вМетаРег = Метаданные.Регистр(СЦ);
вИдент = вМетаРег.Идентификатор;
ТекстЗапроса = "
|DELETE FROM $Регистр." + вИдент + "
|WHERE IDDOC IN (
| SELECT
| жОбщий.IDDOC
| FROM
| _1SJourn as жОбщий (NOLOCK)
| WHERE
| жОбщий.DATE_TIME_IDDOC <= :ВыбДата~
|)
|";
Попытка
вРекордСет.ВыполнитьИнструкцию(ТекстЗапроса);
Исключение
Сообщить("Ошибка обработки регистра " + вИдент + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Важный момент: После удаления физических строк из таблиц движений (RA...) необходимо также сбросить флаги участия документов в регистрах в таблице _1SJOURN, чтобы платформа не считала, что документ сформировал проводки:
Для СЦ = 1 По Метаданные.Регистр() Цикл
вИдент = Метаданные.Регистр(СЦ).Идентификатор;
ТекстСбросаФлагов = "
|UPDATE _1SJourn
|SET $ФлагРегистра." + вИдент + " = 0
|WHERE CLOSED & 1 = 0
|";
вРекордСет.ВыполнитьИнструкцию(ТекстСбросаФлагов);
КонецЦикла;
Когда при запуске базы или загрузке копии возникает ошибка «Нарушена структура таблицы SC496» (или SC597), ни в коем случае нельзя выполнять реструктуризацию через стандартное сохранение конфигурации, так как 1С просто пересоздаст таблицу заново и сотрет все записи.
Разберем по шагам правильный алгоритм синхронизации структуры базы данных с метаданными:
1Cv7.DDS в текстовом редакторе (он находится в каталоге базы данных).Table SC496. Изучаем перечень полей, их типы (CHAR, NUMERIC, DATETIME) и длину.
EXEC sp_help 'SC496';
1Cv7.DDS. Выясняем, каких колонок не хватает или где не совпадают типы данных.
ALTER TABLE SC496 ADD SP497 CHAR(9) NOT NULL DEFAULT ' 0 ';
Если же в таблице SQL остались устаревшие колонки, которых больше нет в конфигурации, аккуратно удаляем их:
ALTER TABLE SC496 DROP COLUMN SP999;
1Cv7.DDS, база запустится в штатном режиме без потери информации в справочниках.Чтобы успешно завершить обслуживание информационной базы после очистки движений, применим следующие рекомендации:
1cv7s.exe можно включить поддержку флага LARGEADDRESSAWARE. Это делается консольной утилитой editbin /LARGEADDRESSAWARE 1cv7s.exe. На 64-битной операционной системе сервер выделит процессу 1С до 4 Гб виртуальной памяти вместо стандартных 2 Гб, что исключит аварийный сбой при длительных проверках..BAK).Используя прямой доступ к данным через ODBCRecordset и ручную синхронизацию структуры таблиц с файлом 1Cv7.DDS, можно гарантированно очистить информационную базу от ошибочных движений и восстановить ее работоспособность без потерь критически важных справочников.