Почему в 1С 7.7 различаются суммы в оборотно-сальдовой ведомости и карточке счета?

Программист 1С v7.7 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При работе в 1С:Предприятии 7.7 в связке с MS SQL Server (особенно версий 2008, 2012 и выше) разработчики и бухгалтеры иногда сталкиваются с неприятной ситуацией: оборотно-сальдовая ведомость (ОСВ) показывает корректные обороты и конечное сальдо, а в карточке счета или карточке субконто итоговые суммы отличаются. Разберем по шагам, почему возникает такое расхождение и как восстановить правильную работу отчетов.

Проанализируем типичный фрагмент программного кода формирования карточки счета:


Ит = СоздатьОбъект("БухгалтерскиеИтоги");
Ит.ВыполнитьЗапрос(НачДата, КонДата, Счет, , , , "Проводка");
Ит.ВыбратьПериоды();
Пока Ит.ПолучитьПериод() = 1 Цикл
    Опер = Ит.Операция;
    // обработка движений и вывод строк
КонецЦикла;

Симптом ошибки заключается в том, что метод ПолучитьПериод() при итерации по проводкам доходит до определенной даты или документа и преждевременно прерывает цикл (возвращает 0), несмотря на то, что в базе есть последующие проводки. В результате отчет не учитывает часть оборотов и выводит неверное конечное сальдо.

Выясним причину расхождения между отчетами

Рассмотрим внутреннее устройство хранения и выборки данных в 1С 7.7:

  1. Разные таблицы-источники данных: Оборотно-сальдовая ведомость формируется по таблицам агрегированных итогов (_1SBKTTL и _1SBKTTLC), где хранятся свернутые остатки и обороты на начало расчетных периодов. Карточка счета с периодичностью "Проводка" обращается непосредственно к таблице проводок _1SENTRY и операциям _1SOPER.
  2. Особенности серверных курсоров SQL Server: Платформа 1С 7.7 использует динамические серверные курсоры через ODBC. На современных версиях MS SQL Server оптимизатор запросов при высокой фрагментации индексов таблицы _1SENTRY может некорректно обрабатывать сортировку по составному индексу DATE_TIME_DOCID, что приводит к внезапному закрытию курсора выборки.
  3. Коллизии в распределенных базах (УРБД): При активном обмене данными между филиалами и перепроведении документов задним числом порядок записей в составном индексе может нарушаться, из-за чего обход периода прекращается раньше времени.
  4. Фрагментация индексов и устаревшая статистика: После массовых перепроведений документов статистика распределения данных деградирует, заставляя SQL Server выбирать неоптимальный план сканирования таблицы проводок.

Способ 1. Пересчет итогов и реиндексация базы данных

Первый шаг при обнаружении проблемы — восстановление целостности итогов и индексов средствами платформы:

  1. Выполним резервное копирование информационной базы.
  2. Запустим 1С 7.7 в режиме Монопольно.
  3. В меню Операции выберем пункт Управление бухгалтерскими итогами и выполним полный пересчет итогов за все периоды.
  4. В конфигураторе выполним пункт меню Администрирование > Реиндексация таблиц информационной базы (или полную процедуру Тестирование и исправление ИБ).

Если проблема повторяется систематически, выполним процедуру полной перегрузки базы: выгрузим данные через конфигуратор (Администрирование > Выгрузка данных), создадим чистую базу данных в MS SQL Server и выполним загрузку данных в новую БД.

Способ 2. Настройка регламентного обслуживания MS SQL Server

Чтобы исключить сбои курсоров из-за фрагментации данных, настроим в среде SQL Server Management Studio (SSMS) регулярное обслуживание таблиц базы данных:

  1. Перестроение индексов (Rebuild Index): Настроим регулярный план обслуживания (Maintenance Plan), выполняющий перестроение всех индексов для основных таблиц бухгалтерского учета: _1SENTRY, _1SOPER, _1SJOURN, _1SBKTTL, _1SBKTTLC.
  2. Обновление статистики: Включим шаг обновления статистики с полным сканированием (UPDATE STATISTICS WITH FULLSCAN). Свежая статистика позволяет оптимизатору SQL корректно поддерживать открытые динамические курсоры 1С.

Способ 3. Альтернативный обход проводок в коде отчетов

Если специфика базы или интенсивный обмен в УРБД приводят к регулярным сбоям метода БухгалтерскиеИтоги с детализацией до проводки, изменим алгоритм выборки данных в отчете.

Вместо обхода периодов через объект БухгалтерскиеИтоги получим им только начальное сальдо, а детальные движения выберем стандартным методом ВыбратьПроводки():


// Получаем начальные остатки
Ит = СоздатьОбъект("БухгалтерскиеИтоги");
Ит.ИспользоватьСубконто(ВидыСубконто.Контрагенты, ВыбКонтрагент, 2);
Ит.ВыполнитьЗапрос(НачДата, КонДата, ВыбСчет);

// Обходим проводки напрямую через объект Проводка/Операция
Пр = СоздатьОбъект("Проводка");
Пр.ВыбратьПроводки(НачДата, КонДата, ВыбСчет);
Пока Пр.ПолучитьПроводку() = 1 Цикл
    // Проверяем соответствие условиям и выводим строку карточки
    Док = Пр.Документ;
    СуммаПроводки = Пр.Сумма;
КонецЦикла;

Также эффективным решением для высоконагруженных баз является перевод тяжелых аналитических отчетов (карточек счетов и субконто) на прямые SQL-запросы к таблицам _1SENTRY и _1SOPER с явной сортировкой ORDER BY DATE_TIME_DOCID. Это полностью исключает ошибки платформенных курсоров и в разы ускоряет построение отчетов.

← На главную