Mazmunga o'tish
Tez Base

CHECKDB нашёл ошибки в базе 1С: порядок действий до REPAIR и после

· Chop etilgan:

Бэкап и восстановление

Утро, ночная проверка целостности упала с ошибками, администратор пересылает вывод DBCC CHECKDB и спрашивает: “откатываемся на вчера?”. В выводе служебные имена таблиц, номера страниц и одна и та же рекомендация в конце: repair_allow_data_loss. По ней кажется, что данные теряются в любом случае.

Это не так. Ту же рекомендацию CHECKDB пишет и тогда, когда испорчен только индекс для поиска, где строк 1С нет вовсе. На нашем стенде из четырёх испорченных страниц копия из бэкапа понадобилась для двух, и даже для них откат всей базы на вчера был не нужен: хватило списка конкретных документов.

Ниже порядок, по которому мы проходим такой случай. Каждый шаг проверен на стенде, о нём в конце статьи.

Шаг 0. Чего не делать в первые минуты

Три действия кажутся очевидными и стоят дороже всего:

ДействиеПочему не сейчас
Запустить REPAIR_ALLOW_DATA_LOSSудаляет строки битых страниц и не называет, какие документы удалил. Список после этого собрать можно только по копии
Перебирать документы в 1С, “какой не откроется”каждое чтение битой страницы обрывает вызов ошибкой СУБД 824. Толку мало, нервов много
Восстановить всю базу из бэкапа поверх рабочейвы теряете всё, что введено после бэкапа, ради нескольких документов, которые можно вернуть точечно

Что сделать сразу: сохранить вывод CHECKDB целиком в файл (вкладка “Сообщения” в SSMS или вывод sqlcmd) и снять полный бэкап базы как есть, с повреждением. Он пригодится, если исправление удалит больше, чем ожидали.

Шаг 1. Найти в выводе таблицу и номер индекса

Из всего вывода для решения нужны два поля каждой битой страницы. Имя таблицы стоит в итоговой строке “в таблице …”, номер индекса в самих сообщениях (“идентификатор индекса 1”). Если итоговые строки потерялись при копировании, имя и индекс по числам даст сам SQL Server:

-- Числа берутся из сообщения CHECKDB: идентификатор объекта и идентификатор индекса
DECLARE @obj int = 680389493;
SELECT OBJECT_NAME(@obj) AS table_name,
       i.index_id,
       i.name           AS index_name,
       i.type_desc
FROM sys.indexes AS i
WHERE i.object_id = @obj
ORDER BY i.index_id;

Как читать номер индекса:

index idЧто этоЧто лежит
1кластерный индекссами строки таблицы: шапки документов, строки табличных частей, движения
больше 1некластерный индекскопия нескольких полей для поиска, по дате или номеру. Строк 1С нет
0таблица без кластерного индексав базах 1С редкость. По соседним страницам не разобрать, только сверкой с копией

Ещё пригодятся номера соседних страниц. В сообщениях 8976 и 8978 CHECKDB называет страницу до испорченной и после неё, по ним потом собирается список документов.

Шаг 2. Перевести таблицу в объект 1С

Имя вида _Document520 в объект метаданных переводит сама платформа. Запускаем в любой консоли кода под пользователем с полными правами:

ИмяТаблицы = "_Document520"; // из итоговой строки CHECKDB
// Пустой первый параметр - вся конфигурация, Истина - имена как в SQL Server
Для Каждого Описание Из ПолучитьСтруктуруХраненияБазыДанных(, Истина) Цикл
	Если НРег(Описание.ИмяТаблицыХранения) = НРег(ИмяТаблицы) Тогда
		Сообщить(Описание.Метаданные + " (" + Описание.Назначение + ")");
		Для Каждого Индекс Из Описание.Индексы Цикл
			Сообщить("  индекс " + Индекс.ИмяИндексаХранения);
		КонецЦикла;
	КонецЕсли;
КонецЦикла;

На стенде ответ был Документ.РеализацияТоваровУслуг (Основная) и восемь индексов, среди них кластерный _Document520HPK и _Document520_ByDocDate по дате. Функция платформенная, работает в любой конфигурации, с БСП и без неё.

Шаг 3. Вердикт по виду таблицы

Поле Назначение из шага 2 и номер индекса из шага 1 вместе дают решение. Сводная таблица, по которой мы сортируем битые страницы:

Что задетоВердиктЧем восстанавливать
некластерный индекс (index id больше 1)данные целыперестроить индекс, шаг 4
движения регистра накопления, бухгалтерии, расчётабез бэкапаперепровести документы-регистраторы, шаг 5
итоги регистра (Итоги)без бэкапапересчёт итогов штатными средствами
регистрация изменений для обмена (РегистрацияИзменений)без бэкапазаново зарегистрировать изменения для узла или полная синхронизация
шапки документов, справочников, планов счетов (Основная)нужна копиявернуть объекты из копии по списку, шаг 6
табличная часть (ТабличнаяЧасть)нужна копиядокумент возвращается из копии целиком
независимый регистр сведений, константанужна копиязаписи вводились руками, пересчитать не из чего
таблицы, где платформа хранит конфигурациюразбирать вручнуюбаза может не открыться вовсе, это работа администратора и бэкапа

Оговорка к движениям: ручные корректировки движений проведение не вернёт. Если в вашей конфигурации регистр заполняют руками, читайте “без бэкапа” для него как “нужна копия”.

Оговорка к итогам: пересчитывать всю историю после битой страницы не обязательно. Чек-ап итогов и остатков 1С сверяет итоги с движениями по каждой границе месяца, находит первый месяц, где они разошлись, и строит пересчёт за один-два месяца от него, а потом проверяет результат.

Шаг 4. Битый индекс: перестроить в правильном порядке

Первый случай на стенде: испорчена страница индекса _Document520_ByDocDate. CHECKDB выдал те же четыре сообщения и ту же рекомендацию repair_allow_data_loss, что и на потерянных документах. Строк при этом не пропало ни одной.

Простой ALTER INDEX ... REBUILD упал с той же ошибкой 824: при перестроении SQL Server читает старый индекс и спотыкается о битую страницу. Сработал порядок “отключить, потом построить”:

-- Отключённый индекс строится заново из таблицы, старые страницы не читаются
ALTER INDEX [_Document520_ByDocDate] ON [dbo].[_Document520] DISABLE;
ALTER INDEX [_Document520_ByDocDate] ON [dbo].[_Document520] REBUILD;
-- Повторная проверка
DBCC CHECKDB WITH NO_INFOMSGS, ALL_ERRORMSGS;

После этого CHECKDB чистый, в индексе 3 000 строк, в таблице тоже 3 000. Делайте это без пользователей: пока индекс отключён, запросы по дате идут медленнее, а уникальный индекс не следит за уникальностью. Штатную реиндексацию из тестирования и исправления на битом индексе мы не проверяли.

Шаг 5. Движения регистра: какие документы перепровести

Второй случай: страница регистра “Товары на складах”, на ней 44 движения десяти документов, восьми реализаций и двух приобретений. Для самих движений бэкап не нужен: их создаёт проведение. Нужен только список регистраторов. В строке регистра регистратор записан двумя полями: _RecorderTRef с номером таблицы документа (у реализаций на стенде 520, как в _Document520) и _RecorderRRef со ссылкой.

Здесь стенд показал неожиданную вещь. Кластерный индекс этого регистра в УТ упорядочен по периоду, и граница страницы режет документ посередине: у РТ-001481 строки 2 и 3 лежали на битой странице, а строка 1 на соседней, целой. В список на перепроведение он попадает, но “пропали все движения” про него сказать нельзя.

Порядок такой: битая страница убирается (шаг 7), документы из списка перепроводятся. Если документ потерян целиком, сначала он возвращается из копии, потом проводится: без регистратора проводить нечего.

Шаг 6. Шапки и табличные части: список документов до исправления

Третий и четвёртый случаи: страница самих реализаций и страница их табличной части “Товары”. Пересчитать их не из чего, нужна копия из бэкапа. Вопрос только в том, какие документы из неё брать, и ответить на него можно двумя путями.

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

-- Нужны права sysadmin. 0 - текущая база, 1 - номер файла, дальше номер страницы
-- из сообщений 8976/8978. Режим 3 показывает значения колонок по слотам.
DBCC PAGE (0, 1, 136101, 3) WITH TABLERESULTS;  -- страница до битой
DBCC PAGE (0, 1, 136103, 3) WITH TABLERESULTS;  -- страница после битой

Сами строки диапазона есть в любом уцелевшем некластерном индексе той же таблицы: каждый некластерный индекс хранит полный ключ кластерного. Запрос с явным указанием индекса берёт поля из него и в кластерный индекс не спускается, поэтому битую страницу никто не читает:

-- Схема запроса. Границы - ключи с соседних страниц из DBCC PAGE.
-- Выбирать только поля, которые есть в индексе, иначе запрос пойдёт за ними
-- в кластерный индекс и упадёт на битой странице.
SELECT a._IDRRef, a._Date_Time
FROM dbo._Document520 AS a WITH (INDEX([_Document520_ByDocDate]))
WHERE a._IDRRef > 0x...   -- последний ключ предыдущей страницы
  AND a._IDRRef < 0x...   -- первый ключ следующей страницы
OPTION (MAXDOP 1);

Отдельно мы обнулили у страницы реализаций весь заголовок, 96 байт. Вместо 8939 пришло сообщение 8909 с объектом 0: страница больше не знает, чья она. Путь по соседям всё равно дал те же девять документов.

Сверкой с копией средствами 1С. Последний бэкап до сбоя поднимается отдельной информационной базой. В обеих базах снимается слепок обычными запросами: ссылки на объекты, число строк табличной части и движений по каждому владельцу. Что есть в копии и пропало в рабочей, то и потеряно. На стенде слепок документа и регистра, 10 499 строк, снимался 0,7 секунды на сервере, сравнение шло 1,2-1,4 секунды.

Оба пути дали одно и то же, и это совпало с тем, что лежало на страницах до порчи:

СтраницаДо порчиНашлось
реализации9 документов, РТ-001342 … РТ-0013509, те же
табличная часть “Товары”19 строк у 5 документов, РТ-001434 … РТ-00143819 у 5
регистр “Товары на складах”44 движения у 10 документов44 у 10

Ключ из SQL Server приходит в виде 16 байт, а в 1С это уникальный идентификатор с переставленными байтами. Перестановку мы сверили по документу с целой страницы:

Двоичное = "0x978EAC120374CE0811F1BA452A5281FD"; // _IDRRef документа РТ-001400
Шестн = НРег(Сред(Двоичное, 3));
УИД = Сред(Шестн, 25, 8) + "-" + Сред(Шестн, 21, 4) + "-" + Сред(Шестн, 17, 4)
	+ "-" + Лев(Шестн, 4) + "-" + Сред(Шестн, 5, 12);
// УИД = "2a5281fd-ba45-11f1-978e-ac120374ce08", совпал с идентификатором в 1С
Ссылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(Новый УникальныйИдентификатор(УИД));

В рабочей базе реквизиты такой ссылки читать нельзя, страница битая. Её место в копии: по идентификатору документ находится однозначно, даже если номер повторяется в разных годах.

Шаг 7. Исправление и то, что после него остаётся

Только когда список снят и бэкап с повреждением лежит рядом, администратор исправляет базу. На отдельной копии, где испорчены все четыре страницы сразу, мы прогнали REPAIR_ALLOW_DATA_LOSS и сравнили результат с копией до порчи.

REPAIR удалил ровно содержимое битых страниц: девять реализаций, 19 строк табличной части у пяти документов, 44 движения у десяти. Индекс по дате перестроил сам. Отчитался строкой “страница освобождена”, без единого номера документа.

Главная ловушка этого шага: у девяти удалённых реализаций их строки “Товаров” и движения лежали на других, целых страницах, и REPAIR их не тронул. Это 41 строка табличной части и 41 движение по складу. База открывается, повторный CHECKDB чистый, а остатки на складе считаются в том числе по документам, которых уже нет. Мы нашли эти строки запросом к копии. Поймает ли их штатное тестирование и исправление, не проверяли.

Если у базы модель восстановления FULL и цепочка бэкапов журнала непрерывна, есть путь мягче REPAIR: SQL Server умеет вернуть из бэкапа отдельные страницы, RESTORE DATABASE ... PAGE. На стенде модель SIMPLE, этот путь мы не проверяли.

Дальше документы из списка переносятся из копии штатно (выгрузка и загрузка данных XML по списку), документы с пропавшими движениями перепроводятся. Документ из копии вернётся в состоянии на момент бэкапа: правки, сделанные после, повторяют руками. Документ, введённый после бэкапа и потерянный на битой странице, сверка не увидит, в копии его нет. Такие ищут по первичке и журналу регистрации за период между бэкапом и сбоем.

На чём это проверено

Копия пустой типовой УТ для Казахстана 3.4 на MS SQL Server 2022, платформа 8.3.27. Данные синтетические: 3 000 реализаций и 1 500 приобретений товаров, у каждого документа от двух до шести строк “Товаров” и движения по регистру “Товары на складах”. Страницы портились недокументированной командой DBCC WRITEPAGE в однопользовательском режиме: восемь байт мимо кэша, контрольная сумма перестаёт сходиться, для SQL Server это выглядит как сбой диска. Четыре случая по отдельности, каждый с чистой копии, и пятый со всеми четырьмя страницами сразу. Что лежало на каждой странице до порчи, записано заранее.

Чего мы не проверяли: несколько битых страниц подряд (соседка тоже нечитаема, граница берётся дальше), битую страницу промежуточного уровня индекса, файловые базы и PostgreSQL. Перевод таблиц в объекты платформенный, а сам разбор гонялся только на УТ для Казахстана.

Готовая обработка

Шаги 1-3 и сверку из шага 6 мы собрали во внешнюю обработку “Повреждение базы 1С на MS SQL: что задето и что поднимать из бэкапа”, она продаётся на Инфостарте за 10 SM. На вход вывод CHECKDB как есть, на выходе объекты 1С с цветным вердиктом по каждой битой странице и план восстановления. Список пропавших документов с номерами и датами даёт сверка рабочей базы с копией из бэкапа. К SQL Server обработка не подключается и в базу не пишет. Что видно в её отчёте на стенде, показано на странице инструмента.

Чтобы такой разбор не пришлось делать утром после аварии, CHECKDB стоит гонять по расписанию, лучше на копии из бэкапа: как это встроить в регламент, разобрано в статье про регламентное обслуживание СУБД под 1С, а восстановление копии с предохранителями в разборе восстановления базы 1С из бэкапа SQL. Проверить, что сервер и бэкапы под базой настроены правильно, помогает Чек-ап СУБД.

CHECKDB нашёл ошибки, и непонятно, что поднимать из бэкапа

Разберём вывод проверки в терминах 1С, вернём индекс и движения без бэкапа, а потерянные документы поднимем из копии по списку

Narxi
450 000 ₸ danbir martalik sozlash; kuzatib borish - oyiga 150 000 ₸ dan; soliqlarsiz

Yozishga erta? O'zingiz o'lchang

Повреждение базы 1С на MS SQL: что задето и что поднимать из бэкапа

Ishlov berishni ochish

INFOSTART TECH EVENT 2026: конференция для 1с-специалистов. если собираетесь, регистрируйтесь по нашей ссылке. Регистрация →

Buni ham o'qing

База 1С не открывается после обновления конфигурации: порядок действий, когда копии нет

Конфигуратор пишет "При обновлении данных, после последней реструктуризации, произошла критическая ошибка", пользователи в базу не попадают, копии до обновления нет. Разбираем по шагам: что сохранить первым, как по журналу регистрации найти этап, на котором упало, какие действия только добавляют ошибок, когда бросать починку старой базы и как через ibcmd выгрузить .dt из базы, которая не открывается, собрать новую и тихо подменить её в кластере. В конце - задания резервного копирования, после которых такая авария превращается в откат на минуту до обновления.

Остатки в 1С не сходятся с движениями: как найти сломанный месяц итогов и не пересчитывать всю историю

Отчёт по движениям даёт одно число, запрос к остаткам другое, перепроведение ничего не меняет. Разбираем, как отличить сломанные итоги от ошибки в движениях, каким запросом найти позицию и месяц расхождения, почему строку итогов на 1 августа чинит пересчёт за август, а не за июль, в каком порядке пересчитывать текущие итоги и как посмотреть саму строку итогов на SQL. Все шаги проверены на тестовой копии УТ 11.5 с испорченной строкой.

Скрипт нейросети за ночь пометил 5 700 документов в рабочей базе 1С: где были двери и как их закрыть

Агент написал скрипт, планировщик запускал его каждый час, условие поиска дублей поймало пустое основание, и к утру остатки в рабочей базе уехали на миллиардные суммы. Разбираем цепочку из пяти разумных шагов, которая к этому привела, ошибку в определении дублей и правила, после которых агент в рабочую базу больше не пишет.