В данной статье будет рассмотрена методика удаления данных запросом в MSSQL-студии.
Отказ от ответственности
Делайте архив.
Проверяйте, пожалуйста, текст скрипта перед выполнением. Понимайте, что делаете. Помните, что ответственность лежит целиком на Вас!
С особой внимательностью рекомендую проверять скрипт перед выполнением, если в Вашей базе есть случаи, когда период записей регистров отличается от даты регистратора.
Основная цель применения
Прикладная задача, в процессе решения которой родилась данная методика: свертка базы (ввод остатков, удаление документов и движений регистров в прошлых периодах). То есть: удаление документов (вместе с табличными частями, разумеется) до определённой даты, и их движений. Иногда обработка использовалась для удаления данных с более сложными условиями, но они менялись вручную уже в SQL-студии.
Предыстория
Проблема: свертка стандартными средствами происходила неприлично долго. Точней, именно этап удаления старых данных. Остатки вводятся быстро, а вот удаление движений регистров, пометка на удаление документов, само удаление - по нашим оценкам на наших объёмах (500ГБ) заняло бы недели.
Решение: удалить данные средствами SQL, чтоб миновать механизмы платформы 1С, ненужные при данной операции, но отнимающие драгоценное (в рамках данной задачи) время.
Препятствия: Данные в SQL хранятся в разных таблицах. Таблиц много, как их связать - не всегда понятно. То есть мало очистить сам документ (шапку), надо очистить также данные табличных частей, и движений документа. Движения по разным регистрам. Для одного документа регистров может быть много. Каждый регистр в свою очередь хранит данные также в нескольких таблицах. Наименования таблиц - неосмысленные.
Теория
Варианты (операторы) удаления в SQL.
- DROP - полное удаление таблицы из структуры данных (вместе с данными). То есть очищаются не только данные, но и метаданные. Работает мгновенно.
- TRUNCATE - полная очистка таблицы с сохранением структуры таблицы (очищаются только строки таблицы, колонки остаются прежними). Работает мгновенно.
- DELETE - удаление записей в таблице по определенному условию. Занимает определенное время.
Оператором DROP на практике я почти не пользуюсь. TRUNCATE - иногда пригождается, когда по условию задачи возможно удалить всю таблицу (данные не нужны совсем, либо можно после удаления загрузить откуда-то только нужную часть). В остальных случаях (в том числе в рамках данной методики) используется DELETE.
Для того, чтоб удалить данные целостно по ряду связанных таблиц документа (шапка, ТЧ, движения) - сперва я рассматривал вариант честно отобрать данные документа по дате, а потом уже связать с другими таблицами через JOIN. То есть очистить поочередно все связанные таблицы, после чего удалить основную (так как только в ней есть реквизит, по которому решаем удалять объект или нет)
В итоге была выбрана и реализована следующая стратегия
- Удаляем движения регистров, которые двигает нужный вид документа, по связке с основной таблицей документа
- Удаляем строки табличных частей документа, по связке с основной таблицей документа
- Удаляем основную таблицу документа
- Очищаем целиком таблицы журналов, где участвует документ (нехорошо, но в нашем случае - не критично, можно и не трогать)
- Опционально можно очистить таблицы регистрации изменений для обмена
Таблиц много + названия неудобные + конструктора запросов нет = очень много рутины с высокой вероятностью ошибки и дороговизной ошибок. Поэтому был создан инструмент, берущий большую часть рутины на себя.
Устаревшая стратегия (альтернатива)
Первое решение, от которого я впоследствии отказался. Хотя вначале оно казалось более удобным и простым. А именно - очистить шапку. А потом все связанные таблицы поочередно, у кого нет "пары" в основной таблице (ссылка/регистратор = "битая" ссылка).
Данный вариант не работает для движений документа. Так как после удаления основной таблицы документа - IS NULL даёт истину после соединения таблицы движений регистра и основной таблицы документа в 2х случаях
- Когда действительно записи сделаны этим видом документа, и эти документы были удалены (тут всё хорошо)
- Когда записи были сделаны документами других видов, и в этом случае записи удаляются ошибочно (так нельзя!). Чтоб решить эту проблему надо связывать таблицу регистра со всеми возможными типами регистраторов, а это слишком сложно
Вобщем порядок был такой (отличия в пунктах 2 и 3)
- Удаляем записи регистров, которые двигает нужный вид документа, по связке с основной таблицей документа
- Удаляем основную таблицу документа
- Удаляем записи табличных частей документа, у которых Ссылка после соединения = IS NULL
- Остальное (как в основном варианте, журналы и регистрация изменений)
Но в процессе эксплуатации выяснилось, что удаление по пустой шапке на больших объёмах работает медленно, поэтому по умолчанию от данной стратегии пришлось отказаться (по крайней мере, на нашем примере), но эта опция по-прежнему доступна по соответствующей галочке на первой закладке.
Особенности
- Доступна опция порционного удаления.
- На данный момент, обработка существует только для обычного приложения.
- Обработка сама не подключается в SQL и не запускает скрипт там на выполнение. Только формирует текст скрипта. Считаю, что скопировать-вставить нетрудно, а если нет навыков работы в SQL-студии, то и запускать подобное, возможно, рано.
- Исходный код открыт.
Порядок действий
- Делаем архив
- Составляем список удаляемых данных (самые большие таблицы, которые удалить стандартными средствами слишком долго / неудобно / не хочется разбираться с тем, что удаляемые данные зарегистрируются к обмену и "пойдут" куда не надо)
- Запускаем обработку, при желании сверху ставим отбор
- Выделяем в списке нужные виды документов (обязательно выделяем ОСНОВНЫЕ таблицы, то есть таблицы шапок, а не табличных частей)
Можно сразу несколько с Ctrl-ом (доступно множественное выделение) - Переходим на вторую закладку и выбираем нужный нам вариант удаления (например по дате)
- Нажимаем соответствующую кнопку по формированию скрипта
- Получаем в окне сообщений готовый скрипт на удаление данных на языке SQL
- Копируем в буфер, вставляем в SQL Management Studio
- При надобности корректируем. Например через замену (Ctrl+H) можно заменить "<" на ">=", и получится скрипт удаляющий данные документов не до указанной даты, а, наоборот, - начиная с неё. Либо отбор по дате можно заменить на пометку документа на удаления (_Marked = 1). Либо чтоб удалялись только непроведенные (_Posted = 0).
- Запускаем на выполнение, дожидаемся завершения, наблюдаем за статусом на закладке Messages
- Проверяем результат в 1С
- Обязательно пересчитываем итоги затронутых регистров накопления и бухгалтерии, так как таблицы итогов не обрабатываются
При желании протестировать/посмотреть "что именно будет удаляться" предусмотрена соответствующая опция (галочка справа внизу), в этом случае скрипты будут формироваться с оператором SELECT, а не DELETE. Можно выделить нужный кусок, запустить на исполнение, посмотреть результаты, прежде чем запускать на удаление.
Для PostgreSQL
...Использовалась копированием текста скрипта из 1С, вставкой и запуском в dbAdmin через Query Tool
Версия для PostgreSQL на данный момент не поддерживает порционное удаление
Вместо эпилога
Конструктивную критику, вопросы и пожелания - прошу в комментарии!
Спасибо за прочтение!