Добрый день!
Возник такой вопрос, как будет работать быстрее и почему?
Допустим есть некая таблица, например документы РасходнаяНакладная, которые нужно в запросе отобрать по ссылочному реквизиту (допустим контрагенту). При этом в процедуре, где это нужно сделать, нет значения ссылки контрагента, есть только его код (например загружаем из внешнего файла где есть коды).
На ум приходит 2 варианта:
1) Получить ссылку на контрагента поиском из базы по коду, потом передать ссылку как параметр в запрос:

```1c
    НужныйКонт = справочники.контрагенты.найтиПоКоду("111");

    Запрос = новый запрос("выбрать Док.ссылка из Документ.РасходнаяНакладная как Док где Док.Контрагент = &НужныйКонт");
    Запрос.установитьПараметр("НужныйКонт", НужныйКонт);
```

2) Другой вариант - передать код сразу в запрос, в секцию ГДЕ.

```1c
    Запрос = новый запрос("выбрать Док.ссылка из Документ.РасходнаяНакладная как Док где Док.Контрагент.Код = 111");
    Запрос.установитьПараметр("НужныйКонт", НужныйКонт);
```

Но в первом случае - поиск по коду в базе - это ведь сам по себе лишний запрос?
А во втором случае - лишнее соединение с таблицей контрагентов?
Как правильнее?
Всем ответившим спасибо.
---
Добрый день,
тоже временами задаюсь этим вопросом, но все же установил для себя некую логику.

По моему мнению вариант 1 не самый верный так как действительно выполняется 2 запроса и это не оптимально, данные из базы данных лучше получать сразу одним запросом. (иногда проще сделать так, это не табу, но все же часто таким методом лучше не пользоваться).

По поводу варианта 2 - я не вижу каких то глобальных проблем в том что появляется лишнее соединение, были бы проблемы если бы контрагент был составного типа.

И еще, добавлю вариант 3

```1c
    Запрос = новый запрос();
    Запрос.Текст =
    "Выбрать
    |Контрагенты.Ссылка
    |ПОМЕСТИТЬ НужныеКонтрагенты
    |Из Справочник.Контрагенты КАК Контрагенты
    |ГДЕ Контрагенты.Код = &Код ;
    |
    |Выбрать Док.ссылка из Документ.РасходнаяНакладная как Док
    |ВНУТРЕННЕЕ СОЕДИНЕНИЕ НужныеКонтрагенты
    |ПО Док.Контрагент = НужныеКонтрагенты.Ссылка"
    Запрос.установитьПараметр("Код", 111);
```

Как насчет такого варианта?

В общем, если данная концепция будет взята за основу в конфигурации, то нужно менять архитектуру системы, скажем брать данные из существующих регистров :)
---
тогда уж фильтр из секции ГДЕ перенести в параметры соединения. Иначе, если большой список Контрагентов и очень большой список документов, будут неоправданно много/долго соединяться, и уже из всех соединений отбираться нужные.
---
Добрый день,
тоже временами задаюсь этим вопросом, но все же установил для себя некую логику.

По моему мнению вариант 1 не самый верный так как действительно выполняется 2 запроса и это не оптимально, данные из базы данных лучше получать сразу одним запросом. (иногда проще сделать так, это не табу, но все же часто таким методом лучше не пользоваться).

По поводу варианта 2 - я не вижу каких то глобальных проблем в том что появляется лишнее соединение, были бы проблемы если бы контрагент был составного типа.

И еще, добавлю вариант 3

```1c
    Запрос = новый запрос();
    Запрос.Текст =
    "Выбрать
    |Контрагенты.Ссылка
    |ПОМЕСТИТЬ НужныеКонтрагенты
    |Из Справочник.Контрагенты КАК Контрагенты
    |ГДЕ Контрагенты.Код = &Код ;
    |
    |Выбрать Док.ссылка из Документ.РасходнаяНакладная как Док
    |ВНУТРЕННЕЕ СОЕДИНЕНИЕ НужныеКонтрагенты
    |ПО Док.Контрагент = НужныеКонтрагенты.Ссылка"
    Запрос.установитьПараметр("Код", 111);
```

Как насчет такого варианта?

В общем, если данная концепция будет взята за основу в конфигурации, то нужно менять архитектуру системы, скажем брать данные из существующих регистров :)
---
Третий вариант понравился, спасибо. Я и сам последнее время склоняюсь к тому что предварительно искать по коду хуже чем сразу в одном запросе, но думал вдруг чего-то не знаю.
---
Больше временных таблиц богу временных таблиц!

(1)

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

```1c
    ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка
    ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    ГДЕ
    РеализацияТоваровУслуг.Контрагент.Код = &Код
```
---
И какая же существенная разница? И там и там соединение с таблицей контрагентов, которая фильтруется по коду.
---
(13) поставьте себя на место движка базы данных и представьте, как вы будете выполнять каждый из запросов.
---
поставили себя? И как?
---
, окей, подумаю за вас.

вариант 8:
1. быстро выбрать ссылку на контрагента по коду
2. просмотреть таблицу документа, отбирая ссылки, где контаргент = ссылке из п.1

вариант с точкой:
1. просмотреть таблицу документа, для каждой строки
1.1. быстро найти контрагента в таблице контрагентов и проверить его код

вариант с условием в соединении (контрагент джойн реализация по контр.ссылка = реализ.контарегнт и контр.код = &код, так?)
1. просмотреть таблицу контрагентов, для каждой строки
1.1. проверить, равен ли код нужному, если да, то
1.2. просмотреть таблицу документов, ища нужные по контрагенту и п. 1.1.

Вариант с тем, что оптимизатор запроса подумает за вас пока опустим.
---
вариант 8:
1. быстро выбрать ссылку на контрагента по коду
2. просмотреть таблицу документа, отбирая ссылки, где контаргент = ссылке из п.1
Ничего не упустили?
Ок. Думаем за Вас:
Вот код из (8):

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

1. Читаем таблицу Справочник.Контрагенты. Всю.
2. Читаем таблицу Документ.РеализацияТоваровУслуг
3. Формируем промежуточную таблицу всех соединений Контрагенты <=> РеализацияТоваровУслуг
4. Из полученной таблицы отбираем только те, где Контагент.Код = &Код

Оптимально?
---
ничего не упустил; попытка подумать за меня не удалась.

P.S. в (20) уже сослались на оптимизатор запроса, так что дальше спорить не о чем - скорее всего, он действительно запилит хорошо. Давайте будем в него верить и не париться!
---
Вот код, который получается на уровне SQL:

```1c
    Fields:(
    T2.Ссылка
    )
    _DOCUMENT65 (T2) RANGE SCAN USING INDEX (_DOCUMENT65HPK@) (1 fields)

    NESTED LOOP
    _REFERENCE25 (T1) RANGE SCAN USING INDEX (_REFERENCE25_CODE@) (3 fields)
    WHERE
    (T1.Ссылка = T2.Контрагент)
    AND
    (T1.Код = 0461111101)
```

Он одинаковый, что для (8), что для (16). Если присмотреться, то 1С просто приводит код (8) к (16). Но это уже заслуга 1С.
---
надо учитывать ресурсы на формирование временной таблицы
делайте замеры производительности
---
тогда уж фильтр из секции ГДЕ перенести в параметры соединения. Иначе, если большой список Контрагентов и очень большой список документов, будут неоправданно много/долго соединяться, и уже из всех соединений отбираться нужные.
---
нужно добавить индекс по Контрагенты.Ссылка. Тогда ВНУТРЕННЕЕ СОЕДИНЕНИЕ будет быстрее выполняться
---
Зачем создавать временную таблицу, там где можно обойтись без нее? Это дорогая операция для СУБД
---
В чем проблема с временными таблицами?
Я бы понял замечание если бы я реализовал это в виде вложенного запроса - то да, это дорогая операция для СУБД.
В 1С есть рекомендация что временные таблицы лучше использовать вместо вложенных запросов - это да. С вложенным запросом СУБД не сразу формирует оптимальный запрос. Требую обоснования :)
---
временные таблицы лучше использовать вместо вложенных запросов
неверно.
верно - временные таблицы лучше использовать вместо вложенных запросов во многих случаях, но уж точно не для хранения таблицы с одной! строкой
---
Элементарные вложенные запросы не страшны. Не надо виртуальные таблицы заворачивать в подзапрос ибо они еще и сами подзапрос. А запрос типа sel ect col_1 fr om Table where col_1='aaa' вполне можно вложить
---
Лучше сразу в запросе искать по коду.
---
Сделал анализ производительности,
поиск по коду - запросом, и найтипо коду.
Запросом - все таки медленнее
---
Вот, вообще без всяких параметров, напрямую в запрос вписал код.

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

    ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка
    ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    ГДЕ
    РеализацияТоваровУслуг.Контрагент.Код = &Код
```

Для ms sql с вероятность 99% будет составлен один план запроса. Запросы одинаково исполнятся примерно.
---
Для ms sql с вероятность 99% будет составлен один план запроса. Запросы одинаково исполнятся примерно.
Вот на этом невысказанном предположении и держится весь хрупкий механизм нашей оптимизации…
---
это не предположение. во втором случае платформа сама добавит левое соединение.