Имя: Пароль:
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
;

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

СГРУППИРОВАТЬ ПО
    ИТОГ.Модель,
    ИТОГ.ТоварнаяГруппа
Чтобы обнаруживать ошибки, программист должен иметь ум, которому доставляет удовольствие находить изъяны там, где, казалось, царят красота и совершенство. Фредерик Брукс-младший