Как я восстанавливал разрушенную базу. АКТ 2

Приёмы, которые помогут тебе устранить рассинхронизацию данных и метаданнах (на уровне SQL)

ДИСКЛЕЙМЕР

Автор не несет никакой ответственности, кроме как за достоверность предоставленной информации.
Всю нижеследующую информацию воспринимать и использовать на свой страх и риск. 

ПРЕДЫСТОРИЯ ЗДЕСЬ

После вступительной части была получена база, которая нормально открывалась (как в конфигураторе, так и в режиме предприятия), аварийное завершение с записью дампа спровоцировать не получалось — это уже было намного лучше, чем первоначальное состояние.

Но и работать с базой было нельзя. Открытие формы констант, определенных документов, попытка обновить конфигурацию ИБ и другие обычные действия — давали исключения уровня СУБД с добровольно-принудительным предложением завершить работу 🙂 Читайте ниже о том, как я победил каждое из них.

Примеры ошибок и приёмы лечения

Проблема №1. Нехватка поля (реквизита объекта либо константы)

Симптомы: 

При попытке открыть форму объекта/констант/etc видим

Ошибка СУБД:
Microsoft OLE DB Provider for SQL Server: Invalid column name ‘_Fld123’

Диагноз:

Очевидно, что в схеме базы (в «метаданных») поле есть. А в реальной таблице — нет.
То есть в новом релизе было добавлено поле, но так как не было реструктуризации — его нет в реальных таблицах.

Что делать:

Как ни странно, добавить недостающее поле 🙂 Для этого нам нужно знать, в какую таблицу и какого типа.

В расследовании поможет профайлер (MS SQL Profiler).

Запускаем трассировку, воспроизводим ошибку, делаем поиск по имени поля, в идеале попадаем в запрос вида как на картинке.

Имя таблицы — в первой строке запроса, тип поля — параметр справа от самого поля.

Нехватка поля, 1

 

В итоге у нас есть: куда и что добавить, и какого типа.

Добавим же это поле в SQL-студии, для этого нам поможет оператор ALTER TABLE … ADD 

После добавления поля в таблицу — во всех строках в этом поле будет значение NULL, что не годится, так как как правило вызывает ошибки преобразования типов (например в поле должно быть Булево, и есть строки кода

Если ЭтоДобавленноеПоле Тогда

или

РеквизитТипаБулево=ЭтоДобавленноеПоле

)

поэтому заполним сразу неким значением по-умолчанию

Я обычно заполнял единичкой (для ссылок, чисел и булево) либо пустой строкой » для типа ntext

Пример скрипта

-- добавление в таблицу новой колонки
ALTER TABLE ИмяТаблицы ADD ИмяПоля ТипПоля NULL;
-- заполнение дефолтным значением
UPDATE ИмяТаблицы
SET ИмяПоля=ДефолтноеЗначение 

Добавление недостающих колонок

При выполнении обращайте внимание на контекст выполнения, то есть в какой базе будет выполнен запрос. Для уверенности можно использовать явное указание через USE

USE target_base
GO

Выделяем нужный фрагмент, выполняем выделенный фрагмент текста запроса нажатием на Execute

Если всё ок — внизу отображается количество обработанных строк (цифры будут меняться в зависимости от реального количества строк в обрабатываемых таблицах)

Если всё сделали правильно — ошибка исчезнет.

Проблема №2. Наоборот, лишнее поле

Симптомы: 

При попытке записать объект видим

Ошибка СУБД:
Microsoft OLE DB Provider for SQL Server: Cannot insert the value NULL into column ‘_Fld123’table ‘SufferedBase.dbo._Document234’column does not allow nullsINSERT fails.

Напрямую не мешает, но косвенно жить не даёт 🙂

Дело в том, что многие поля на уровне SQL имеют ограничение NOT NULL. То есть NULL туда записать нельзя. И при записи 1С явно передаёт в SQL через INSERT какие поля и какими значениями заполнить.

И если в SQL есть поле, про которое 1С не знает — значит неявно получится попытка записать в это поле NULL. И будет следующая ошибка 

Ошибка вставки НУЛЛ

Диагноз:

В новом релизе поле было удалено. В схеме базы (в «метаданных») поля уже нет. А в реальной таблице — осталось.

Что делать:

Решением будет удалить это поле из таблицы SQL.

С помощью конструкции 

ALTER TABLE ИмяТаблицы DROP COLUMN ИмяПоля;

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

Лишние реквизиты - как лечить

Проблема №3. Количество полей в реальной таблице SQL отличается от количества полей в метаданных

Симптомы: 

При попытке записать объект с заполненной табличной частью

Ошибка СУБД:
Microsoft OLE DB Provider for SQL Server: Column name or number of supplied values does not match table definition.

Диагноз:

Как и в прошлом случае, в схеме базы (в «метаданных») поля нет, в реальной таблице — осталось.
Разница с прошлой проблемой: расхождение в полях произошло в табличной части, а не в шапке.

Что делать:

Как и в прошлом случае, решением будет удалить это поле из таблицы SQL.

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

Как и раньше, ищем проблемный запрос профайлером. 

Разное количество полей в ТЧпосчитать реквизиты в запросе 

Самое интересное здесь — имя таблицы, куда идёт вставка. 

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

Для этого сравнения есть разные способы, самый эффективный на мой взгляд: получить скрипты создания этих таблиц (подробно способ описан в решении проблемы №4, ниже)

И сравнить их тексты, вот так:

Сравнение скриптов добавления таблиц для вычисления разницы между полями

Таким образом, видим в новой проблемной базе 2 лишних поля, удаляем их описанным ранее способом, и проблема решается. Если всё правильно расследовали и сделали, конечно 🙂

 

Вариация на тему

Был еще случай, когда ошибка та же, но в профайлере мне не удалось ничего по ней найти полезного.
Тогда по журналу регистрации увидел на каком документе остановилась транзакция загрузки данных (на этапе восстановления обмена РИБ), попробовал поменять данные в его табличных частях. Точней, увидел что есть пустая ТЧ, внес в нее новую строку, увидел что ошибка воспроизводится, и далее как на прошлом шаге — сравнил скрипты создания этой таблицы, увидел разницу в одном поле, удалил его из битой базы, стало хорошо.

Проблема №4. Нехватка целиком какой-то таблицы

Симптомы: 

В разных транзакциях вот такое:

Ошибка СУБД:
Microsoft OLE DB Provider for SQL Server: Invalid object name

Диагноз:

В схеме базы (в «метаданных») таблица есть, а в базе — такая отсутствует.
В новом релизе таблицу добавили, но так как реструктуризации не было, в базе её нет.

Что делать:

Добавить.

Самое простое — добавить из живой базы

  1. Находим там эту таблицу
  2. Правый клик на ней
  3. Script Table As
  4. CREATE TO
  5. New Query…
  6. Меняем там имя целевой базы
  7. Выполняем

Нехватка таблицы

Радуемся, если проблема решались (опционально)
🙂

Ещё кое-что

Был еще ряд проблем, которые не удалось классифицировать. Кратко о них:

  1. При реструктуризации исключение, жалоба на нехватку таблицы EDBT…
    Как выяснилось, так кодируется таблица внешнего источника данных
    После удаления этого внешнего источника данных из Конфигуратора — проблема решилась
  2. Словил ошибку 

    Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong

    после анализа удалось выяснить, что ошибка связана с агрегатами, после небольших экспериментов в Конфигураторе по удалению агрегатов — задача была решена

Если есть конфигурация поломанной базы (CF)…

, то можно восстановить методом проще. Раскрыть этот CF в пустую базу, и оттуда перетащить в битую базу таблицу Config

Вместо эпилога

Вопросы, конструктивную критику, пожелания, дополнения и предложения, как обычно в комментарии.
Если статья оказалась полезной/интересной — Вы знаете что делать 🙂

И еще.. Интересно ли кому-то легкий мануал по соответствию имён таблиц «SQL-1C» ?
Который позволит однозначно ответить на вопрос «А какой таблице 1С соответствует SQL-ная _SeqB567» и все аналогичные

15 Comments

  1. МихаилМ

    предлагаю автору перейти от эмпирического поиска ошибок к аналитическому.

    разобраться , как 1с8 сопоставляет реквизиты и поля бд.

    Для этого научиться парсить запись dbnames таблицы params , записи таблицы config.

    по их данным строить сопоставления имен метаданных и имен таблиц и полей.

    подсказка: 1с хранит описания метаданных в виде текста в кодировке utf8 (сжатого deflate)

    tsql не умеет работать с utf . а xml умеет. н уи про BOM не забываем.

    Reply
  2. METAL

    (1) МихаилМ, учитывая Ваш совет — что конкретно можно было сделать лучше в рамках данной статьи?

    А так, согласен, как ра3 собирался распарсить эти таблицы, посмотреть что внутри? Приходилось ли Вам МЕНЯТЬ содержимое этих таблиц (deflate-и3менение-inflate-3апись в ба3у)?

    Reply
  3. Светлый ум

    +1. Сложная и нужная тема

    А подобные комментарии: (1)

    «разобраться , как 1с8 сопоставляет реквизиты и поля бд. «, — уменьшаю неопределенность и говорят куда копать.

    Reply
  4. МихаилМ

    (2) приходилось изменять dbnames. читайте мой комментарий к Вашей первой части про восстановление.

    Reply
  5. METAL

    (4) МихаилМ, попробовал… Честно говоря, не понял как Вы меняли DBNames..

    Ведь в указанной разработке http://infostart.ru/public/74406/ Deflate и чтение только делается

    Inflate и запись — непонятно как…

    Но Бог с ним, у меня даже на чтение не получается… (((

    Тестовый скрипт Test.sql возвращает пустую таблицу.

    Скрипт

    SELECT * FROM [mybase].[dbo].[fn_GetBinary] (

    (Select TOP 1 BinaryData From Config)) k

    также возвращает пустую таблицу… 🙁

    Возможно неправильно подключил?

    Скрипты подключения во вложении (один вспомогательный просто разрешает выполнение CLR)

    Можете подсказать, где я ошибся, и как всё-таки прочитать двоичные данные из SQL?

    Reply
  6. МихаилМ

    (5) сейчас нет доступа к наработкам. поэтому ничем помочь не могу тк не помню . на инфостарте есть несколько аналогичных clr + исходники на си шапр.

    попробуйте другую.

    Например

    Reply
  7. METAL

    (6) МихаилМ, спасибо! поискать по маске CLR я что-то не догадался.. Буду пробовать!

    Reply
  8. Gureev

    Как выяснилось, почти все эти проблемы решаются путем добавления реквизита, в конфигураторе, к объекту метаданных на который ругается система.

    Таблица красиво пересоздается.

    Reply
  9. METAL

    (8) «Все эти проблемы» совершенно точно не может решить добавление реквизита. Так как в некоторых случаях реквизит УЖЕ лишний (в таблице SQL есть, а описании метаданных — нет). Его надо удалять. И через конфигуратор этого не сделать, так как конфигуратор об этом ничего не «знает». В этом и проблема.

    Возможно, у вас был сбой какого-то другого рода.

    Более детально Ваш случай развернуть можете?

    Reply
  10. olegmedvedev
    Интересно ли кому-то легкий мануал по соответствию имён таблиц «SQL-1C» ?

    Который позволит однозначно ответить на вопрос «А какой таблице 1С соответствует SQL-ная _SeqB567» и все аналогичные

    а можно мануал?

    Reply
  11. olegmedvedev

    (11)ого) спасибо

    Reply
  12. Gureev

    (9) Фишка в другом, когда добавляется реквизит, 1с реструктуризирует объект, и делает это правильно.

    Там не важно были лишние, или чего то нехватало, 1С воссоздаст все как нужно.

    Reply
  13. METAL

    (13) Не знаю, какой кейс у вас был, но повторюсь, база мне на восстановление досталась в следующем состоянии

    Конфигуратор доступен, открывается, но при попытке внести любые изменения (точней, обновить конфигурацию ИБ) — валится с записью дампа

    То есть, очевидно, проблема другого характера.

    Reply
  14. METAL

    UPD При борьбе с ошибкой

    «Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong»

    поможет следующая стратегия

    1. Включить профайлер на мониторинг

    2. Спровоцировать ошибку

    3. Остановить сбор логов в профайлере

    4. Запустить поиск по маске object’



    5. Обнаружится запрос вида

    declare @p1 int

    set @p1=1424

    declare @p4 int

    set @p4=1

    exec sp_prepexec @p1 output,N’@P1 int OUTPUT’,N’EXEC @P1 = sp_rename N»[dbo].[_AccumRgAggOpt10310]», N»_AccumRgAggOpt10310OG», N»object»

    ‘,@p4 output

    select @p1, @p4


    В котором _AccumRgAggOpt10310 — недостающая таблица, изза которой возникает ошибка.

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

    Решением будет добавить эту таблицу вручную в SQL.

    В моём случае это был скрипт на создание из аналогичной таблицы (через SCRIPT CRE ATE TABLE)

    Точнее больше 50 таблиц

    В итоге скрипт получил обработкой

    Если интересует подробности — пишите сюда или в личку, поделюсь опытом!

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *