В процессе эксплуатации файловых баз данных на платформе 1С:Предприятие 7.7 администраторы нередко сталкиваются с проблемой физического или логического разрушения таблиц (DBF). Особенно критична ситуация, когда повреждается справочник "Номенклатура". Симптомы могут быть пугающими: программа аварийно закрывается ("вылетает") при открытии списка товаров, вместо названий отображаются "кракозябры", которые можно выявить с помощью утилит для проверки базы на некорректные символы, а стандартная проверка физической целостности сообщает, что ошибок нет. При этом тестирование и исправление (ТиИ) в режиме логической целостности может зависнуть на несколько суток.
Разберем детально, почему это происходит, и рассмотрим эффективные методы восстановления базы данных без потери ссылочной целостности, даже если резервная копия была сделана давно.
Прежде чем приступать к "хирургическому вмешательству", проанализируем симптомы. В рассматриваемой ситуации мы имеем дело со следующим поведением системы:
PARENTID (ссылка на родительскую группу) записывается мусор или ID текущего элемента. В итоге программа бесконечно ходит по кругу "папка в папке", пытаясь построить дерево.Восстановление из старой резервной копии (например, месячной давности) часто неприемлемо. При создании новых элементов в копии они получат новые внутренние идентификаторы (ID). В результате во всех документах, созданных за последний месяц, ссылки на товары превратятся в "Объект не найден", так как старых ID в новой базе уже не будет.
Это самый надежный и быстрый способ, если у вас настроена компонента УРБД (Управление Распределенными Базами Данных). Рассмотрим, почему это работает.
В системе 1С 7.7 уникальность объекта определяется его внутренним идентификатором. При обмене данными между Центральной базой и Периферийными узлами ID объектов синхронизируются и совпадают. Даже если файл в центре поврежден, на периферии он может быть абсолютно целым.
Выполним следующие шаги для восстановления:
SCxxxxx.DBF (где xxxxx — номер таблицы в словаре данных). Узнать точное имя можно в файле словаря 1Cv7.DD, поискав там строку "Номенклатура". Допустим, это SC84.DBF.SCxxxxx.DBF в папке центральной базы на файл, полученный с периферийного узла..CDX) в папке базы данных. Это заставит 1С пересоздать их заново, исключая ошибки индексации.После этой процедуры структура справочника восстановится, а все ссылки в документах останутся корректными, так как ID объектов в распределенных базах идентичны. Недостающие элементы (которые были созданы в центре после последнего обмена и не успели уйти на периферию) можно будет восстановить вручную или найти через анализ журнала регистрации. В некоторых случаях для выборочного переноса недостающих позиций из другой копии базы можно использовать обработки по загрузке элементов справочников, но основная масса данных будет спасена.
Если периферийной базы нет, или файл поврежден везде, придется чистить таблицу от "мусора" вручную. Поврежденные записи часто имеют смещенные данные, из-за чего в ключевых полях появляются недопустимые символы. Удалить их штатными средствами 1С нельзя — программа "вылетит" при попытке чтения такой записи.
Воспользуемся внешней компонентой 1sqlite, которая позволяет выполнять прямые SQL-запросы к таблицам DBF, минуя движок 1С. Это позволяет удалить битые строки "хирургическим путем".
Рассмотрим пример кода обработки, которая находит и удаляет записи с некорректными кодами (например, начинающимися с пробела или недопустимых символов, что характерно для сбоев):
// Загрузка компоненты для прямых запросов
Если ЗагрузитьВнешнююКомпоненту("1sqlite.dll") = 0 Тогда
Сообщить("Не удалось загрузить 1sqlite.dll. Проверьте наличие файла.");
Возврат;
КонецЕсли;
// Формируем текст запроса на удаление.
// В данном примере удаляем записи, где код начинается с пробела (признак мусора)
// Таблицу называем "Справочник_Номенклатура" (виртуальное имя для 1sqlite)
ТекстЗапроса = "
|DELETE FROM Справочник_Номенклатура
|WHERE substr(CODE, 1, 1) = ' '
|";
// Создаем объект базы данных и выполняем запрос
База = СоздатьОбъект("SQLiteBase");
База.Открыть(":memory:"); // Открываем базу в памяти
База.РазрешитьDELETE(1); // Разрешаем операции удаления (опасно!)
Запрос = База.НовыйЗапрос();
Попытка
Запрос.ВыполнитьЗапрос(ТекстЗапроса);
Сообщить("Запрос на очистку выполнен.");
Исключение
Сообщить("Ошибка выполнения запроса: " + ОписаниеОшибки());
КонецПопытки;
Важно: Для использования метода РазрешитьDELETE(1) вам может потребоваться специфическая версия сборки 1sqlite (например, от dorex), так как стандартная версия от Orefkov может не поддерживать этот функционал напрямую для DBF. Альтернативой является использование внешних редакторов DBF.
Если программный метод кажется сложным, воспользуемся специализированными утилитами для просмотра и правки DBF-файлов (например, CDBF, DBF Commander или старый добрый редактор из FoxPro).
Проанализируем порядок действий:
SCxxxxx.DBF в стороннем редакторе. Эти программы менее чувствительны к ошибкам структуры, чем 1С.CODE или DESCR. Обычно поврежденные записи ("мусор") всплывают в начало или конец списка, либо имеют пустые ID. Предварительно выявить такие строки помогает проверка на некорректные символы.PARENTID. Если в нем содержатся некорректные символы, очистите это поле (сделайте его пустым). Это перенесет элемент в корень справочника, но разорвет бесконечный цикл вложенности.* в первом байте строки) и выполните упаковку таблицы (Pack), если редактор это позволяет.После того как вы заменили файл на здоровый из периферии или вычистили мусор вручную, необходимо привести базу в рабочее состояние:
1SCONST.DBF. Если вы восстанавливали номенклатуру из периферийной базы (с сохранением ID), цены должны "подхватиться" автоматически. Если же элементы создавались заново (что не рекомендуется), файл констант будет содержать много "мертвых" записей, которые со временем нужно будет вычистить сверткой базы.Используйте эти методы последовательно, начиная с наименее деструктивного (копирование из периферии), и всегда сохраняйте резервную копию перед началом работ. После восстановления может потребоваться дополнительная работа с данными, например, изменение реквизитов у группы товаров.