Реально быстрая очистка документов через SQL

Как делать нельзя, но если очень нужно, то можно!

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

У меня камнем преткновения были документы Заказ покупателя, которые имели 4 табличных части и вели свою историю аж с 2005 года. Накопилось там документов порядка полутора миллионов, казалось бы, не так уж много, но удаление их занимало адское количество времени и не давало провести свертку до утра, в связи с чем родился такой маленький  sql.

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

/****** Набор запросов для очистки документов заказы покупателей по дате  ******/

—Как реально быстро почистить документы от даты…. А то обработки на Инфостарте тормозят дружно, даже где написано SQL

—Не забудьте свернуть регистры по документам. Например обработкой свертка и ввод начальных остатков.
—Имена таблиц в SQL можно получить любой обработкой их полно, например SQL БАЗОМЕР (заодно посмотрите, с чего начать)
—После удаления больших таблиц документов и закрытия регистров, даже штатная свертка отрабатывает на ура и быстро.
—Только на тестовой базе сначала, и BACKUP BACKUP BACKUP!!!!!

— _IDRRef Документа наименьший можно получить запросом 

SELECT TOP 1 FROM [sql_new1].[dbo].[_Document134]
WHERE _Date_Time < ‘2024-01-01 00:00:00.000’
ORDER BY _IDRRef

— По дате первый IDRRef брать НЕЛЬЗЯ! Надо именно по значению. Иначе можете удалить нужные табличные части заказов.
— Чистим табличные части:

DELETE
FROM [sql_new1].[dbo].[_Document134_VT2446]
WHERE _Document134_IDRRef < 0x8267002590D8EFB911E5891E7F179918

DELETE
FROM [sql_new1].[dbo].[_Document134_VT2468]
WHERE _Document134_IDRRef < 0x8267002590D8EFB911E5891E7F179918

DELETE
FROM [sql_new1].[dbo].[_Document134_VT2476]
WHERE _Document134_IDRRef < 0x8267002590D8EFB911E5891E7F179918

DELETE
FROM [sql_new1].[dbo].[_Document134_VT2489]
WHERE _Document134_IDRRef < 0x8267002590D8EFB911E5891E7F179918

— И сам документ

DELETE
FROM [sql_new1].[dbo].[_Document134]
WHERE _IDRRef < 0x8267002590D8EFB911E5891E7F179918

— если много, удаляем кусками, чтобы юзеры даже не почуяли…
DECLARE @RowsDeleted INTEGER 
DECLARE @RowsTo INTEGER 
SET @RowsDeleted = 1 
SET @RowsTo= 1 

WHILE (@RowsDeleted > 0 and @RowsTo < 16000000) 
BEGIN 
DELETE TOP (50000) FROM _Document134 WHERE _Date_Time < ‘2024-01-01 00:00:00.000’ 
SET @RowsDeleted = @@ROWCOUNT 
SET @Rowsto = (@Rowsto+@RowsDeleted) 
— WAITFOR DELAY ’00:00:001′ —чтоб можно было работать без блокировки таблицы, можно удалить
END 

24 Comments

  1. Константин С.

    Реально быстрая очистка

    format c:
    Reply
  2. Gilev.Vyacheslav

    изобретение велосипеда, серия 100500-я

    зачем изучать что было сделано до тебя, когда можно самому изобрести велосипед… )))

    нужное во временную таблицу, остальное транкейтим, потом из временной таблицы назад нужное…

    Reply
  3. vano-ekt

    битые ссылки в борьбе за 5 гигов места … шел 2018 год

    Reply
  4. Marik

    Delete — плохо

    Truncate — рулит

    Reply
  5. GreenDragon

    (3) Ну, так-то в нашей базе на 500+ гиг таким варварским методом можно базу процентов на 10-20 уменьшить… Но метод ужасен, да

    Reply
  6. ksnik

    Еще до кучи — SELECT — остатки товаров

    —DECLARE @XXX binary(16)

    —SET @XXX = (SELECT _IDRref

    —FROM _Reference55

    —where _Code = ‘ЦБ005’)

    —SELECT @XXX

    —SELECT _AccumRg6465._Period AS Период, _AccumRg6465._Fld6469 AS Количество, _Reference55._Description AS Организация,

    — _Reference52._Description AS Номенклатура, _Reference70._Description AS СкладКомпании

    —FROM _AccumRg6465

    —LEFT OUTER JOIN

    — _Reference70 ON _AccumRg6465._Fld6467RRef = _Reference70._IDRRef LEFT OUTER JOIN

    — _Reference52 ON _AccumRg6465._Fld6466RRef = _Reference52._IDRRef LEFT OUTER JOIN

    — _Reference55 ON _AccumRg6465._Fld7882RRef = _Reference55._IDRRef

    —WHERE (_AccumRg6465._Period BETWEEN CONVERT(DATETIME, ‘2010-12-31 00:00:00’, 102) AND CONVERT(DATETIME, ‘2010-12-31 23:59:59’, 102))

    SELECT COUNT(_AccumRg6465._Fld7882RRef)

    FROM _AccumRg6465

    Reply
  7. ksnik

    — UPDATE_ВзаиморасчетыКомпании

    DECLARE @XXX binary(16)

    SET @XXX = (SELECT _IDRref

    FROM _Reference55

    where _Code = ‘ЦБ005’)

    —SELECT @XXX

    update

    Reply
  8. ksnik

    — UPDATE_ДенежныеСредстваКомпании

    — DECLARE @XXX binary(16)

    SET @XXX = (SELECT _IDRref

    FROM _Reference55

    where _Code = ‘ЦБ005’)

    —SELECT @XXX

    update

    Reply
  9. Roman_SE

    (2)

    Delete в цикле позволяет делать фоном.

    Reply
  10. Roman_SE

    (3)

    Не за 5 гигов места, а за производительность в бекапах, да и отрезать надо было начало учета, где вообще все сверхкриво велось.

    Reply
  11. Roman_SE

    (5)

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

    Reply
  12. Roman_SE

    (4)

    Да кто спорит, но тут можно на работающей базе споконой чистить хвосты постепенно. Truncate замечательно конечно, но это надо и таблицы создавать и тд…А если таблица весит 50 гигов, а стереть надо в ней только первые 2-3 года…

    Reply
  13. Roman_SE

    (8)

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

    Reply
  14. nvv1970

    (14) да, если это не остатки, то можно и прямо во время работы.

    А если остатки?

    В теории тоже можно скулем самому очистить движения до даты, и остатки до даты, а первые остатки записать в движения на какой-либо регистратор (даже битый — пофиг). Если вдруг кто-то пересчитает итоги — все будет норм.

    А если это хозрасчетный? А если нужно в остатках поправить пустые ссылки в валюте, неверные типы в субконто и прочие косяки древних кривых данных? Все становится не так просто. Без монопольного доступа к регистру — никак.

    Ну и представьте, что из 500 млн строк нужно удалить 400 )))))) делете будет выполняться день как минимум. А если это full recovery ??? (Даже и представить не могу, что может быть у кого simple)

    Reply
  15. МихаилМ

    меня пугает

    _IDRRef < 0x8267002590D8EFB911E5891E7F179918

    тк обычно _IDRRef — случайное значение для разных сессий, а в пределах сессии — инкрементальное.

    Reply
  16. Roman_SE

    (17) Серьезно? оно сквозное на всю таблицу, как оно случайным может быть?

    Reply
  17. МихаилМ

    (18) тогда подумайте логически , сколько в базе должно быть документов , чтобы достичь значения 0x8267002590D8EFB911E5891E7F179918

    для инкрементального счетчика 4 байт хватилобы вместо 16

    Reply
  18. Roman_SE

    (19) Ну в 1с много что сделано с запасом. А все же откуда уверенность в случайности? или случайное все же берется больше чем последнее?

    Reply
  19. fishca

    1. Удалять нужно периодами

    2. Про журналы документов нужно еще не забыть, т.к. это отдельная таблица.

    3. Табличные части / движения документов, потом сами ссылки

    Reply
  20. МихаилМ

    (20)

    https://yandex.ru/search/?lr=213&offline_search=1&text=1%D1%81%20%D0%BA%D0%B0%D0%BA%20­%D1%84%D0%BE%D1%80%D0%BC%D0%B8%D1%80%D1%83%D0%B5%D1%82%D1%81­%D1%8F%20guid%20

    Reply
  21. Roman_SE

    (22) Убедили, но проверка на практике говорит, что все же он может и местами случайный, но инкрементальный. То что там много байт длина это не значит что значимые не последние 5-6 всего, а начало уникально для базы или справочника

    Reply
  22. Roman_SE

    (23) инкрементальный в том смысле, что возрастающий ,а не что a++

    Reply
  23. Roman_SE

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

    Reply
  24. avusachev

    (17) Тоже режу базу таким же макаром. У нас PostgreSQL. Ну и, чтобы, совсем не бояться _IDRRef решил вот так делать:

    DELETE FROM _document397_vt9019 WHERE _document397_vt9019._document397_idrref IN (SELECT _idrref FROM _document397 WHERE _date_time < ‘2016-01-01 00:00:00’);

    DELETE FROM _document397 WHERE _date_time < ‘2016-01-01 00:00:00’;

    Reply

Leave a Comment

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