При администрировании крупных баз данных на платформе 1С:Предприятие разработчики часто сталкиваются с необходимостью анализа физической структуры таблиц СУБД. Для этого используется стандартная функция ПолучитьСтруктуруХраненияБазыДанных. Однако на практике возникает неприятная проблема: имена индексов, возвращаемые этой функцией, не совпадают с фактическими именами индексов в СУБД (например, в MS SQL Server или PostgreSQL). Вместо ожидаемого имени индекса, начинающегося с _Document, в СУБД мы видим усеченное имя _Documen.
В этой статье мы подробно разберем, почему возникает такое расхождение, проанализируем внутренние механизмы платформы 1С и рассмотрим надежные способы решения и программного обхода этой проблемы.
Главная архитектурная причина расхождения заключается в том, что функция ПолучитьСтруктуруХраненияБазыДанных с параметром ИменаБазыДанных = Истина возвращает не реальное физическое состояние таблиц в СУБД, а плановую модель (ожидаемые имена), которую платформа 1С рассчитывает увидеть на основе текущей конфигурации и версии платформы. Платформа «думает», что структура базы данных идеально синхронизирована с ее алгоритмами генерации имен.
Однако реальные физические индексы в СУБД могут оставаться в неизменном «устаревшем» виде годами, если соответствующие объекты метаданных долгое время не подвергались процедуре реструктуризации.
Исторически механизмы именования объектов в базах данных 1С претерпевали изменения. Рассмотрим ключевую веху этих изменений:
_Document... физически превращалось в СУБД в _Documen....ПолучитьСтруктуруХраненияБазыДанных стала возвращать унифицированные короткие названия индексов, одинаковые для всех типов СУБД.Если ваша база данных обновлялась «накатом» со старых версий платформы на новые без полной реструктуризации таблиц, физические индексы в СУБД остались старыми (усеченными), в то время как функция новой платформы пытается вернуть обновленное плановое имя. Это и создает опасную иллюзию ошибки, из-за которой внешние скрипты обслуживания СУБД не могут найти нужные индексы.
Ситуация значительно усложняется, если объекты метаданных затронуты расширениями конфигурации. В платформе 1С зарегистрирована официальная ошибка (например, № 60026177), суть которой заключается в неверном формировании суффиксов индексов. Платформа при вызове функции может перепутать порядок суффиксов местами. Например, реальный индекс в СУБД имеет имя _Document1108_1X1, а функция возвращает строку _Document1108X1_1. Любая попытка обратиться по такому имени напрямую из внешнего SQL-скрипта приведет к ошибке.
Самый очевидный и методологически верный способ привести фактическую структуру СУБД к плановому виду — выполнить реструктуризацию. Рассмотрим, как это сделать:
Важное предупреждение: Для терабайтных баз данных процесс реструктуризации крупных таблиц (таких как регистры бухгалтерии или таблицы документов) может занять многие часы или даже дни, парализуя работу пользователей. Поэтому данный метод применим далеко не всегда.
Если вам необходимо написать универсальную обработку обслуживания индексов (например, для дефрагментации или реиндексации средствами СУБД), категорически не рекомендуется завязываться на строковые имена индексов, возвращаемые платформой. Разберем самый надежный алгоритм, используемый опытными разработчиками: сопоставление по составу полей.
Идея метода заключается в том, что состав колонок, входящих в индекс, в 1С и в СУБД всегда совпадает, независимо от того, как этот индекс называется на уровне SQL. Нам нужно получить структуру полей индекса из 1С и найти в системных представлениях СУБД индекс с точно таким же набором физических колонок.
Рассмотрим по шагам программный пример получения состава полей индексов средствами 1С:
// Получаем структуру хранения базы данных для конкретного объекта метаданных
СтруктураТаблиц = ПолучитьСтруктуруХраненияБазыДанных("Документ.РеализацияТоваровУслуг", Истина);
Для Каждого СтрокаТаблицы Из СтруктураТаблиц Цикл
// Обходим все индексы таблицы
Для Каждого СтрокаИндекса Из СтрокаТаблицы.Индексы Цикл
ИмяИндекса1С = СтрокаИндекса.ИмяИндекса;
СоставПолей = Новый Массив;
// Получаем состав колонок, входящих в данный индекс
Для Каждого СтрокаПоля Из СтрокаИндекса.Поля Цикл
СоставПолей.Добавить(СтрокаПоля.ИмяПоляБазыДанных);
КонецЦикла;
// Теперь у нас есть массив имен колонок, формирующих индекс
// Мы можем использовать его для точной идентификации индекса в СУБД
ПроанализируемСоставИндексаВ_СУБД(СтрокаТаблицы.ИмяТаблицыБазыДанных, СоставПолей);
КонецЦикла;
КонецЦикла;
После получения массива колонок в 1С, мы можем выполнить запрос к системным каталогам СУБД. Ниже приведен пример логики SQL-запроса (для MS SQL Server), который позволяет найти реальное имя физического индекса по именам входящих в него колонок:
SELECT
i.name AS IndexName,
OBJECT_NAME(i.object_id) AS TableName
FROM
sys.indexes i
JOIN
sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN
sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
WHERE
OBJECT_NAME(i.object_id) = 'ИмяТаблицыИз1С'
AND c.name IN ('ИмяКолонки1', 'ИмяКолонки2') -- передаем сюда наш массив полей
GROUP BY
i.name, i.object_id
HAVING
COUNT(c.name) = КоличествоПолейВ1С;
Этот подход гарантирует 100% точность сопоставления. Даже если платформа вернула имя _Document1108X1_1, а в СУБД реально существует _Document1108_1X1, ваш скрипт безошибочно определит целевой индекс по набору ключевых полей и выполнит требуемую технологическую операцию.
В ходе анализа структуры хранения базы данных часто обнаруживается избыточное количество индексов (как было упомянуто на форуме — более 20 индексов для одной таблицы). Помните, что каждый лишний индекс существенно замедляет операции записи (вставку, обновление и удаление данных), так как СУБД вынуждена при каждой транзакции перестраивать индексное дерево.
Рекомендуется придерживаться следующих правил оптимизации:
Таким образом, понимание разницы между плановыми именами индексов 1С и фактической структурой таблиц СУБД позволяет избежать критических ошибок при автоматизации администрирования баз данных и повысить общую стабильность работы информационных систем.