В практике администрирования и поддержки старых, но всё ещё активно эксплуатируемых баз данных на платформе 1С:Предприятие 7.7 в файловом режиме (формат DBF/CDX) специалисты нередко сталкиваются с крайне неприятным поведением системы. При сохранении изменений в конфигураторе, создании нового документа или запуске тестирования и исправления (ТиИ) процесс зависает на длительное время, а индексный файл общего журнала документов 1sjourn.cdx лавинообразно увеличивается в объеме, пока не достигает критического предела в 2 ГБ. После этого система аварийно завершает работу с ошибкой доступа к файлу: "Ошибка доступа к файлу new_stru/1sjourn.cdx" (Error #-70 или Error #-120).
Особенно парадоксально эта ситуация выглядит тогда, когда вся база данных весит не более 150–200 МБ, а сама таблица журнала документов 1sjourn.dbf занимает скромные 10–15 МБ. Каким образом индексный файл, предназначенный для ускорения поиска, может превышать размер индексируемых данных в сотни раз? Разберем подробно техническую природу этого сбоя, проанализируем внутреннее устройство файлового движка 1С 7.7 и рассмотрим практические способы решения этой проблемы.
Файловая версия платформы 1С 7.7 использует в качестве встроенной СУБД сторонний движок CodeBase от компании Sequiter Software. Взаимодействие с базой данных на уровне платформы осуществляет библиотека dbeng32.dll. В архитектуре этого движка заложены жесткие лимиты на длину индексных ключей, которые напрямую связаны со структурой хранения сбалансированных деревьев (B-деревьев) индексов:
dbeng32.dll дает критический сбой. Движок не может корректно выполнить балансировку и сжатие ветвей B-дерева. Вместо этого он уходит в бесконечный цикл дублирования пустых или некорректно сформированных узлов. Этот процесс вызывает лавинообразный (экспоненциальный) рост файла .cdx.Проанализируем, как именно формируется проблемный индекс в системном журнале 1SJOURN, и почему под удар чаще всего попадают строковые реквизиты документов.
Таблица общего журнала документов 1SJOURN.DBF хранит метаданные всех существующих в базе документов (дата, время, тип, проведенность, уникальный идентификатор и значения общих реквизитов). Когда в конфигураторе у общего реквизита (например, "КомментарийДокумента" или "Содержание") взведены флаги «Сортировка» или «Отбор», система обязана построить по этому полю индексный тег в файле 1sjourn.cdx.
Для текстовых реквизитов в общем журнале индекс строится по сложному составному шаблону:
ИмяРеквизита(UPPER=X) + DATE + TIME + IDDOC
Рассмотрим детально длину составляющих этого составного ключа в байтах:
DATE (дата документа) — занимает ровно 8 байт.TIME (время документа) — занимает ровно 6 байт.IDDOC (уникальный внутренний 36-ричный идентификатор документа) — занимает ровно 9 байт.UPPER=X — строковое значение реквизита, приведенное к верхнему регистру. Его длина напрямую зависит от длины, заданной реквизиту в Конфигураторе. В зависимости от настроек кодовой страницы, на один символ может выделяться 1 байт.Если разработчик создает общий реквизит типа "Строка" неограниченной или просто большой длины (например, стандартные 255 символов) и включает по нему отбор, платформа зарезервирует под строковую часть ключа значительный объем байт. Суммарный размер ключа рассчитывается следующим образом:
Размер ключа = ДлинаСтроки + 8 (DATE) + 6 (TIME) + 9 (IDDOC)
Если длина строки равна 255, то размер ключа составит 255 + 23 = 278 байт, что более чем в два раза превышает критический порог в 117 байт. Даже если ограничить строку длиной в 100 символов, размер ключа составит 123 байта, что также является опасным значением при большом количестве документов в базе.
Для того чтобы локализовать и устранить проблему, выполним несколько последовательных шагов.
Шаг 1. Анализ файла словаря данных 1Cv7.DD
В каталоге информационной базы найдем файл 1Cv7.DD. Откроем его с помощью любого текстового редактора (например, Notepad++). Нам необходимо найти описание структуры таблицы 1SJOURN и ее индексов. Найдем блок, описывающий индексы таблицы. Нам нужно обратить внимание на индексные теги, связанные с общими реквизитами. Пример проблемной записи в словаре данных выглядит так:
# Пример фрагмента файла 1Cv7.DD:
# Описание поля общего реквизита "Комментарий"
F=SP2239 |(P)КомментарийДокуме|C |255 |0
# Описание составного индекса по этому полю
I=VIA2239 |VIA2239 |0 |SP2239(UPPER=128),DATE,TIME,IDDOC
Здесь мы наглядно видим, что поле SP2239 имеет длину 255 символов, а индекс VIA2239 строится по формуле, использующей первые 128 символов этой строки в верхнем регистре совместно со служебными полями даты, времени и идентификатора документа. Очевидно, что длина ключа выходит за безопасные рамки.
Рассмотрим несколько способов устранения этой ошибки — от самых простых и быстрых до архитектурно более сложных, но сохраняющих исходную функциональность системы.
Если для бизнес-процессов не требуется хранить в реквизите отбора огромные тексты, самым простым и эффективным решением будет уменьшение длины реквизита в Конфигураторе.
70 + 23 = 93 байта, что гарантированно укладывается в безопасный лимит 117 байт.1sjourn.cdx больше не будет раздуваться.Важное предупреждение: При уменьшении длины реквизита данные в существующих документах, длина которых превышала новое установленное значение, будут безвозвратно обрезаны до установленного лимита символов! Если эти данные критически важны, воспользуйтесь другими решениями.
Если длинный комментарий в 255 символов обязательно должен храниться в документах в исходном виде, но при этом по нему не требуется выполнять быстрый поиск, сортировку или строить отборы в журналах, мы можем просто отключить индексацию этого поля.
После сохранения изменений платформа удалит описание этого индекса из файла словаря данных 1Cv7.DD и при очередной переиндексации полностью исключит его расчет. Файл 1sjourn.cdx вернется к нормальному компактному размеру.
Что делать, если бизнесу крайне необходим и длинный комментарий (255 символов), и возможность мгновенного поиска по нему в журналах? В таком случае программисты 1С 7.7 применяют обходную технологию разделения данных на "хранилище" и "поисковый индекс":
Комментарий длиной 255 символов, но отключите для него свойства «Сортировка» и «Отбор».КомментарийДляПоиска, с типом "Строка", длиной 50 символов. Для этого реквизита включите свойства «Сортировка» и/или «Отбор».Рассмотрим пример реализации программного заполнения поискового поля при записи документа:
// Процедура, вызываемая перед записью документа
Процедура ПриЗаписи()
// Заполняем короткое индексируемое поле первыми символами длинного комментария
Если ПустаяСтрока(Комментарий) = 0 Тогда
КомментарийДляПоиска = Лев(СокрЛП(Комментарий), 50);
Иначе
КомментарийДляПоиска = "";
КонецЕсли;
КонецПроцедуры
При таком подходе быстрый поиск и отборы в журналах будут осуществляться по полю КомментарийДляПоиска, что абсолютно безопасно для стабильности СУБД CodeBase, а детальный просмотр полной строки комментария будет выполняться из основного неиндексируемого поля Комментарий.
Если база данных имеет большие объемы и активно развивается, лучшим стратегическим решением будет отказ от файлового режима DBF/CDX и переход на использование клиент-серверной версии 1С 7.7 под управлением Microsoft SQL Server.
В версии для MS SQL Server все индексы строятся механизмами промышленной СУБД. Ограничения на размер индексного ключа там несопоставимо выше (например, до 900 байт в старых версиях SQL Server и до 1700 байт в современных редакциях). При переходе на SQL-версию проблема с раздуванием файлов индексов исчезнет раз и навсегда, а общая стабильность информационной базы при многопользовательской работе существенно повысится.