Имеется регистр сведений цен номенклатуры с общей заполненностью в 71 миллион записей. Существует ли способ очистки этого регистра от определенных записей с отбором например по группе номенклатуры? Какими методами это возможно реализовать?
Все возможные манипуляции приводили к отвалу обработок очистки и к сообщениям "Недостаточно памяти для получения запроса к базе данных".
База крутится на MS SQL 2014 Сервер 1С 8.3 х64.
---
!!!ЗАДАЧУ РЕШИЛ, ТЕМА ЗАКРЫТА!!!
---
для УПП допиливал обработку поиск и замены чтобы удаляло из табличной части и подчищяло движение = мягкое перепроведение.
Что у вас подвисает и на каком этапе не понятно.
Как уже говорилось оптимизируйте запрос, запускайте в фоне несколько потоков.
Распараллеливания потоки можно периодами по месяцам, если много уменьшайте до приемлемого результата.
---
А если запрос порционно формировать? указывать, например, первые 1000?
И список номенклатуры по группе вы же отдельно получаете до отбора по РС?
Я к тому что у Вас должна быть ТаблицаНоменклатуры и к ней внутренним соединением накинуть регистр, а не фильтровать напрямую по таблице РС
---
Имеется ввиду не по р/с искать номенклатуру, а по номенклатуре р/с? При порционном формировании время очистки такого количества записей может затянуться до пенсионного возраста))
---
НаборЗаписпей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписпей.Отбор.Период.Установить('20170101');
НаборЗаписпей.Записать();

И так в цикле удалять, меняя период.

По порциям.
---
Отбор по периоду исключен.
---
регистр подчинен регистратору, надо так, в запросе можно указывать период.

```1c
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ
    | ЦеныНоменклатуры.Регистратор
    |ИЗ
    | РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры";

    Результат = Запрос.Выполнить();

    Выборка = Результат.Выбрать();

    НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();

    Пока Выборка.Следующий() Цикл

    НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);

    НаборЗаписей.Записать();

    КонецЦикла;
```
---
Как здесь обратиться к группе номенклатуры и именно ценам этой номенклатуры?
---
предлагаю воспользоваться прямым доступом к данным (ms sql)
А через МенеджерЗаписи кстати пробовали?
---
На SQL писал запрос на выбор данных по идентификатору таблицы (Номенклатура), выбор роняет SQL за пару часов. Возможно запрос корявый. Но на такой же базе с меньшим количеством записей в регистре отрабатывает идеально.
---
можно пример такого запроса?
---
Пример:

```1c
    exec sp_executesql N'SEL ECT
    T1.Q_001_F_000RRef,
    T1.Q_001_F_004RRef,
    T1.Q_001_F_005RRef,
    T1.Q_001_F_001RRef,
    T1.Q_001_F_002RRef,
    T1.Q_001_F_003_TYPE,
    T1.Q_001_F_003_RRRef,
    T13.Period_,
    T13.Fld7294_TYPE,
    T13.Fld7294_RTRef,
    T13.Fld7294_RRRef,
    T13.Fld7293_,
    T13.Fld7292_,
    T12._Fld816RRef,
    T12._Fld820,
    T1.Q_001_F_007_,
    T1.Q_001_F_006_,
    T17._Description,
    T18._Description
    FR OM (SEL ECT
    T4.Q_001_F_000RRef AS Q_001_F_000RRef,
    T4.Q_001_F_001RRef AS Q_001_F_001RRef,
    T2.Q_001_F_000RRef AS Q_001_F_002RRef,
    T2.Q_001_F_001_TYPE AS Q_001_F_003_TYPE,
    T2.Q_001_F_001_RRRef AS Q_001_F_003_RRRef,
    T4.Q_001_F_002RRef AS Q_001_F_004RRef,
    T4.Q_001_F_003RRef AS Q_001_F_005RRef,
    T4.Q_001_F_004_ AS Q_001_F_006_,
    T4.Q_001_F_005_ AS Q_001_F_007_
    FR OM (SEL ECT DISTINCT
    T3._IDRRef AS Q_001_F_000RRef,
    CASE WHEN T3._Fld821 = 0x01 THEN CASE WHEN T3._Fld822RRef IS NOT NULL THEN 0x08 END ELSE 0x01 END AS Q_001_F_001_TYPE,
    CASE WHEN T3._Fld821 = 0x01 THEN T3._Fld822RRef ELSE @P1 END AS Q_001_F_001_RRRef
    FR OM dbo._Reference48 T3
    WHERE ((T3._Fld395 = @P2))) T2
    INNER JOIN (SEL ECT DISTINCT
    T5.Fld7290RRef AS Q_001_F_000RRef,
    T5.Fld7291RRef AS Q_001_F_001RRef,
    T9._Fld1513RRef AS Q_001_F_002RRef,
    CASE WHEN (T10._ParentIDRRef = @P3) THEN T9._Fld1513RRef ELSE T10._ParentIDRRef END AS Q_001_F_003RRef,
    T10._Fld2563 AS Q_001_F_004_,
    CASE WHEN (T10._ParentIDRRef = @P4) THEN T10._Fld2563 ELSE T11._Fld2563 END AS Q_001_F_005_
    FR OM (SELECT
    T8._Fld7291RRef AS Fld7291RRef,
    T8._Fld7290RRef AS Fld7290RRef
    FR OM (SELECT
    T7._Fld7289RRef AS Fld7289RRef,
    T7._Fld7290RRef AS Fld7290RRef,
    T7._Fld7291RRef AS Fld7291RRef,
    MAX(T7._Period) AS MAXPERIOD_
    FR OM dbo._InfoRg7288 T7
    WHERE (T7._Fld395 = @P5)
    GROUP BY T7._Fld7289RRef,
    T7._Fld7290RRef,
    T7._Fld7291RRef) T6
    INNER JOIN dbo._InfoRg7288 T8
    ON T6.Fld7289RRef = T8._Fld7289RRef AND T6.Fld7290RRef = T8._Fld7290RRef AND T6.Fld7291RRef = T8._Fld7291RRef AND T6.MAXPERIOD_ = T8._Period
    WH ERE (T8._Fld395 = @P6)) T5
    LEFT OUTER JOIN dbo._Reference85 T9
    ON (T5.Fld7290RRef = T9._IDRRef) AND (T9._Fld395 = @P7)
    LEFT OUTER JOIN dbo._Reference145 T10
    ON (T9._Fld1513RRef = T10._IDRRef) AND (T10._Fld395 = @P8)
    LEFT OUTER JOIN dbo._Reference145 T11
    ON (T10._ParentIDRRef = T11._IDRRef) AND (T11._Fld395 = @P9)) T4
    ON 1=1) T1
    LEFT OUTER JOIN dbo._Reference48 T12
    ON (T1.Q_001_F_002RRef = T12._IDRRef) AND (T12._Fld395 = @P10)
    LEFT OUTER JOIN (SELECT
    T16._Fld7289RRef AS Fld7289RRef,
    T16._Fld7291RRef AS Fld7291RRef,
    T16._Fld7292 AS Fld7292_,
    T16._Fld7293 AS Fld7293_,
    T16._Fld7290RRef AS Fld7290RRef,
    T16._Period AS Period_,
    T16._Fld7294_TYPE AS Fld7294_TYPE,
    T16._Fld7294_RTRef AS Fld7294_RTRef,
    T16._Fld7294_RRRef AS Fld7294_RRRef
    FR OM (SELECT
    T15._Fld7289RRef AS Fld7289RRef,
    T15._Fld7290RRef AS Fld7290RRef,
    T15._Fld7291RRef AS Fld7291RRef,
    MAX(T15._Period) AS MAXPERIOD_
    FR OM dbo._InfoRg7288 T15
    WH ERE ((T15._Fld395 = @P11)) AND (T15._Period <= @P12)
    GROUP BY T15._Fld7289RRef,
    T15._Fld7290RRef,
    T15._Fld7291RRef) T14
    INNER JOIN dbo._InfoRg7288 T16
    ON T14.Fld7289RRef = T16._Fld7289RRef AND T14.Fld7290RRef = T16._Fld7290RRef AND T14.Fld7291RRef = T16._Fld7291RRef AND T14.MAXPERIOD_ = T16._Period
    WH ERE (T16._Fld395 = @P13)) T13
    ON (((T1.Q_001_F_000RRef = T13.Fld7290RRef) AND (T1.Q_001_F_001RRef = T13.Fld7291RRef)) AND CASE WHEN (T12._Fld821 = 0x00) THEN CASE WHEN (T1.Q_001_F_002RRef = T13.Fld7289RRef) THEN 0x01 WHEN NOT (T1.Q_001_F_002RRef = T13.Fld7289RRef) THEN 0x00 END ELSE CASE WHEN
    (T12._Fld822RRef = T13.Fld7289RRef) THEN 0x01 WHEN NOT (T12._Fld822RRef = T13.Fld7289RRef) THEN 0x00 END END = 0x01)
    LEFT OUTER JOIN dbo._Reference85 T17
    ON (T1.Q_001_F_000RRef = T17._IDRRef) AND (T17._Fld395 = @P14)
    LEFT OUTER JOIN dbo._Reference144 T18
    ON (T1.Q_001_F_001RRef = T18._IDRRef) AND (T18._Fld395 = @P15)
    WH ERE (T17._Marked = 0x00) AND T13.Fld7293_ = 0x01
    ORDER BY (T1.Q_001_F_007_), (T1.Q_001_F_006_), (T17._Description), (T18._Description), (T1.Q_001_F_002RRef)',N'@P1 varbinary(16),@P2 numeric(10),@P3 varbinary(16),@P4 varbinary(16),@P5 numeric(10),@P6 numeric(10),@P7 numeric(10),@P8 numeric(10),@P9 numeric(10),@P10 numeric(10),@P11 numeric(10),@P12 datetime2(3),@P13 numeric(10),@P14 numeric(10),@P15 numeric(10)',0x00000000000000000000000000000000,0,0x00000000000000000000000000000000,0x00000000000000000000000000000000,0,0,0,0,0,0,0,'4018-04-16 00:00:00',0,0,0
```
---
а вот теперь - ничего не понял.
Если цель - почистить регистр сведений, то зачем такая непонятная выборка?
---
Необходимо еще оставить актуальные цены)
---
может тогда
а) создаем копию таблицы
б) заливаем в нее срез последних, при необходимости чистим (по неактуальной номенклатуре и т.п.)
в) truncate таблиц регистра сведений с ценами
г) заливаем из копии таблицы в оригинал
Единственное - определиться как кошернее создавать копию и переносить срез последних, да и тестирование и исправление на всякий случай потом прогнать. Ну и неактуальные документы установки цен как-нибудь распровести/пометить на удаление.
---
Конфигурация УНФ. Регистр цен независим от документов. Не получается выбрать срез последних... Сам скуль наглухо падает и перезапускается. Таблица объемом на диске в 10 Гб.
---
Если ещё актуально, можно поставить птичку для РС: "Разрешить итоги: срез последних" - далее провести реструктуризацию, если тех. платформа какой-то своей магией это сделает, дальше полная свобода - в составе Иб появится отдельная таблица итогов, можно на ее базе перезаписать основную.
---
Попробую спасибо.
---
еще вариант -
1)пустая база идентичной конфигурации
2) перегнать в нее срез последних конвертацией (точнее регистраторов среза последних)
3) транкейт цен и установок в оригинальной базе
4) перегнать регистраторы обратно
---
фу фу фу. вложенные запросы - зло. только временные таблицы: select into. По опыту скажу - давно через sql MS делаем все - объемы дикие, 1С не справляется, а на стороне sql эти операции отрабатываются за секунды
---
```1c
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ ПЕРВЫЕ 1000
    | ЦеныНоменклатуры.Регистратор
    |ИЗ
    | РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
    | Где Номенклатура в (&ГруппаНоменклатуры)";
```

а что подразумевается под ценой? Конкретное число?
также параметром в запрос передать.
---
Скорее запись регистра. То есть если искать по регистратору(Номенклатура) и в цикле отбирать по 1000 записей можно добиться результата, как тогда не повесить всё и добиться ускоренного выполнения?
---
в цикле выполнять эту операцию, например за один прогон выполнять 100 прогонов по 1000 документов.

```1c
    ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 1000
```
---
многопоточность не рассматривали? Если можно выделить независимые блоки данных, то обрабатывать их параллельно
---
Запустить несколько экземпляров запросов?
---
я бы не пользовался этим способом.
Основная засада - "выбрать первые 1000" в первом запросе, во втором - так же "первые 1000", но при этом надо пропустить первые 1000, выбираемую в первом, в третьем .....
Четкого критерия все-таки нету и нагрузка на базу будет дикая.
---
посмотрите Многопоточная обработка данных. Запускать параллельные фоновые задания.
---
Интересная статья.
---
разве многопточное удаление записей из одной таблицы не приведет к блокировке?
---
Наборы обрабатываемых данных не должны пересекаться. Если, например, использовать НаборЗаписей - то в каждом потоке условие отбора по ключам свое и будет блокироваться только эта группа записей (в каждом потоке своя блокировка). Вы же не будете блокировать всю таблицу.
---
все зависит от того, как автор построит отбор. если брать top 1000, как многие предлагают, то блокировка точно будет
---
смысл select? если нужно удалять записи. Многопоточность приведет к блокировке в случае удаления записей
---
А сколько записей должно остаться в итоге?
---
Те записи, которые не привязаны к определенной номенклатуре. Причем именно актуальные записи.
---
1 - выбрать в отдельную таблицу актуальные цены номенклатуры, очистка которой будет выполняться.
2 - создать набор записей с отбором по номенклатуре. записать. очистятся все записи по этой номенклатуре.
3 - записать по этой номенклатуре актуальную цену, добавив одну запись.

Повторить для каждой номенклатуры.
Так разве не работает?
---
Выбор из 71+ миллиона записей.
Актуальные цены не трогать. Удалить записи по группе номенклатуры+неактуальные записи остальной номенклатуры.
---
Не пробовали. Запросом выбрать нужные данные. т.е. те которые должны остаться в регистре. Запрос, выбрать срез последних которые не в нужной группе. Потом создать менеджер записи и записать всё из запроса.
---
Выбор из 71+ миллиона записей.
Вообще не очень понятно, в чем проблема. Ну много записей, так это же не 71кк элементов номенклатуры.
Это 71кк записей регистра.
Выбираем из справочника номенклатуры те элементы, записи которых будем чистить.

В отдельную процедуру с параметром ТекНоменклатура вынести:

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

Потом чистим записи по этой номенклатуре
НаборЗаписпей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписпей.Отбор.Номенклатура.Установить(ТекНоменклатура);
НаборЗаписпей.Записать();

Добавить в набор запись из выборки запроса актуальной цены и записать еще раз.

Вызывать эту процедуру для каждой номенклатуры.
---
Можно подробнее или в виде примера кода пожалуйста. Суть в том что на определенную номенклатуру вообще даже актульные цены не нужны.
---
УНФ у меня под рукой нет, поэтому примерный код такой

```1c
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ
    | Спр.Ссылка
    |ИЗ
    | Справочник.Номенклатура КАК Спр
    | Где Ссылка в (&ГруппаНоменклатуры)";

    ...
    Выборка = Запрос.Выполнить().Выбрать();

    НужнаАктуальнаяЦена = Истина;
    Пока Выборка.Следующий() Цикл

    ОчиститьЗаписиРегистра(ТекНоменклатура,НужнаАктуальнаяЦена );

    КонецЦикла;

    Процедура ОчиститьЗаписиРегистра(ТекНоменклатура,НужнаАктуальная)

    Если НужнаАктуальная Тогда
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ ПЕРВЫЕ 1
    | *
    |ИЗ
    | РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
    | Где Номенклатура = &ТекНоменклатура
    |Упорядочить По Период Убыв";

    ...
    Выборка = Запрос.Выполнить().Выбрать();

    КонецЕсли;

    НаборЗаписпей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
    НаборЗаписпей.Отбор.Номенклатура.Установить(ТекНоменклатура);
    НаборЗаписпей.Записать();

    Если НужнаАктуальная И Выборка.Следующий() Тогда

    НовЗапись = НаборЗаписей.Добавить();
    ЗаполнитьЗначенияСвойств(НовЗапись,Выборка);
    НаборЗаписей.Записать();

    КонецЕсли;

    КонецПроцедуры
```
---
Подобный запрос роняет скуль.
---
Какой именно? Из справочника номенклатуры?
Ну так а что мешает выбирать партиями? Или указать группу поменьше, для начала.
Или выбрать 1000 элементов, обработать их. В следующий раз - выбрать еще 1000 исключая тех, что уже обработаны.
---
в обработке "Поиск и замена реквизитов для УФ (с обработкой табличных частей)" есть возможность задавать отборы запросом ну или списком по полям фильтрации

Это я к тому, что я использовал эту обработку на регистрах сведений с кол-во записей от 10 млн. до 200+ млн. записей

и она неплохо чистит - главное голова не болит, что не тот отбор и все пропало. Отобрал 10 000 записей - удалить и т.д.

и так неспешно и вдумчимо, в процессе других дел, можно решать подобные задачи без костылей и промахов.
---
Это я к тому, что я использовал эту обработку на регистрах сведений с кол-во записей от 10 млн. до 200+ млн. записей Какая конкретно задача выполнялась?
---
Это скорее "Универсальный подбор и обработка"???
---
В общем этой обработкой я пытался выбрать номенклатуру по группе и в транзакции. 10 минут и рпхост уходит в перезапуск "сжирая" порядка 30+ гб оперативы в тот момент, когда SQL "пыхтит" на 40ГБ
---
Произвольным запросом отбор делать надо(там кнопочка есть расширенный отбор или что-то вроде) и ставить ПЕРВЫЕ 5000 или Первые 10 000

Эта обработка выводит отобранные записи в табличную часть и ясен пень без ПЕРВЫЕ при попытке втиснуть в ТЧ отобранные по группе миллионы будет падение
---
Кажется, нет смысла распинаться))
ТС добавил награду в тему, чтобы решить свою проблему, но ничего не поняв из советов, сам себе ее выплатил))
---
Награду за что то платят не так ли? После долгого и нудного биения в бубен вокруг всей этой проблемы проблема до сих пор решается медленно но уверенно средствами SQL.
---
Вам предложили способы решения средствами 1С.
Но... не в коня корм =)
Ставить же награду за тему, а потом выплачивать ее себе за пустые сообщения - это как минимум не красиво.
Если бы вы решили проблему по своему и потом написали способ решения - и на это сообщение выплатить награду, это одно, а так как сделали сейчас - фу так делать.
---
Сообщение было скрыто модератором.
---
Сообщение было скрыто модератором.
---
А есть понимание для какой номенклатуры сколько записей в регистре? Сколько номенклатуры у вас записей?
---
Для одной позиции номенклатуры минимум 1200+ записей. Позиций номенклатуры 30 000+ именно той, записи на которую не нужны.
---
регистр сведений периодический? почему отбор по периоду исключен?

вытащите запросом просто структуру данных "Номенклатура" "Кол-во записей в РС" даже можно с отбором по 1 номенклатуре, сколько времени займет? только сразу ко-во считайте что бы все другие поля не тянуть.
---
В таком случае придется отбирать с самой последней даты до границы и крайней даты, я думал на счет отбора по дате например дата больше или равно 15.04.2018 кол-во записей будет равно созданным на период с 15.04 по 20.04.
---
Посмотрите за какой период сколько данных, с какого периода у вас база с 2000 года? пусть за год 2000 - 2001 сколько записей ? они все не нудны? Выбрать их набором по отбору даты и очистить не перебирая. Или на самом деле удалить все и проставить цены одним документом ( или обработкой ) на дату. У вас вообще какая конченая цель? удалить старые цены из регистра независимо от того были по ним продажи по этим ценам или нет? или что?
---
регистр подчинен регистратору? Если да, то можно попробовать отбирать документы и отменять проведение. Тупой конечно вариант, но можно в несколько потоков запустить
---
Нет не подчинен...
---
тогда проще через скул пофиксить записи
---
Так и делаю)
---
У меня в скуле понимания поболя нежели в 1С
---
че ж ты вложенных запросов нафигачил тогда? еще удивляешься, что он висит?
---
!!!ЗАДАЧУ РЕШИЛ, ТЕМА ЗАКРЫТА!!!
---
А как решил вопрос то?
---
Проблема была решена средствами SQL. Определил названия отборов в 1С. Перевел на SQL и прошелся по SQL запросом.
---
Сообщение было скрыто модератором.