Имя: Пароль:
1C
1С v8
Оптимизация запроса или что-то еще?
0 noxxx
 
13.11.13
10:44
Господа, есть запрос, выполняющийся 4 секунды. Выполняется он в модуле проведения заказа покупателя, я уже писал об этом.

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

Запрос проверяет какое количество продукции по моделям и товарным группам мы уже приняли с определенной датой выпуска, и если ограничения позволяют, то принимаем еще. Если нет - не принимаем.

Есть вариант перенести эту проверку в процедуру ПередЗаписьюНаСервере и проверять там, но т.к. это дело будет выполняться вне транзакции, то есть вероятность что лимиты производства будут превышены, чего не хотелось бы.

Может быть кто-нибудь посоветует как переделать запрос таким образом, чтобы SQL строила более оптимальный план запроса, например, и он выполнялся бы быстрее?

Сам запрос:

ВЫБРАТЬ
    СУММА(ЗаказыПокупателейОстаткиСвернуто.КоличествоОстаток - ЕСТЬNULL(ЗаказыПоставщикамОстатки.КоличествоОстаток, 0) - ЕСТЬNULL(ТоварыВРезервеНаСкладах.КоличествоОстаток, 0)) КАК Количество,
    ЗначенияСвойствОбъектовТоварнаяГруппа.Значение КАК ТоварнаяГруппа,
    ЗначенияСвойствОбъектовМодель.Значение КАК Модель
ИЗ
    (ВЫБРАТЬ
        ЗаказыПокупателейОстатки.Номенклатура КАК Номенклатура,
        ЗаказыПокупателейОстатки.ЗаказПокупателя КАК ЗаказПокупателя,
        СУММА(ЕСТЬNULL(ЗаказыПокупателейОстатки.КоличествоОстаток, 0)) КАК КоличествоОстаток
    ИЗ
        РегистрНакопления.ЗаказыПокупателей.Остатки(
                &ДатаОстатков,
                СтатусПартии <> ЗНАЧЕНИЕ(Перечисление.СтатусыПартийТоваров.ВозвратнаяТара)
                    И НЕ Номенклатура.Комплект
                    И НЕ Номенклатура.Услуга
                    И Номенклатура.ВидВоспроизводства = &ВидВоспроизводства
                    И ЗаказПокупателя <> &Заказ
                    И ЗаказПокупателя.оДатаВыпуска = &ДатаОграничения) КАК ЗаказыПокупателейОстатки
    
    СГРУППИРОВАТЬ ПО
        ЗаказыПокупателейОстатки.ЗаказПокупателя,
        ЗаказыПокупателейОстатки.Номенклатура) КАК ЗаказыПокупателейОстаткиСвернуто
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.РазмещениеЗаказовПокупателей.Остатки(
                &ДатаОстатков,
                ТоварТара = ЗНАЧЕНИЕ(Перечисление.ТоварТара.Товар)
                    И ТИПЗНАЧЕНИЯ(ЗаказПоставщику) = ТИП(Документ.ЗаказПоставщику)
                    И ЗаказПокупателя <> &Заказ) КАК ЗаказыПоставщикамОстатки
        ПО ЗаказыПокупателейОстаткиСвернуто.Номенклатура = ЗаказыПоставщикамОстатки.Номенклатура
            И ЗаказыПокупателейОстаткиСвернуто.ЗаказПокупателя = ЗаказыПоставщикамОстатки.ЗаказПокупателя
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки(&ДатаОстатков, ДокументРезерва <> &Заказ) КАК ТоварыВРезервеНаСкладах
        ПО ЗаказыПокупателейОстаткиСвернуто.Номенклатура = ТоварыВРезервеНаСкладах.Номенклатура
            И ЗаказыПокупателейОстаткиСвернуто.ЗаказПокупателя = ТоварыВРезервеНаСкладах.ДокументРезерва
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектовТоварнаяГруппа
        ПО ЗаказыПокупателейОстаткиСвернуто.Номенклатура = ЗначенияСвойствОбъектовТоварнаяГруппа.Объект
            И (ЗначенияСвойствОбъектовТоварнаяГруппа.Свойство.Наименование = "Товарная группа")
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектовМодель
        ПО ЗаказыПокупателейОстаткиСвернуто.Номенклатура = ЗначенияСвойствОбъектовМодель.Объект
            И (ЗначенияСвойствОбъектовМодель.Свойство.Наименование = "Модель")
ГДЕ
    ЗаказыПокупателейОстаткиСвернуто.КоличествоОстаток - ЕСТЬNULL(ЗаказыПоставщикамОстатки.КоличествоОстаток, 0) - ЕСТЬNULL(ТоварыВРезервеНаСкладах.КоличествоОстаток, 0) > 0

СГРУППИРОВАТЬ ПО
    ЗначенияСвойствОбъектовТоварнаяГруппа.Значение,
    ЗначенияСвойствОбъектовМодель.Значение
1 Ненавижу 1С
 
гуру
13.11.13
10:47
избавься от:

И (ЗначенияСвойствОбъектовТоварнаяГруппа.Свойство.Наименование = "Товарная группа")
И (ЗначенияСвойствОбъектовМодель.Свойство.Наименование = "Модель")
2 Нуф-Нуф
 
13.11.13
10:47
ужаснах
3 Нуф-Нуф
 
13.11.13
10:48
РегистрНакопления.ЗаказыПокупателей.Остатки и РегистрНакопления.РазмещениеЗаказовПокупателей.Остатки в в отдельные временные таблицы
4 Sabbath
 
13.11.13
10:48
(0) разыменование в условиях и соединениях - не очень
ну и попробуй без вложенных
5 Нуф-Нуф
 
13.11.13
10:48
РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки тоже
6 Sabbath
 
13.11.13
10:48
+(4) с ВТ
7 Sabbath
 
13.11.13
10:49
а блокировки и взаимоблокировки все равно могут быть)
8 Ненавижу 1С
 
гуру
13.11.13
10:50
может вмето ГДЕ надо ИМЕЮЩИЕ по логике?
9 Нуф-Нуф
 
13.11.13
10:50
И ЗаказПокупателя <> &Заказ
                    И ЗаказПокупателя.оДатаВыпуска = &ДатаОграничения

можно заменить отдельной таблицей с индексацией и ее совать в параметры временной таблицы ЗаказыПокупателей.Остатки
10 Нуф-Нуф
 
13.11.13
10:50
(7) блокировки и взаимоблокировки как бы разные вещи
11 noxxx
 
13.11.13
10:51
(7) Да это понятно, но когда проведение документа из-за очередей занимает до 30 секунд - это плохо.

(1) А как сделать лучше?
12 Нуф-Нуф
 
13.11.13
10:53
И (ЗначенияСвойствОбъектовТоварнаяГруппа.Свойство = &СвойствоГруппа)
И (ЗначенияСвойствОбъектовМодель.Свойство = &СвойствоМодель)
13 WildSery
 
13.11.13
10:55
Вложенный запрос радует.
Достаём остатки по Номенклатуре и Заказу, а потом ещё зачем-то группируем по ним же. ЕстьNULL внутри суммы тоже хорош.
14 Ненавижу 1С
 
гуру
13.11.13
10:55
(11) предопределнные значения или константы
15 noxxx
 
13.11.13
11:03
(13) Потом к этой таблице присоединяются резервы и размещения, и если в заказе, например, будет 2 строки одной номенклатуры, но с разной ценой, то будет 2 строки на номенклатуру. Разве нет?
16 WildSery
 
13.11.13
11:19
(15) С какой ещё ценой? Я говорю об этом:
ВЫБРАТЬ
    Номенклатура,
    ЗаказПокупателя,
    СУММА(ЕСТЬNULL(КоличествоОстаток, 0))
ИЗ
    РегистрНакопления.ЗаказыПокупателей.Остатки() КАК ЗаказыПокупателейОстатки
СГРУППИРОВАТЬ ПО
    ЗаказПокупателя,
    Номенклатура
17 noxxx
 
13.11.13
11:47
(16) Я уже понял.

Переделал запрос в соответствии с рекомендациями, стало намного быстрее:

ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗаказПокупателя.Ссылка КАК Ссылка
ПОМЕСТИТЬ ЗаказыНаДатуВыпуска
ИЗ
    Документ.ЗаказПокупателя КАК ЗаказПокупателя
ГДЕ
    ЗаказПокупателя.оДатаВыпуска = &ДатаОграничения
    И ЗаказПокупателя.Проведен = ИСТИНА

ИНДЕКСИРОВАТЬ ПО
    Ссылка
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЗаказыПокупателейОстатки.Номенклатура КАК Номенклатура,
    ЗаказыПокупателейОстатки.ЗаказПокупателя КАК ЗаказПокупателя,
    ЗаказыПокупателейОстатки.КоличествоОстаток КАК КоличествоОстаток
ПОМЕСТИТЬ Заказы
ИЗ
    РегистрНакопления.ЗаказыПокупателей.Остатки(
            &ДатаОстатков,
            СтатусПартии <> ЗНАЧЕНИЕ(Перечисление.СтатусыПартийТоваров.ВозвратнаяТара)
                И НЕ Номенклатура.Комплект
                И НЕ Номенклатура.Услуга
                И ЗаказПокупателя <> &Заказ
                И ЗаказПокупателя В
                    (ВЫБРАТЬ
                        ЗаказыНаДатуВыпуска.Ссылка
                    ИЗ
                        ЗаказыНаДатуВыпуска)) КАК ЗаказыПокупателейОстатки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    РазмещениеЗаказовПокупателейОстатки.ЗаказПокупателя,
    РазмещениеЗаказовПокупателейОстатки.Номенклатура,
    РазмещениеЗаказовПокупателейОстатки.КоличествоОстаток
ПОМЕСТИТЬ РазмещениеЗаказов
ИЗ
    РегистрНакопления.РазмещениеЗаказовПокупателей.Остатки(
            &ДатаОстатков,
            НЕ Номенклатура.Комплект
                И НЕ Номенклатура.Услуга
                И ЗаказПокупателя <> &Заказ
                И ЗаказПокупателя В
                    (ВЫБРАТЬ
                        ЗаказыНаДатуВыпуска.Ссылка
                    ИЗ
                        ЗаказыНаДатуВыпуска)) КАК РазмещениеЗаказовПокупателейОстатки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ТоварыВРезервеНаСкладахОстатки.Номенклатура,
    ТоварыВРезервеНаСкладахОстатки.ДокументРезерва,
    ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток
ПОМЕСТИТЬ РезервыНаСкладах
ИЗ
    РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки(
            &ДатаОстатков,
            НЕ Номенклатура.Комплект
                И НЕ Номенклатура.Услуга
                И ДокументРезерва <> &Заказ
                И ДокументРезерва В
                    (ВЫБРАТЬ
                        ЗаказыНаДатуВыпуска.Ссылка
                    ИЗ
                        ЗаказыНаДатуВыпуска)) КАК ТоварыВРезервеНаСкладахОстатки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЗаказыНаДату.КоличествоОстаток + ЕСТЬNULL(РазмещениеЗаказов.КоличествоОстаток, 0) + ЕСТЬNULL(РезервыНаСкладах.КоличествоОстаток, 0) КАК Количество,
    ЕСТЬNULL(ЗначенияСвойствОбъектовТГ.Значение, ЗНАЧЕНИЕ(Справочник.оТоварныеГруппы.ПустаяСсылка)) КАК ТоварнаяГруппа,
    ЕСТЬNULL(ЗначенияСвойствОбъектовМодель.Значение, ЗНАЧЕНИЕ(Справочник.оМодели.ПустаяСсылка)) КАК Модель
ПОМЕСТИТЬ ИТОГ
ИЗ
    Заказы КАК ЗаказыНаДату
        ЛЕВОЕ СОЕДИНЕНИЕ РазмещениеЗаказов КАК РазмещениеЗаказов
        ПО ЗаказыНаДату.ЗаказПокупателя = РазмещениеЗаказов.ЗаказПокупателя
            И ЗаказыНаДату.Номенклатура = РазмещениеЗаказов.Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РезервыНаСкладах КАК РезервыНаСкладах
        ПО ЗаказыНаДату.ЗаказПокупателя = РезервыНаСкладах.ДокументРезерва
            И ЗаказыНаДату.Номенклатура = РезервыНаСкладах.Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектовТГ
        ПО ЗаказыНаДату.Номенклатура = ЗначенияСвойствОбъектовТГ.Объект
            И (ЗначенияСвойствОбъектовТГ.Свойство = &СвойствоТоварнаяГруппа)
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектовМодель
        ПО ЗаказыНаДату.Номенклатура = ЗначенияСвойствОбъектовМодель.Объект
            И (ЗначенияСвойствОбъектовМодель.Свойство = &СвойствоМодель)
ГДЕ ЗаказыНаДату.КоличествоОстаток + ЕСТЬNULL(РазмещениеЗаказов.КоличествоОстаток, 0) + ЕСТЬNULL(РезервыНаСкладах.КоличествоОстаток, 0) > 0
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ИТОГ.ТоварнаяГруппа,
    ИТОГ.Модель,
    СУММА(ИТОГ.Количество) КАК Количество
ИЗ
    ИТОГ КАК ИТОГ

СГРУППИРОВАТЬ ПО
    ИТОГ.Модель,
    ИТОГ.ТоварнаяГруппа
Я не хочу быть самым богатым человеком на кладбище. Засыпать с чувством, что за день я сделал какую-нибудь потрясающую вещь — вот что меня интересует. Стив Джобс