База 1С весом 4,2 терабайта. Ночной бэкап — два часа и 556 ГБ. Места на дисках почти нет, кассиры ждут список чеков по 25 секунд, а вечером, в час закрытия смен, всё «залипает». Знакомая картина? Нам предстояло с ней разобраться — и первое, что мы сделали, это не стали ничего чинить. Две недели ушло на диагноз. Он того стоил: выяснилось, что больше 90 % базы — вообще не данные бизнеса.
Это история-расследование о диагностике: с картой объёмов, тремя красивыми гипотезами, которые не подтвердились, и неожиданным виновником, который съел 3,85 из 4,2 терабайт. Спойлер: это была не история продаж и не версии документов.
Завязка: пациент и симптомы
Вводные. Розничная сеть fashion-сегмента: три страны, около 200 касс, 11 боевых баз 1С (Розница + ERP). Главная база — 4,2 ТБ — росла быстрее, чем бизнес, который она обслуживает. Симптомы на момент обращения:
- Диски. Файл данных — 4 197 ГБ, свободного места на сервере почти не осталось. Дальше — только закупка СХД.
- Бэкапы. Полный ночной бэкап — около 2 часов и 556 ГБ в сжатом виде. Восстановление тестового контура — событие, которое планируют заранее.
- Кассы. Список чеков под кассиром открывался ~25 секунд. В вечерний пик закрытие смен подвисало.
- Соседи. SQL-сервер общий: на одном инстансе живут десятки баз и делят диск, память, tempdb и процессорные ядра.
Всё это — боевой контур работающей розницы: останавливать торговлю нельзя, терять данные нельзя, ошибаться в правах доступа — тем более нельзя.
Метод: карта «что сколько занимает» — прежде любых действий
По опыту, в задачах вида «база слишком большая и всё тормозит» самое дорогое — это не решение, а правильный диагноз. Инструмент диагностики штатный и доступен каждому: метод глобального контекста ПолучитьСтруктуруХраненияБазыДанных() возвращает соответствие объектов метаданных таблицам хранения. Дальше остаётся сопоставить этому списку размеры таблиц из административных отчётов СУБД (стандартные отчёты о занимаемом месте, доступные администратору сервера) — и отсортировать.
В нашем случае карта связала 3 585 таблиц с метаданными. Ожидания у всех участников были стандартные: «наверное, документы за десять лет», «наверное, версии объектов», «наверное, логи». Реальность оказалась интереснее:
| Что | Объём |
|---|---|
| История версий шаблонов ограничения доступа | 3,34 ТБ |
| Очередь «пересчитать ключи доступа пользователей» (1,18 млрд строк) | 287 ГБ |
| Очередь «пересчитать ключи доступа к данным» (1,19 млрд строк) | 221 ГБ |
| Итого: служебный кэш механизма разграничения доступа | ≈ 3,85 ТБ из 4,2 ТБ |
Прочитайте таблицу ещё раз. Больше 90 % четырёхтерабайтной базы — не данные бизнеса. Это служебный кэш универсального механизма ограничения доступа на уровне записей (RLS в терминологии БСП), который годами рос и никогда не использовался по назначению: регламентные задания пересчёта ключей доступа были выключены ещё в 2020 году. Механизм исправно складывал в очереди задания «пересчитать», которые никто никогда не забирал, и версии шаблонов ограничений, которые никто никогда не читал.
То есть база не «разжирела от документов». Она годами копила ТОДО-лист, который никто не собирался выполнять. 2,37 миллиарда строк ТОДО-листа.
Откуда вообще берётся такой кэш
В типовых конфигурациях на «Библиотеке стандартных подсистем» есть два способа ограничивать доступ на уровне записей. Классический — условие подставляется прямо в текст запроса каждого списка: дёшево в хранении, но каждое чтение платит за вычисление условия. И универсальный — система заранее рассчитывает «ключи доступа»: материализует для каждого пользователя и каждого объекта ответ на вопрос «видит / не видит», чтобы в момент чтения оставалось только соединиться с готовой таблицей ключей.
Универсальный механизм — это по сути гигантский материализованный кэш прав. И как любой кэш, он требует инвалидации: каждое изменение ролей, профилей или состава пользователей ставит в очередь задания на пересчёт ключей, а изменения шаблонов ограничений версионируются. Пока регламентные задания пересчёта работают, очереди перемалываются и система находится в равновесии. Но если задания однажды выключить — например, потому что пересчёт грузил сервер, — механизм не останавливается. Он продолжает прилежно ставить задачи в очередь, которые больше никто не забирает, и накапливать версии шаблонов, которые больше никто не читает. Никаких ошибок, никаких предупреждений: просто две очереди по миллиарду строк и 3,34 ТБ истории версий шесть лет спустя. Идеальное преступление.
Глава, которую мы любим больше всего: отброшенные гипотезы
В отчётах об успешных проектах обычно пишут только то, что сработало. Это создаёт у читателя иллюзию, что авторы шли к цели по прямой. Мы шли не по прямой — и три правдоподобные гипотезы, каждая из которых стоила бы недели работы впустую, были проверены и отброшены. Рассказываем, потому что сами гипотезы наверняка придут в голову и вам.
Гипотеза 1. «RLS отключён — значит, всё это мусор, сносим целиком»
Раз регламентные задания пересчёта выключены с 2020 года, соблазнительно решить, что механизм мёртв целиком: очистить кэш, отключить ограничения, разойтись. Проверка ролей показала обратное: 208 ролей реально используют ограничения доступа по условию. Механизм жив, им пользуются каждый день, просто его кэширующая часть превратилась в свалку. Снести «всё целиком» означало бы открыть кассирам чужие магазины.
Гипотеза 2. «Мусор накопили уволенные сотрудники — почистим по ним»
Красивая версия: справочник пользователей разросся до 5 600 карточек, из которых активны ~150. Логично предположить, что ключи доступа уволенных и составляют массу кэша. Посчитали: живых ключей доступа — 660 строк. Из миллиардов. Эффект от чистки «по уволенным» — десятки килобайт. Не гигабайт. Килобайт.
Гипотеза 3. «Виноват вот этот конкретный медленный регистр»
В метриках сервера СУБД стабильно светился один регистр с чудовищными чтениями — идеальный подозреваемый. При внимательном разборе выяснилось, что регистр… из соседней базы на том же инстансе. Урок бесплатный, но выстраданный: на общем сервере любую метрику сначала фильтруйте по конкретной базе. Иначе будете неделю оптимизировать чужую систему.
Почему «просто удалить кэш» нельзя — и что делать сначала
Ключевая развилка проекта: пока динамические списки работают через универсальный механизм, его кэш нельзя трогать — без кэша универсальный RLS начнёт вычислять права «на лету», и кассы лягут окончательно. Значит, сначала база переводится с универсального механизма разграничения доступа на классический — отбор по магазину прямо в запросах динамических списков. Это полностью прикладная доработка: отбор внедрён в 23 документах средствами конфигурации. После этого кэш становится по-настоящему мёртвым, а списки начинают работать быстро, потому что перестают тащить за собой каскад служебных соединений.
Замер эффекта на списке чеков (с учётом RLS): 162 млн логических чтений → 94. Плюс отдельно — добавление недостающих индексов под кассовые операции: список чеков открылся мгновенно вместо 25 секунд, 505 410 логических чтений → 4. Такой порядок улучшения — почти всегда признак того, что раньше запрос просматривал таблицу целиком; никакой магии, просто индекс, которого не хватало годами.
Права — только через матрицу эквивалентности
Смена механизма доступа — точка максимального риска всего проекта: права — единственная область, где «почти как раньше» равно «авария». Кассир, увидевший чужой магазин, — инцидент безопасности; менеджер, потерявший свой, — остановка работы. Поэтому перед переключением прогонялась матрица эквивалентности прав: 329 проверок «кто что видит до и после» по комбинациям ролей и сценариев, с фиксацией результата по каждой строке. Расхождений — 0. Это самая скучная таблица проекта, и мы ни разу не пожалели о часах, потраченных на её заполнение: скучная таблица сильно приятнее интересного инцидента.
Тем же принципом проверялись доработанные отчёты: результат «до» и «после» сравнивается не «на глаз», а контрольной суммой по нормализованной выгрузке. Дёшево — и снимает все споры об «идентичности данных».
Вечерний пик: все думали на блокировки — виноват был параллелизм
Второй сюжетный поворот расследования. Все были уверены, что вечерние залипания касс — это блокировки. Аудит показал: блокировок в пик — ноль. Душил кассы агрессивный параллелизм: заводские настройки сервера СУБД (cost threshold for parallelism = 5, MAXDOP = 0) на 48-ядерном сервере отправляли даже лёгкие запросы разбегаться по всем ядрам, и две трети запросов в пик просто стояли в очереди за потоками. Лечение — административная настройка сервера: cost threshold 5 → 50, MAXDOP 0 → 8, динамически, с заранее подготовленным откатом. Это стандартные серверные параметры, рекомендации по которым есть в любой методике обслуживания нагруженных СУБД.
Что было дальше — и что осталось за рамками статьи
Диагноз определил план: доказанно мёртвый служебный кэш и устаревшая история подлежат очистке, регламентные механизмы — приведению в порядок, индексы и статистика — обслуживанию. Для самой очистки у администратора есть штатный инструментарий, и выбор зависит от объёма и допустимого окна:
- объектное удаление средствами платформы — порциями, в фоновых заданиях, с контролем ссылочной целостности;
- штатные регламентные процедуры БСП — у механизмов версий и очередей есть собственные средства очистки, которые нужно включить и настроить;
- «Тестирование и исправление» с опцией сжатия таблиц — освобождает место после массовых удалений;
- выгрузка/загрузка через DT — полностью перестраивает базу и убирает фрагментацию: эффективный способ «сбросить вес» после очистки;
- регламентное обслуживание СУБД без изменения данных — обновление статистики, дефрагментация индексов, настройки производительности сервера: это административные операции, не затрагивающие данные.
Процедурная дисциплина при любой очистке одна и та же: полные репетиции на копии, контрольные сверки остатков «до/после», точки отката, приёмка на стороне заказчика. Детали исполнения сознательно вынесены за рамки этой статьи: здесь нам важно было показать, как ставится диагноз и как доказывается, что данные действительно мёртвые — потому что именно на этом этапе рождаются и катастрофы, и успехи.
Результат для понимания масштаба: база — 105 ГБ вместо 4 197, полный бэкап — 18,3 ГБ вместо 556 и минуты вместо двух часов, кассы открывают список чеков мгновенно. Приёмку проводили не мы: представители заказчика под ограниченными правами прошли по чекам, отчётам, остаткам и разграничению доступа. Замечаний не было. Мы вообще считаем, что приёмка глазами исполнителя — это оксюморон: исполнитель смотрит туда, где ожидает увидеть успех.
Чек-лист диагностики для тех, у кого база «весит как чугунный мост»
Если у вас конфигурация на БСП с универсальным ограничением доступа и база подозрительно велика:
- Постройте карту объёмов.
ПолучитьСтруктуруХраненияБазыДанных()+ административные отчёты о размерах таблиц, отсортировать по убыванию. Диагноз — до любых действий. Наши 3,85 ТБ кэша нашлись именно так. - Проверьте таблицы механизма доступа БСП: версии шаблонов ограничений, очереди обновления ключей доступа. Если регламентные задания пересчёта выключены, а таблицы растут — вы, вероятно, нашли своего пожирателя дисков.
- Не удаляйте кэш, пока не разобрались, кто им пользуется. «Задания выключены» ≠ «механизм мёртв». Посчитайте роли с ограничениями по условию.
- На общем инстансе фильтруйте метрики по своей базе. Иначе рискуете оптимизировать соседей.
- Проверьте параллелизм до охоты на блокировки. Заводские
cost threshold for parallelismиMAXDOPна многоядерном сервере — мина, которая маскируется под «блокировки в пик». - Любое изменение механизма прав — только через матрицу эквивалентности «роль × сценарий × видимость» до и после. У нас в ней было 329 строк, и жалеть не пришлось ни разу.
- Отчёты сверяйте контрольной суммой по нормализованной выгрузке, а не глазами.
Вместо эпилога
Самое поучительное в этой истории, на наш взгляд, не цифры. А то, что четыре терабайта проблем не были следствием чьей-то ошибки в моменте. Каждый участник в своё время действовал разумно: механизм доступа включили, потому что он был нужен; задания пересчёта выключили, потому что они грузили сервер; на растущую базу махнули рукой, потому что «диски пока есть». Система деградировала маленькими рациональными шагами — и «внезапно» оказалось, что бэкап идёт два часа, а бизнес живёт на 2,5 % своей базы, нося на спине остальные 97,5.
Поэтому главный вывод скучен, как и всё главное: измеряйте. Карта «что сколько занимает» стоит двух недель работы и отвечает на вопрос, который дороже всех остальных: что из этого вообще ваши данные.
Если у вас база тоже «весит как чугунный мост» — начните с карты объёмов из чек-листа. А вопросы и свои грабли несите в комментарии: самое интересное в таких историях обычно всплывает именно там.
Вступайте в нашу телеграмм-группу Инфостарт