Форум 1С
Программистам, бухгалтерам, администраторам, пользователям
Задай вопрос - получи решение проблемы
28 мар 2024, 20:06

Вторник. Вопрос 5

Автор mixqn, 12 мар 2013, 00:51

0 Пользователей и 1 гость просматривают эту тему.

mixqn

Вашему вниманию предлагается запрос. Произведите его оптимизацию и поясните свои действия.
Примечание таблица РегистрСведений.ЛимитыКредиторскойЗадолженности имеет следующие измерения:


  • Организация
  • Контрагент
  • Договор
  • ТипЗадолженности (долгосрочная, краткосрочная)

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

СГРУППИРОВАТЬ ПО
ЛимитыКредиторскойЗадолженности.Организация,
ЛимитыКредиторскойЗадолженности.Контрагент,
ЛимитыКредиторскойЗадолженности.Договор) КАК ЛимитыКредиторскойЗадолженности
ПО ПоступлениеТоваровИУслуг.Контрагент = ЛимитыКредиторскойЗадолженности.Контрагент
И ПоступлениеТоваровИУслуг.Договор = ЛимитыКредиторскойЗадолженности.Договор
ГДЕ
(ПоступлениеТоваровИУслуг.Сумма < &МинимальнаяСуммаЗадолженности
ИЛИ ПоступлениеТоваровИУслуг.Сумма < ЛимитыКредиторскойЗадолженности.Сумма)
И (ПоступлениеТоваровИУслуг.Договор.ДоговорСПодрядчиком = ИСТИНА
ИЛИ ПоступлениеТоваровИУслуг.Договор.ДоговорСПоставщиком = ИСТИНА)



Предыдущий вопрос Следующий вопрос

nidom

ВЫБРАТЬ
   ПоступлениеТоваровИУслуг.Ссылка,
   ПоступлениеТоваровИУслуг.Номер,
   ПоступлениеТоваровИУслуг.Договор,
   ПоступлениеТоваровИУслуг.Контрагент,
   ПоступлениеТоваровИУслуг.Организация,
   ПоступлениеТоваровИУслуг.Сумма,
   ПоступлениеТоваровИУслуг.Дата
ИЗ
   Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг
      ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
         ЛимитыКредиторскойЗадолженности.Организация КАК Организация,
         ЛимитыКредиторскойЗадолженности.Контрагент КАК Контрагент,
         ЛимитыКредиторскойЗадолженности.Договор КАК Договор,
         СУММА(ЛимитыКредиторскойЗадолженности.Сумма) КАК Сумма
      ИЗ
         РегистрСведений.ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности
      ГДЕ
         ЛимитыКредиторскойЗадолженности.Организация = &Организация
         И (ЛимитыКредиторскойЗадолженности.Договор.ДоговорСПодрядчиком
               ИЛИ ЛимитыКредиторскойЗадолженности.Договор.ДоговорСПоставщиком) // *1
      
      СГРУППИРОВАТЬ ПО
         ЛимитыКредиторскойЗадолженности.Организация,
         ЛимитыКредиторскойЗадолженности.Контрагент,
         ЛимитыКредиторскойЗадолженности.Договор) КАК ЛимитыКредиторскойЗадолженности
      ПО ПоступлениеТоваровИУслуг.Контрагент = ЛимитыКредиторскойЗадолженности.Контрагент
         И ПоступлениеТоваровИУслуг.Договор = ЛимитыКредиторскойЗадолженности.Договор
         И (ПоступлениеТоваровИУслуг.Сумма < &МинимальнаяСуммаЗадолженности
            ИЛИ ПоступлениеТоваровИУслуг.Сумма < ЛимитыКредиторскойЗадолженности.Сумма) // *2
ГДЕ
   (ПоступлениеТоваровИУслуг.Договор.ДоговорСПодрядчиком
         ИЛИ ПоступлениеТоваровИУслуг.Договор.ДоговорСПоставщиком) // *3

1. Еще больше ограничиваем выборку из регистра только по договорам с подрядчиками или по договорам с поставщиками, чтобы результат вложенного запроса по регистру сведений стал более компактным.
2. Накладываем условие только на основную таблицу запроса (по документам), а условие с использованием результата вложенной таблицы переносим в условие связи.
3. Убираем кобинацию "=Истина" из условий, чтобы лишний раз не производить сравнение.

ninzel

Наложить отбор договоров на внутренний запрос, тогда результат соединения таблиц будет меньше => быстее работает запрос

serj1C

1) неявное соединение с справочником договором делаю явным и делаю внутреннее соединение, чтобы отфильтровать договоры без галок
2) подзапрос выносим во временную таблицу с индексирование по договору
3) из временной таблицы убираем "лишние" поля:
    - организация - т.к. не используется в соединении, нужна только для отбора, что странно;
    - контрагент - т.к. (скорей всего) является владельцем справочника договоры, избыточен. А про индексы нам ничего не известно
4) Накладываем ограничение на сумму, т.к. значения меньшие МинимальнаяСуммаЗадолженности все-равно пройдут и без соединения.

Запрос:

ВЫБРАТЬ
    ЛимитыКредиторскойЗадолженности.Договор КАК Договор,
    СУММА(ЛимитыКредиторскойЗадолженности.Сумма) КАК Сумма
Поместить ЛимитыКредиторскойЗадолженности
ИЗ
    РегистрСведений.ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности
    внутреннее соединение Справочник.Договоры СпрДоговоры По
    ЛимитыКредиторскойЗадолженности.Договор = СпрДоговоры.Ссылка
    И(СпрДоговоры.ДоговорСПодрядчиком ИЛИ СпрДоговоры.ДоговорСПоставщиком)
ГДЕ
    ЛимитыКредиторскойЗадолженности.Организация = &Организация

СГРУППИРОВАТЬ ПО
    ЛимитыКредиторскойЗадолженности.Договор
Имеющие
СУММА(ЛимитыКредиторскойЗадолженности.Сумма) > &МинимальнаяСуммаЗадолженности
Индексировать по Договор;

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

AQR

Вместо вложенного запроса использовать временные таблицы,  Уменьшить набор данных для объединения условиями    ЛимитыКредиторскойЗадолженности.Организация = &Организация И ЛимитыКредиторскойЗадолженности.Сумма < &МинимальнаяСуммаЗадолженност.

Итоговый запрос:
ВЫБРАТЬ
   ЛимитыКредиторскойЗадолженности.Контрагент,
   ЛимитыКредиторскойЗадолженности.Договор,
   СУММА(ЛимитыКредиторскойЗадолженности.Сумма) КАК Сумма
ПОМЕСТИТЬ ЛимитыСотбором
ИЗ
   РегистрСведений.ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности
ГДЕ
   ЛимитыКредиторскойЗадолженности.Организация = &Организация
   И ЛимитыКредиторскойЗадолженности.Сумма < &МинимальнаяСуммаЗадолженност

СГРУППИРОВАТЬ ПО
   ЛимитыКредиторскойЗадолженности.Договор,
   ЛимитыКредиторскойЗадолженности.Контрагент
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
   ПоступлениеТоваровУслуг.Ссылка,
   ПоступлениеТоваровУслуг.Номер,
   ПоступлениеТоваровУслуг.Договор,
   ПоступлениеТоваровУслуг.Контрагент,
   ПоступлениеТоваровУслуг.Организация,
   ПоступлениеТоваровУслуг.СуммаДокумента,
   ПоступлениеТоваровУслуг.Дата
ИЗ
   Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг
      ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЛимитыСотбором КАК ЛимитыСотбором
      ПО ПоступлениеТоваровУслуг.Контрагент = ЛимитыСотбором.Контрагент
         И ПоступлениеТоваровУслуг.Договор = ЛимитыСотбором.Договор
ГДЕ
   (ПоступлениеТоваровУслуг.Договор.ДоговорСПодрядчиком = ИСТИНА
         ИЛИ ПоступлениеТоваровУслуг.Договор.ДоговорСПоставщиком = ИСТИНА)
   И ПоступлениеТоваровУслуг.СуммаДокумента < ЛимитыСотбором.Сумма

Slin

Вообще есть подозрение, что надо исправить запрос в плане ошибок, а не оптимизировать. Но, допустим, что так и надо...

ВЫБРАТЬ
    ПоступлениеТоваровИУслуг.Ссылка,
    ПоступлениеТоваровИУслуг.Номер,
    ПоступлениеТоваровИУслуг.Договор,
    ПоступлениеТоваровИУслуг.Контрагент,
    ПоступлениеТоваровИУслуг.Организация,
    ПоступлениеТоваровИУслуг.Сумма,
    ПоступлениеТоваровИУслуг.Дата
ПОМЕСТИТЬ НачальныйОтбор
ИЗ
    Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг
ГДЕ
    ПоступлениеТоваровИУслуг.Договор.ДоговорСПодрядчиком ИЛИ ПоступлениеТоваровИУслуг.Договор.ДоговорСПоставщиком;
//////////////////////////
ВЫБРАТЬ *
ПОМЕСТИТЬ Отбор1
ИЗ НачальныйОтбор КАК НачальныйОтбор
ГДЕ
   НачальныйОтбор.Организация = &Организация;

//////////////////////////
ВЫБРАТЬ *
ИЗ Отбор1 КАК Отбор1
   ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
        ЛимитыКредиторскойЗадолженности.Организация КАК Организация,
        ЛимитыКредиторскойЗадолженности.Контрагент КАК Контрагент,
        ЛимитыКредиторскойЗадолженности.Договор КАК Договор,
        СУММА(ЛимитыКредиторскойЗадолженности.Сумма) КАК Сумма
    ИЗ
        РегистрСведений.ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности
    СГРУППИРОВАТЬ ПО
        ЛимитыКредиторскойЗадолженности.Организация,
        ЛимитыКредиторскойЗадолженности.Контрагент,
        ЛимитыКредиторскойЗадолженности.Договор) КАК ЛимитыКредиторскойЗадолженности
    ПО Отбор1.Организация = ЛимитыКредиторскойЗадолженности.Организация
        И Отбор1.Контрагент = ЛимитыКредиторскойЗадолженности.Контрагент
        И Отбор1.Договор = ЛимитыКредиторскойЗадолженности.Договор
ГДЕ
   Отбор1.Сумма < &МинимальнаяСуммаЗадолженности ИЛИ Отбор1.Сумма < ЛимитыКредиторскойЗадолженности.Сумма
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ *
ИЗ НачальныйОтбор КАК НачальныйОтбор
ГДЕ
   НЕ НачальныйОтбор.Организация = &Организация И НачальныйОтбор.Сумма < &МинимальнаяСуммаЗадолженности

Оптимизация достигается за счёт уменьшения сложности условий отбора и уменьшения исходного набора данных при левом соединении(там же исключается отбор по организации, за счет соединения).
также на заключительном этапе применятся инструкия ОБЪЕДИНИТЬ ВСЕ вместо ОБЪЕДИНИТЬ  для ускорения операции объединения множеств непересекающихся по определению.

P.S. А зачем отдельно информация о полях измерений регистра сведений? лучше бы написали периодический он или нет
skype: slin-dev

soft

1 вариант
Поставление товаров и услуг, вместе с условием на вид договора - в отдельную ВТ, проиндексировать ее по контрагенту и договору.
Вложенный запрос - к регистру сведений - так же в ВТ, так же проиндексировать по Контрагенту и Договору, условие на организацию - оставить в ВТ.
Объединяем 2 ВТ по контрагенту и договору - накладываем условие на сумму.

2 вариант
Вложенный запрос у нас только ради суммы - сама по себе сумма тут достаточно странно выглядит - это регистр сведений, зачем мы его суммируем - не очень понятно. Если складываем краткосрочный и долгосрочный лимит, то зачем нам тогда такое измерение, которым мы не пользуемся(не делим лимит на один и другой - тут скорее всего надо брать жестко только краткосрочную).
В общем, если сумма нам по логике все же не нужна, то можно ПТУ объединить напрямую с регистром сведений, но в условие объединения добавить организацию (чтобы нормально использовался индекс регистра).
Хотя в любом случае 1 вариант будет поинтереснее.


SlazZy

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


По логике запроса требуется выбрать лимиты задолженности, поэтому я убрал лишние поля выборки из регистра, они должны совпадать с полями документа, поэтому делаем связь таблиц по трем измерениям регистра, и выбираем всего 2 поля - сумма и ТипЗадолженности. В этом случае группировка тоже не имеет смысла, тк мы делаем запрос по полной комбинации полей, как следствие дублей в итоговой таблице быть не может: Комбинация ТипЗадолженности - Сумма, всегда будет уникальна.
И немного убрал избыточность условий (ПоступлениеТоваровИУслуг.Договор.ДоговорСПодрядчиком = ИСТИНА) -> (ПоступлениеТоваровИУслуг.Договор.ДоговорСПодрядчиком).

Alex_k

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

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

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

СГРУППИРОВАТЬ ПО
ЛимитыКредиторскойЗадолженности.Организация,
ЛимитыКредиторскойЗадолженности.Контрагент,
ЛимитыКредиторскойЗадолженности.Договор
// проиндексируем для ускорения
ИНДЕКСИРОВАТЬ ПО
Организация,
Контрагент,
Договор
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПоступлениеТоваровИУслуг.Ссылка,
ПоступлениеТоваровИУслуг.Номер,
ПоступлениеТоваровИУслуг.ДоговорКонтрагента,
ПоступлениеТоваровИУслуг.Контрагент,
ПоступлениеТоваровИУслуг.Организация,
ПоступлениеТоваровИУслуг.Сумма,
ПоступлениеТоваровИУслуг.Дата
ИЗ
Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг
ЛЕВОЕ СОЕДИНЕНИЕ ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности
//По полному ключу поиск будет быстрее
                ПО ПоступлениеТоваровИУслуг.Организация = ЛимитыКредиторскойЗадолженности.Организация
И ПоступлениеТоваровИУслуг.Контрагент = ЛимитыКредиторскойЗадолженности.Контрагент
И ПоступлениеТоваровИУслуг.Договор = ЛимитыКредиторскойЗадолженности.Договор
// В соединении условие по договорам выполнится быстрее
                ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТДоговара КАК ВТДоговара
ПО ПоступлениеТоваровИУслуг.ДоговорКонтрагента = ВТДоговара.Договор
ГДЕ
        // в ЛимитыКредиторскойЗадолженности.Сумма уже максимум из лимита и минимальной суммы, что соответствует сравнению с этими двумя значениями через ИЛИ
ПоступлениеТоваровИУслуг.Сумма < ЕСТЬNULL(ЛимитыКредиторскойЗадолженности.Сумма, &МинимальнаяСуммаЗадолженности)

sivalor

При использовании временных таблиц велика вероятность выбора СУБД неоптимального плана, так что следует использовать
временные таблицы.
Отбор по виду договоров перенесен в условия соединения с этим справочником, для отбора на этапе соединения.

ВЫБРАТЬ
ЛимитыКредиторскойЗадолженности.Организация КАК Организация, 
ЛимитыКредиторскойЗадолженности.Контрагент КАК Контрагент, 
ЛимитыКредиторскойЗадолженности.Договор КАК Договор, 
СУММА(ЛимитыКредиторскойЗадолженности.Сумма) КАК Сумма 
Поместить ЛимитыКредиторскойЗадолженности
ИЗ РегистрСведений.ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности 
ГДЕ ЛимитыКредиторскойЗадолженности.Организация = &Организация   
СГРУППИРОВАТЬ ПО
ЛимитыКредиторскойЗадолженности.Организация,
ЛимитыКредиторскойЗадолженности.Контрагент, 
ЛимитыКредиторскойЗадолженности.Договор
ИНДЕКСИРОВАТЬ ПО
Организация,
Контрагент,
Договор
;

ВЫБРАТЬ 
ПоступлениеТоваровИУслуг.Ссылка, 
ПоступлениеТоваровИУслуг.Номер, 
ПоступлениеТоваровИУслуг.Договор, 
ПоступлениеТоваровИУслуг.Контрагент, 
ПоступлениеТоваровИУслуг.Организация, 
ПоступлениеТоваровИУслуг.Сумма, 
ПоступлениеТоваровИУслуг.Дата 
ИЗ Документ.ПоступлениеТоваровИУслуг КАК ПоступлениеТоваровИУслуг 
ЛЕВОЕ СОЕДИНЕНИЕ ЛимитыКредиторскойЗадолженности КАК ЛимитыКредиторскойЗадолженности 
ПО  ПоступлениеТоваровИУслуг.Организация = ЛимитыКредиторскойЗадолженности.Организация И
ПоступлениеТоваровИУслуг.Контрагент = ЛимитыКредиторскойЗадолженности.Контрагент 
И  ПоступлениеТоваровИУслуг.Договор = ЛимитыКредиторскойЗадолженности.Договор
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Договоры КАК Договоры
ПО ПоступлениеТоваровИУслуг.Договор= Договоры.Ссылка
И (Договор.ДоговорСПодрядчиком ИЛИ Договор.ДоговорСПоставщиком)

ГДЕ
(ПоступлениеТоваровИУслуг.Сумма < &МинимальнаяСуммаЗадолженности  ИЛИ
ПоступлениеТоваровИУслуг.Сумма < ЕстьNull(ЛимитыКредиторскойЗадолженности.Сумма,0)) 

Теги:
Рейтинг@Mail.ru

Поиск