Форум на Kuban.ru (http://forums.kuban.ru/)
-   Территория 1С (http://forums.kuban.ru/f1040/)
-   -   Какой запрос будет требовать меньше ресурсов? (http://forums.kuban.ru/f1040/kakoj_zapros_budet_trebovat-_men-she_resursov-4382490.html)

bma1 20.06.2013 14:11

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

angro 20.06.2013 14:16

какой sql сервер, какая версия, собрана ли статистика, какие индексы, сколько оперативной памяти

:) не угадаешь

angro 20.06.2013 14:16

+1 что говорит план запроса во всех 3-х случаях? а если будет рлс?

bma1 20.06.2013 14:35

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

angro 20.06.2013 14:44

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

bma1 20.06.2013 14:51

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

bma1 20.06.2013 15:53

Хм... с другой стороны СОЕДИНЕНИЕ и подзапрос не рекомендованное сочетание, во всяком случае так было раньше, вот что-то не припомню, кажется в последних релизах писалось про оптимизацию этой ситуации в движке 1с или нет?

Billi 20.06.2013 17:48

Скуль - умный. Без хинтов ему по барабану, какой вариант из этих трёх ты ему предложишь.
Он всё равно, в зависимости от ситуации, придумает свой собственный.
Так что не парься, оставляй какой тебе больше нравится. :)

bma1 20.06.2013 18:22

я пока склоняюсь ко второму варианту...

Reaper 20.06.2013 20:16

На текущем этапе своего развития я нахожу наиболее гармоничным и сбалансированным второй вариант.

denacid 20.06.2013 21:29

Вот смотрю на запрос 1 и 2 и почему то мне кажется что у них будет разный результат

denacid 20.06.2013 21:46

не обратил внимание на пару верхних сообщений, сорри

Morrison 21.06.2013 00:00

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

Morrison 21.06.2013 00:03

+(12) Что касается запросов - не занимайтесь фигней пишите через точку, толку от того, что выполнение запроса выиграло пару секунд, который нужен раз в пятилетку. Вот, когда предполагается запись данных, тогда да, стоит с этим разбираться и оптимизировать всеми возможными средствами.

Morrison 21.06.2013 00:05

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

bma1 21.06.2013 07:33

2(14) Это все верно, только это не повод писать запросы абы как. Здесь как раз операция чтения критична, так как это будет rls на журнал. Лишняя пара даже не миллисекунд а целых секунд при записи не будет заметна на фоне кучи интерактивных проверок типа "а такой реквизит не забыли заполнить?".
P.S. вот... почти намертво завесил 1с-ку запросом с конструкцией
ПО (ВЫБОР КОГДА таблица1.Реквизит = ЗНАЧЕНИЕ(Справочник.Некий.ПустаяСсылка) ТОГДА ИСТИНА ИНАЧЕ
таблица1.Реквизит = таблица2.Реквизит КОНЕЦ)
Вариант с
ПО (таблица1.Реквизит = ЗНАЧЕНИЕ(Справочник.Некий.ПустаяСсылка) ИЛИ
таблица1.Реквизит = таблица2.Реквизит)
работает значительно быстрее.

Jimbo 21.06.2013 09:15

поиграться на своем компе всегда полезно!
1) ВАРИАНТ теоретически - мимо, слабоват. На больших объемах просядет.
2 или 3 - надо засекать на конкретных примерах.
Предложу 4 - пакетный запрос.
4) Выборка по временную таблицу - подзапрос
Ну и соединение по ссылке

bma1 21.06.2013 09:54

2(16) в обычном случае пакетный подошел бы идеально, но тут запрос для rls, там особо не побалуешься...

P.S. хотя непонятно, почему в (15) такая разница во времени исполнения... вроде смысл в обоих условиях одинаков - сперва сравнить с пустым значением и дальше получив ИСТИНА не проверять следующее условие...

Jimbo 21.06.2013 10:38

ветвление всегда более сложная операция чем логические

Lexusss 21.06.2013 14:40

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

Lexusss 21.06.2013 14:43

(15) Конструкция ВЫБОР никогда не учитывается при построении плана выполнения запроса, а накладывается сверху. В отличии от этого, условие по ИЛИ очень даже понятно SQL при определении порядка выборки.
Мы напоролись на такую тему при разборках с 1С по поводу тормозов динамического списка управляемых форм. В каждом релизе обещают исправить, но по данным последней переписки опять отодвинули на 8.3.4 :-( Задолбали

bma1 21.06.2013 15:52

2(19) в окончательном варианте запрос будет переписываться на внутреннее соединение, которое несколько эффективнее конструкции В(ВЫБРАТЬ...) по скорости. А сейчас это тестовые варианты.

Lexusss 21.06.2013 16:32

(21) В большинстве случаев, внутреннее соединение и В(ВЫБРАТЬ) приводят к полностью идентичному плану выполнения. Мои разработчики приводили некоторые примеры, где действительно соединение оказывается получше. Но это было гораздо более сложные запросы, нежели в этом случае.
На время теста, до передачи в производство, именно в RLS, все таки я бы рекомендовал именно В(ВЫБРАТЬ...) как основной подход к написанию запроса. Так мы показываем, какие именно критерии накладываем на каждую строку. А на этапе отладки можно каждый из таких критериев отдельно проверять, просто комментируя ветку "ИЛИ..."

Пудель 23.06.2013 15:18

ИМХО, зависит от статистики:
Что больше ограничивает выборку по второй таблице - "Поле" или "СсылкаНаСсылку"?

bma1 24.06.2013 16:27

Так, что выяснилось из сбора информации по разным форумам (1С, MSSQL, MySQL) и чтения MSDNов.
1. Конструкция
"ВНУТРЕННЕЕ СОЕДИНЕНИЕ
ПО таблица1.Реквизит1 = таблица2.Реквизит1
И таблица1.Реквизит2 = &НекоеЗначение"
выполняется всегда не медленнее чем конструкция
"ВНУТРЕННЕЕ СОЕДИНЕНИЕ
ПО таблица1.Реквизит1 = таблица2.Реквизит1
ГДЕ таблица1.Реквизит2 = &НекоеЗначение"
и иногда быстрее.
2. конструкция
"ВНУТРЕННЕЕ СОЕДИНЕНИЕ
ПО таблица1.Реквизит2 = &НекоеЗначение
И таблица1.Реквизит1 = таблица2.Реквизит1"
выполняется всегда не медленне чем конструкция
"ВНУТРЕННЕЕ СОЕДИНЕНИЕ
ПО таблица1.Реквизит1 = таблица2.Реквизит1
И таблица1.Реквизит2 = &НекоеЗначение"
и иногда быстрее.
Причины не всегда понятны, что-то больно мудрят оптимизаторы планов запросов.

bma1 25.06.2013 11:05

Проверил два варианта:
1-ый вариант:
ВЫБРАТЬ
Т.Ссылка
ИЗ
Документ.НекийДокумент КАК Т
ГДЕ
ИСТИНА В
(ВЫБРАТЬ ПЕРВЫЕ 1
ИСТИНА
ИЗ
РегистрСведений.НекийРегистр КАК Д
ГДЕ
Д1.РеквизитЗн = &Значение
И Д1.Реквизит = Т.Реквизит1)

2-ой вариант:
ВЫБРАТЬ
Т.Ссылка
ИЗ
Документ.НекийДокумент КАК Т
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
РегистрСведений.НекийРегистр КАК Д
ПО Д.РеквизитЗн = &Значение
И Д1.Реквизит = Т.Реквизит1

оказалось, что второй вариант действительно кушает меньше ресурсов. Он сперва делает отбор по первому условию, а потом внутреннее соединение по второму.

А первый, для каждой строки таблицы с документами делает проверку в цикле по сформированным вложенным запросам с отбором по условиям.
А при росте количества реквизитов, по которым происходит проверка - преимущество второго варианта только растет.
Разница выходит в пределах 10% при пяти проверяемых реквизитах.

bma1 25.06.2013 11:08

[quote=bma1;31017972]Он сперва делает отбор по первому условию, а потом внутреннее соединение по второму.[/quote]
В смысле. Он сперва из регистра делает отбор по первому условию в ПО, а потом результат соединяет с таблицей документа про условию во второй строке условия ПО.

bma1 26.06.2013 08:33

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

ОБЪЕДИНИТЬ
ВЫБРАТЬ
Д.Реквизит
ИЗ
РегистрСведений.НекийРегистр КАК Д)
КАК Д
ПО Т.Реквизит = Д.Реквизит
Второй вариант быстрее от 10 до 100 раз.
Я в задумчивости...

Billi 26.06.2013 09:47

27-bma1 >Даже и не задумывайся, можно сказать - баян :)
[url]http://forums.kuban.ru/f1040/ut10_3_u_kogo_problemy_so_skorost-yu_spisaniya_partij_hod-_syudy-2892325.html[/url]

bma1 26.06.2013 10:19

2(28) Не, задуматься стоит. Т.к.
1. у тебя объединение пустой ссылки икороткого справочника "Склады", а я делал объединение пустой строки и длинного справочника "Контрагенты"
2. конструкция с ВНУТРЕННЕЕ СОЕДИНЕНИЕ, как показал план запросов в SQL, меньше занимает времени чем конструкция с В()

Billi 26.06.2013 11:51

29-bma1 >1. Тут важно не то с чем объединяем, а наличие - отсутствие ИЛИ.
2. Как я уже писал ранее, скуль умный, и зачастую оптимизатор подменяет WHERE VAL IN (SELECT ... ) на INNER JOIN, особенно когда есть возможность соединить по индексу. Так что зачастую В() и ВНУТРЕННЕЕ СОЕДИНЕНИЕ равнозначны.


Текущее время: 19:03. Часовой пояс GMT +3.