Имя: Пароль:
1C
1С v8
Медленно работает форма подбора товара в документы продажи в ЕРП. Галка "Только в наличии"
0 blesha
 
09.06.20
09:58
Всем привет.
Вопрос собственно в теме обозначен.

Немного контекста:
платформа - 8.3.15.1830
конфа - 1С:ERP Управление предприятием 2 (2.4.11.104)
Справочник номенклатуры содержит 1 600 000+ элементов

При работе с формой подбора товара в документ продажи или в помощник продажи, при нажатии галки "только в наличии" тупит 10-15 минут, точно не помню. Если есть отбор по складу, то галка уже называется, например, "только в наличии на складе Центральный склад" и выполняется быстрее, но все равно тупит.

На форме добавлены свои галки, которые работают быстро, меньше секунды.
Сразу скажу, тупил функционал и до наших галок, когда все типовое - форма, общие модули и т.д.

Кто сталкивался с подобной проблемой, как лечили?
1 shuhard
 
09.06.20
10:00
(0) тупость менеджеров не лечиться
2 blesha
 
09.06.20
10:09
(1)  при чем здесь менеджеры?? тупило ЕРП на указанном объеме из коробки
3 Bigbro
 
09.06.20
10:12
остатки по полутора миллионам позиций считать "на лету" для подбора? эмм....
я наверное чего то не понимаю.
4 Ненавижу 1С
 
гуру
09.06.20
10:22
сколько живых остатков из этих полутора миллионов позиций?
5 Фрэнки
 
09.06.20
10:24
ну как живых... они не живые, наверняка. Но вероятно, что конфа имеет некую специфику применения, которую топикстартер решил утаить
6 Bigbro
 
09.06.20
10:37
ну а вообще с остатками в подборах и формах списка справлялись обычно 2 путями - либо показывали остаток только по текущей позиции на которой позиционирован, либо делали отдельную кнопку которую тыкали _после_ прочих отборов, чтобы из 3 десятков подшипников отобразить только 4 позиции которые есть на складе.
7 blesha
 
09.06.20
10:48
(3)  типовая ЕРПешная форма подбора изначально имеет колонку "В наличии" и при открытие формы ничего не тупит. При этом в перемешку идут строки с остатками и без. ПРи работе динамические списки используют "первые N", у меня 45, что видно по скульному запросу
8 Фрэнки
 
09.06.20
10:54
(7) Ну так в скульном запросе, раз получается его открыть и проверить - там же видно должно быть каждому, по какому регистру он строит выборку...

Можно провести проверку или тестирование самого запроса в консоли,
можно протестировать состояние регистра, количество записей в нем, наличие в нем каких-то сбоев (такое тоже не исключено на 100%)
влияние на поведение запроса наличие или отсутствие индексов по заданным измерением... возможностей много, на самом деле.
9 Ненавижу 1С
 
гуру
09.06.20
11:00
(7) вот именно, без наложения фильтра
он тупо берет порцию 45 элементов из справочника (возможно сортированных по полю справочника, что не составляет труда)
при наложении он вынужден брать записи, пока не наберет свои 45 элементов, отфильтровывая по остаткам и тут нет никакого индекса.

Например, сортировка справочника по наименованию:
Арбуз - 100
// здесь 100500 элементов не имеющих остатков, но которые попадут в сканирование запроса с последующим отбрасыванием
Брюква - 20
10 blesha
 
09.06.20
11:02
(8)  и планы запросов получены, и видно что проблема совсем не с регистром накопления. я не стал это все писать сразу, т.к. статья какая-то получается, но без решения, да и без прикрепленных планов воспринимать эту писанину будет тяжело.
Надеялся, что я не первый с такой проблемой столкнулся.
11 Bigbro
 
09.06.20
11:05
если все работало хорошо и быстро до доработок и реструктуризация была - можно попробовать статистику обновить. обычно здорово помогает.
12 blesha
 
09.06.20
11:06
(9) судя по плану получение остатков оценка (subtree cost): 0.9, а всего запроса 695.
сейчас могу чуть подробнее расписать.
13 blesha
 
09.06.20
11:07
(11)  это все сразу сделал
14 Ненавижу 1С
 
гуру
09.06.20
11:12
(12) да сами остатки он быстро получит, но потом идет тупое сканирование
в общем ждем картинки с планами запроса
15 Фрэнки
 
09.06.20
11:12
(12) Я правильно понимаю твое пояснение, что там текст запроса - это простыня на пару погонных метров, как минимум...
и затягивается там в результирующую таблицу всякая ... мягко говоря ерунда, не имеющая никакого прямого отношения
к собственно значениям остатков по выбранным позициям?
16 Фрэнки
 
09.06.20
11:15
Как там ... раз пошла такая пьянка - режь последний огурец.

Выкинь вообще все из того запроса, кроме данных одного единственного регистра с остатками и посмотри, что от этого изменится.

И результирующий подбор - это же "плоская" таблица, не дерево?
17 Фрэнки
 
09.06.20
11:18
Кстати, курочить саму форму совсем не обязательно для всего этого тестирования. Это все в консоли запросов надо проверять.
18 blesha
 
09.06.20
11:32
По плану запроса с отбором по наличию видно, что проблема, т.е. обрабатывается огромное количество строк, в следующем:
-цены номенклатуры - ~2 000 000 строк, хотя предполагаемое количество строк 1,5, а факт 2 лям,  стоимость небольшая, но потом идет сброс в темпДБ строк при сортировке.
- выгребается зачем-то весь справочник номенклатуры, 1 600 000 строк,  треть всей стоимости
- затем используется оператор, с которым я мало знаком index spool (lazy spool), в него входит одна строка, а выходит 1 600 000, походу вся номенклатура, это 60% всей стоимости.
top 45 срабатывает гораздо позже

Если без этого отбора, то план почти такой же, везде обрабатывается <= 45 сток, индекс спул не возникает, тишь да гладь, кое где идут индекс сики по другим индексам.

планы запросов:
https://yadi.sk/d/ysNPub3wKHkT0Q

стата актуальна, индексы не фрагментированы, процедурный кэш чистил.
отлаживаю уже в консоли запросов
19 blesha
 
09.06.20
11:33
(15) ну да:

ВЫБРАТЬ ПЕРВЫЕ 45
    СправочникНоменклатура.Ссылка КАК Ссылка,
    СправочникНоменклатура.Артикул КАК Артикул,
    СправочникНоменклатура.Код КАК Код,
    СправочникНоменклатура.Наименование КАК Наименование,
    СправочникНоменклатура.ПометкаУдаления КАК ПометкаУдаления,
    СправочникНоменклатура.Родитель КАК Родитель,
    СправочникНоменклатура.ЭтоГруппа КАК ЭтоГруппа,
    СправочникНоменклатура.Ссылка КАК Номенклатура,
    СправочникНоменклатура.Ссылка КАК ЭлементСписка,
    СправочникНоменклатура.ВидНоменклатуры КАК ВидНоменклатуры,
    СправочникНоменклатура.ТипНоменклатуры КАК ТипНоменклатуры,
    ВЫБОР
        КОГДА СправочникНоменклатура.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Набор)
            ТОГДА ЕСТЬNULL(ЗНАЧЕНИЕ(Перечисление.ВариантыРасчетаЦенНаборов.ПустаяСсылка), ЗНАЧЕНИЕ(Перечисление.ВариантыРасчетаЦенНаборов.ПустаяСсылка))
        ИНАЧЕ ЗНАЧЕНИЕ(Перечисление.ВариантыРасчетаЦенНаборов.ПустаяСсылка)
    КОНЕЦ КАК ВариантРасчетаЦеныНабора,
    ЛОЖЬ КАК СодержитТовары,
    ЛОЖЬ КАК СодержитУслуги,
    СправочникНоменклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
    СправочникНоменклатура.ЦеноваяГруппа КАК ЦеноваяГруппа,
    СправочникНоменклатура.Качество КАК Качество,
    СправочникНоменклатура.ИспользованиеХарактеристик КАК ИспользованиеХарактеристик,
    ВЫБОР
        КОГДА СправочникНоменклатура.ТипНоменклатуры В (ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Товар), ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.МногооборотнаяТара))
            ТОГДА ИСТИНА
        КОГДА СправочникНоменклатура.ТипНоменклатуры В (ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Набор))
                И ЕСТЬNULL(ЛОЖЬ, ЛОЖЬ)
                И НЕ ЕСТЬNULL(ЛОЖЬ, ЛОЖЬ)
            ТОГДА ИСТИНА
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ КАК ЭтоТовар,
    ВЫБОР
        КОГДА СправочникНоменклатура.ТипНоменклатуры В (ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Услуга), ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Работа))
            ТОГДА ИСТИНА
        КОГДА СправочникНоменклатура.ТипНоменклатуры В (ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Набор))
                И ЕСТЬNULL(ЛОЖЬ, ЛОЖЬ)
                И НЕ ЕСТЬNULL(ЛОЖЬ, ЛОЖЬ)
            ТОГДА ИСТИНА
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ КАК ЭтоУслуга,
    ВЫБОР
        КОГДА СправочникНоменклатура.ИспользованиеХарактеристик = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияХарактеристикНоменклатуры.ОбщиеДляВидаНоменклатуры)
            ТОГДА СправочникНоменклатура.ВидНоменклатуры
        КОГДА СправочникНоменклатура.ИспользованиеХарактеристик = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияХарактеристикНоменклатуры.ИндивидуальныеДляНоменклатуры)
            ТОГДА СправочникНоменклатура.Ссылка
        КОГДА СправочникНоменклатура.ИспользованиеХарактеристик = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияХарактеристикНоменклатуры.ОбщиеСДругимВидомНоменклатуры)
            ТОГДА СправочникНоменклатура.ВладелецХарактеристик
        ИНАЧЕ НЕОПРЕДЕЛЕНО
    КОНЕЦ КАК ВладелецХарактеристик,
    ВЫБОР
        КОГДА СправочникНоменклатура.ИспользованиеХарактеристик = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияХарактеристикНоменклатуры.НеИспользовать)
            ТОГДА ЛОЖЬ
        ИНАЧЕ ИСТИНА
    КОНЕЦ КАК ХарактеристикиИспользуются,
    ВЫБОР
        КОГДА СправочникНоменклатура.ЭтоГруппа
            ТОГДА ВЫБОР
                    КОГДА СправочникНоменклатура.ПометкаУдаления
                        ТОГДА 13
                    ИНАЧЕ 12
                КОНЕЦ
        ИНАЧЕ ВЫБОР
                КОГДА СправочникНоменклатура.ЕстьТоварыДругогоКачества
                    ТОГДА 4 + ВЫБОР
                            КОГДА СправочникНоменклатура.ПометкаУдаления
                                ТОГДА 1
                            ИНАЧЕ 0
                        КОНЕЦ + ВЫБОР
                            КОГДА СправочникНоменклатура.ИспользованиеХарактеристик = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияХарактеристикНоменклатуры.НеИспользовать)
                                ТОГДА 0
                            ИНАЧЕ 2
                        КОНЕЦ
                ИНАЧЕ -1 + ВЫБОР
                        КОГДА СправочникНоменклатура.ПометкаУдаления
                            ТОГДА 1
                        ИНАЧЕ 0
                    КОНЕЦ + ВЫБОР
                        КОГДА СправочникНоменклатура.ИспользованиеХарактеристик = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияХарактеристикНоменклатуры.НеИспользовать)
                            ТОГДА 1
                        ИНАЧЕ 3
                    КОНЕЦ
            КОНЕЦ
    КОНЕЦ КАК ИндексКартинки,
    &ВидыЦен КАК ВидЦены,
    ЕСТЬNULL(ЦеныНоменклатуры.Упаковка, ЗНАЧЕНИЕ(Справочник.УпаковкиЕдиницыИзмерения.ПустаяСсылка)) КАК Упаковка,
    ВЫРАЗИТЬ(ЕСТЬNULL(ЦеныНоменклатуры.Цена, 0) * ВЫБОР
            КОГДА &Валюта <> ЦеныНоменклатуры.Валюта
                ТОГДА ВЫБОР
                        КОГДА ЕСТЬNULL(КурсыСрезПоследнихВалютаЦены.Кратность, 0) > 0
                                И ЕСТЬNULL(КурсыСрезПоследнихВалютаЦены.Курс, 0) > 0
                                И ЕСТЬNULL(КурсыСрезПоследнихВалютаДокумента.Кратность, 0) > 0
                                И ЕСТЬNULL(КурсыСрезПоследнихВалютаДокумента.Курс, 0) > 0
                            ТОГДА КурсыСрезПоследнихВалютаЦены.Курс * КурсыСрезПоследнихВалютаДокумента.Кратность / (КурсыСрезПоследнихВалютаДокумента.Курс * КурсыСрезПоследнихВалютаЦены.Кратность)
                        ИНАЧЕ 0
                    КОНЕЦ
            ИНАЧЕ 1
        КОНЕЦ КАК ЧИСЛО(31, 2)) КАК Цена,
    ВЫРАЗИТЬ(ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) / ЕСТЬNULL(ВЫБОР
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Вес)
                        И ЦеныНоменклатуры.Номенклатура.ВесИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ВесЧислитель / ЦеныНоменклатуры.Номенклатура.ВесЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Объем)
                        И ЦеныНоменклатуры.Номенклатура.ОбъемИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ОбъемЧислитель / ЦеныНоменклатуры.Номенклатура.ОбъемЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Площадь)
                        И ЦеныНоменклатуры.Номенклатура.ПлощадьИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ПлощадьЧислитель / ЦеныНоменклатуры.Номенклатура.ПлощадьЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Длина)
                        И ЦеныНоменклатуры.Номенклатура.ДлинаИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ДлинаЧислитель / ЦеныНоменклатуры.Номенклатура.ДлинаЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА (ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Мощность)
                        ИЛИ ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Энергия)
                        ИЛИ ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.ЭлектрическийЗаряд)
                        ИЛИ ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Время))
                        И ЦеныНоменклатуры.Номенклатура.ЕдиницаИзмерения.ТипИзмеряемойВеличины = ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Упаковка)
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.КоличествоШтук)
                    ТОГДА 1
                ИНАЧЕ NULL
            КОНЕЦ, 1) КАК ЧИСЛО(15, 3)) КАК ВНаличииОстаток,
    ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) КАК ВНаличииВБазовыхЕдиницах,
    ВЫРАЗИТЬ((ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) - ЕСТЬNULL(СвободныеОстатки.ВРезервеПодЗаказОстаток, 0) - ЕСТЬNULL(СвободныеОстатки.ВРезервеСоСкладаОстаток, 0) + ЕСТЬNULL(ОстаткиИзЗаказов.Количество, 0)) / ЕСТЬNULL(ВЫБОР
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Вес)
                        И ЦеныНоменклатуры.Номенклатура.ВесИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ВесЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ВесЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ВесЧислитель / ЦеныНоменклатуры.Номенклатура.ВесЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Объем)
                        И ЦеныНоменклатуры.Номенклатура.ОбъемИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ОбъемЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ОбъемЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ОбъемЧислитель / ЦеныНоменклатуры.Номенклатура.ОбъемЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Площадь)
                        И ЦеныНоменклатуры.Номенклатура.ПлощадьИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ПлощадьЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ПлощадьЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ПлощадьЧислитель / ЦеныНоменклатуры.Номенклатура.ПлощадьЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Длина)
                        И ЦеныНоменклатуры.Номенклатура.ДлинаИспользовать
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Числитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Знаменатель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЧислитель, 0) <> 0
                        И ЕСТЬNULL(ЦеныНоменклатуры.Номенклатура.ДлинаЗнаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ДлинаЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ДлинаЧислитель / ЦеныНоменклатуры.Номенклатура.ДлинаЗнаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА (ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Мощность)
                        ИЛИ ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Энергия)
                        ИЛИ ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.ЭлектрическийЗаряд)
                        ИЛИ ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Время))
                        И ЦеныНоменклатуры.Номенклатура.ЕдиницаИзмерения.ТипИзмеряемойВеличины = ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ((ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))) / (ВЫРАЗИТЬ(ЦеныНоменклатуры.Номенклатура.ЕдиницаИзмерения.Числитель / ЦеныНоменклатуры.Номенклатура.ЕдиницаИзмерения.Знаменатель КАК ЧИСЛО(15, 7))) КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.Упаковка)
                        И ЕСТЬNULL(ЦеныНоменклатуры.Упаковка.Знаменатель, 0) <> 0
                    ТОГДА ВЫРАЗИТЬ(ЦеныНоменклатуры.Упаковка.Числитель / ЦеныНоменклатуры.Упаковка.Знаменатель КАК ЧИСЛО(15, 7))
                КОГДА ЦеныНоменклатуры.Упаковка.ТипИзмеряемойВеличины = ЗНАЧЕНИЕ(Перечисление.ТипыИзмеряемыхВеличин.КоличествоШтук)
                    ТОГДА 1
                ИНАЧЕ NULL
            КОНЕЦ, 1) КАК ЧИСЛО(15, 3)) КАК Доступно
ИЗ
    Справочник.Номенклатура КАК СправочникНоменклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
                КОНЕЦПЕРИОДА(&Дата, ДЕНЬ),
                ВидЦены = &ВидыЦен
                    И Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) {(Номенклатура).* КАК Номенклатура}) КАК ЦеныНоменклатуры
        ПО (ЦеныНоменклатуры.Номенклатура = СправочникНоменклатура.Ссылка)
            И (ЦеныНоменклатуры.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка))
            И (ЦеныНоменклатуры.ВидЦены = &ВидыЦен)
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют.СрезПоследних(, ) КАК КурсыСрезПоследнихВалютаЦены
        ПО (КурсыСрезПоследнихВалютаЦены.Валюта = ЦеныНоменклатуры.Валюта)
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют.СрезПоследних(, Валюта = &Валюта) КАК КурсыСрезПоследнихВалютаДокумента
        ПО (ИСТИНА)
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СвободныеОстатки.Остатки(
                ,
                Склад = &Склад
                    И Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) {(Номенклатура).* КАК Номенклатура}) КАК СвободныеОстатки
        ПО (СвободныеОстатки.Склад = &Склад)
            И (СвободныеОстатки.Номенклатура = СправочникНоменклатура.Ссылка)
            И (СвободныеОстатки.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка))
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДоступныеОстаткиПланируемыхПоступлений КАК ОстаткиИзЗаказов
        ПО (ОстаткиИзЗаказов.Склад = &Склад)
            И (ОстаткиИзЗаказов.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка))
            И (ОстаткиИзЗаказов.ДатаДоступности = ДАТАВРЕМЯ(1, 1, 1))
            И (ОстаткиИзЗаказов.Номенклатура = СправочникНоменклатура.Ссылка)
            И (ОстаткиИзЗаказов.Количество < 0)

ГДЕ
    НЕ СправочникНоменклатура.ЭтоГруппа
    И СправочникНоменклатура.ТипНоменклатуры В (ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Товар), ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Набор), ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Услуга), ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Работа), ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.МногооборотнаяТара))
    
    
// И ЕСТЬNULL(СвободныеОстатки.ВНаличииОстаток, 0) > 0
    

УПОРЯДОЧИТЬ ПО
    Наименование
20 Галахад
 
гуру
09.06.20
11:34
Подпишусь. Скоро будет актуально.
21 blesha
 
09.06.20
11:36
(14)  картинки не получится, широкие, сами планы скинул))
22 Фрэнки
 
09.06.20
11:51
Скажу кратко - все плохо!
И добавлю - я бы весь этот запрос переписал по своему!!!

з.ы. Ну а что еще может сказать настоящий программист со стажем в несколько десятков лет?! :-)))
23 Фрэнки
 
09.06.20
11:52
А если серьезно, то там и так понятно, что оптимизация подобного запроса - это его радикальное переписывание
24 blesha
 
09.06.20
11:54
(18) " Если без этого отбора, то план почти такой же, везде обрабатывается <= 45 сток, индекс спул не возникает, тишь да гладь, кое где идут индекс сики по другим индексам."
план почти такой же по составу операторов, только количество строк намного меньше.
и например цена номенклатуры - таблица - _InfoRG43985 в ней используется другой индекс, в котором есть измерение номенклатура и по нему идет поиск (искать предикат).
т.е. условие на остатки сильно херит план, но не получением самих остатков(((
25 blesha
 
09.06.20
12:00
(22) все еще хуже чем перезапись запроса, т.к. в общем модуле он собирается динамически, зависит у кучи условий, как в типовой любят делать. И естественно хочется при дальнейшем обновлении ЕРП сделать это без геморроя.
2 + 2 = 3.9999999999999999999999999999999...