|
Индексы в запросах. | ☑ | ||
---|---|---|---|---|
0
Lionelho
19.12.13
✎
14:21
|
Здравствуйте. Подскажите пожалуйста. Есть левое соединение 2-х временных таблиц. Левая таблица индексируется по связующему полю. Имеет ли смысл индексировать ещё правую таблицу по тому же полю? Ускорит ли это запрос? Количество строк в таблицах в расчет не берем.
|
|||
1
Defender aka LINN
19.12.13
✎
14:26
|
"Количество строк в таблицах в расчет не берем". Полагаешь, на таблице из одной строки и из 100500 индекс даст одинаковое изменение быстродействия?
|
|||
2
Lionelho
19.12.13
✎
14:30
|
Полагаю что разное. Представьте что в таблице 100 строк.
|
|||
3
Classic
19.12.13
✎
14:34
|
(0)
В чем смысл индексировать левую таблицу? Тогда уж лучше только правую А вообще для одного соединения индексить как-то некомильфо. |
|||
4
Fragster
гуру
19.12.13
✎
14:35
|
для 100 вообще можно ничего не индексировать
|
|||
5
Жан Пердежон
19.12.13
✎
14:38
|
(3) смысл: надеятся, что сервер бд сам догадается запустить цикл по правой таблице
|
|||
6
selenat
19.12.13
✎
14:39
|
(0) 1.попробую сказать такую глупость. Индексирование может играть роль в плане ускорения при большом объеме данных. Индексировать маленькие таблицы нет нужды вообще. 2. если есть желание оптимизировать запрос, то всегда можно заменить левое соединение объединениям запросов с группировкой. По скорости этот вариант работает куда быстрее левого соединения.
|
|||
7
Classic
19.12.13
✎
14:40
|
(5)
А что потом? Добирать из левой все неприсоединенные? Да и зачем в общем случае вообще цикл по правой делать? например одна таблица содержит только Номенклатура1 12 Номенклатура1 13 Номенклатура1 14 Номенклатура1 15 А правая - всю номенклатуру с ценами. Зачем правую всю обходить то? |
|||
8
H A D G E H O G s
19.12.13
✎
14:43
|
Я бы повесил индекс на большую таблицу с высокой селективностью поля.
И посмотрел профайлер. |
|||
9
Жан Пердежон
19.12.13
✎
14:48
|
(7) а если наоборот? то очень даже имеет.
в общем случае - конечно нет, но статистика как раз не для общих случаев и ведется |
|||
10
H A D G E H O G s
19.12.13
✎
14:50
|
А вообще - я бы не стал вещать индекс.
Если у тебя ВТ большого размера - значит ты криво данные выбрал уже, в 87.9 % случаях. |
|||
11
Classic
19.12.13
✎
14:51
|
(9)
Что наоборот? Левая таблица с ценами, правая маленькая? Так в любом случае большую с ценами надо обойти полностью |
|||
12
Lionelho
19.12.13
✎
14:59
|
H A D G E H O G s, а можешь по подробней рассказать про кривую выборку ВТ.
|
|||
13
Fragster
гуру
19.12.13
✎
15:01
|
(10) а если я из биллинга ТЗ гружу для обработки и формирования доков в 1с?
|
|||
14
H A D G E H O G s
19.12.13
✎
15:03
|
(13) Для вас я оставил 12.1%
|
|||
15
selenat
19.12.13
✎
15:03
|
Идея заменить левое соединение объединением во внутреннем запросе и группировкой всеми было проигнорировано. Я в печали. Мне этот прием всегда помогал решать проблемы быстродействия запроса, которые возникают при левом соединении. Ну да ладно.
|
|||
16
H A D G E H O G s
19.12.13
✎
15:07
|
(15) Идея внутреннного запроса - это че такое? Вложенный штоле?
|
|||
17
selenat
19.12.13
✎
15:08
|
(16) да. Объединение во вложенном и группировка результата этого самого вложенного.
|
|||
18
H A D G E H O G s
19.12.13
✎
15:14
|
(17) Бррр.
|
|||
19
selenat
19.12.13
✎
15:17
|
(18) ну, чуть сложнее в написании конечно, но по скорости - небо и земля по сравнению с левым соединением. Если стоИт задача оптимизации запроса на больших таблицах, я бы не задумываясь шел именно по этому пути.
|
|||
20
H A D G E H O G s
19.12.13
✎
15:17
|
(19) Ты какие-то странные вещи походу оптимизировал.
|
|||
21
selenat
19.12.13
✎
15:39
|
(20) ничуть. По-моему это из разряда "новое - это хорошо забытое старое". Я давно не появлялся на мисте, но научился этому приему помнится именно здесь. И с тех пор он меня ни разу не подводил.
|
|||
22
Classic
19.12.13
✎
15:43
|
(21)
Где-то видел этот метод. Но мне помнится, что он совсем не универсальный. Максимальная размерность результата при соединении M*N, при объединении M + N, где M и N - размер таблиц |
|||
23
selenat
19.12.13
✎
15:46
|
(22) ну речь ведь именно о больших таблицах. На малых особой разницы не будет видно, оба запроса будут отрабатывать достаточно быстро для того, чтобы не заморачиваться и писать такой текст запроса, который удобнее программисту. А программисту конечно удобнее написать левое соединение.И вопрос об индексах на малых таблицах не стоИт.
|
|||
24
Classic
19.12.13
✎
15:49
|
(23)
Да я не про скорость и изящество. Просто не понимаю, как объединением получить результат идентичный соединению. В примеру ВЫБРАТЬ 1 КАК Поле ПОМЕСТИТЬ ТЗ1 ОБЪЕДИНИТЬ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВЫБРАТЬ 4 ОБЪЕДИНИТЬ ВЫБРАТЬ 4 ; ВЫБРАТЬ 1 КАК Поле ПОМЕСТИТЬ ТЗ2 ОБЪЕДИНИТЬ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВЫБРАТЬ 4 ОБЪЕДИНИТЬ ВЫБРАТЬ 4 ; ВЫБРАТЬ ТЗ1.Поле, ТЗ2.Поле ИЗ ТЗ1 КАК ТЗ1 ЛЕВОЕ СОЕДИНЕНИЕ ТЗ2 КАК ТЗ2 ПО Истина Вот как ты "объединением с группировкой" получишь идентичный результат? |
|||
25
selenat
19.12.13
✎
15:50
|
(22) ты сейчас под результатом что понимаешь? Если готовую таблицу, то запрос составляется так, что она одинакова в обоих случаях.
|
|||
26
Classic
19.12.13
✎
15:51
|
(25)
Так покажи, как в примере (24) заменить левое соединение объединением |
|||
27
toypaul
гуру
19.12.13
✎
15:52
|
(0) в левом соединении лучше индексировать правую таблицу. левую необязательно
|
|||
28
DVN
19.12.13
✎
15:56
|
(25)Пример в студию.. а то я здесь таблицы по 100-300к строк в запросе левым соединением соединяю.. хочу потестить производительность
|
|||
29
selenat
19.12.13
✎
16:25
|
Пардон, отлучался на поесть.
(26) ты прав, в общем случае это наверное не всегда возможно. Поэтому откорректирую свою позицию. Во всех случаях, которые мне встречались на практике, когда меня не удовлетворяла скорость запроса с левым соединением, мне удавалось найти вариант с объединением и группировкой, который давал тот же самый результат и работал в десятки раз быстрее. |
|||
30
selenat
19.12.13
✎
17:27
|
Тем не менее, выложу самый элементарный пример, чтобы было понятно что вообще имеется в виду для тех, кто не знаком с этим приемом.
Вариант 1: ВЫБРАТЬ РеализацияТоваровУслугТовары.Номенклатура, РеализацияТоваровУслугТовары.Количество, ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КАК Остаток ИЗ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&СписокНоменклатуры)) КАК ТоварыНаСкладахОстатки ПО РеализацияТоваровУслугТовары.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура ГДЕ РеализацияТоваровУслугТовары.Ссылка = &Ссылка Вариант 2: ВЫБРАТЬ ВложенныйЗапрос.Номенклатура, СУММА(ВложенныйЗапрос.Количество) КАК Количество, СУММА(ВложенныйЗапрос.Остаток) КАК Остаток ИЗ (ВЫБРАТЬ РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура, РеализацияТоваровУслугТовары.Количество КАК Количество, 0 КАК Остаток ИЗ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ТоварыНаСкладахОстатки.Номенклатура, 0, ТоварыНаСкладахОстатки.КоличествоОстаток ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&СписокНоменклатуры)) КАК ТоварыНаСкладахОстатки) КАК ВложенныйЗапрос СГРУППИРОВАТЬ ПО ВложенныйЗапрос.Номенклатура Что-то в это роде. Я отдаю себе отчет в том, что запросы написаны небрежно, в частности что разные строки в документе реализация могут содержать одинаковую номенклатуру и надо бы для начала ее сгруппировать, но аккуратно написанный запрос будет бОльшего размера и сложнее восприниматься. Думаю, принцип понятен. Иногда в более сложных случаях приходится вводить в объединяемые запросы дополнительные служебные поля а потом при группировке результата фильтровать при помощи конструкции ИМЕЮЩИЕ. Обычно такие служебные поля делаются либо числовыми (тогда при группировке берется СУММА()), либо булевскими (при группировке используется МАКСИМУМ() или МИНИМУМ()). В общем, если у кого-то есть проблемы со скоростью выполнения запроса с левым соединением, попробуйте построить для него аналог по такому принципу. Возможно результат вас приятно удивит своей скоростью. |
|||
31
selenat
19.12.13
✎
17:28
|
+30 во втором варианте конечно тоже должно быть еще
ГДЕ РеализацияТоваровУслугТовары.Ссылка = &Ссылка |
|||
32
H A D G E H O G s
19.12.13
✎
17:32
|
(30) Зачем тут Вложенный?
|
|||
33
selenat
19.12.13
✎
17:35
|
(32) не понял. Ты имеешь в виду зачем вообще второй вариант запроса, если можно использовать первый? Или ты хочешь предложить более простую версию второго варианта запроса?
|
|||
34
H A D G E H O G s
19.12.13
✎
17:41
|
(33) Все, понял зачем.
ЯБыСделалТак и даже не парился. ВЫБРАТЬ РеализацияТоваровУслугТовары.Номенклатура, РеализацияТоваровУслугТовары.Количество ПОМЕСТИТЬ Товары ИЗ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары ГДЕ РеализацияТоваровУслугТовары.Ссылка = &Ссылка И РеализацияТоваровУслугТовары.Номенклатура В(&СписокНоменклатур) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ТоварыНаСкладахОстатки.Номенклатура, ТоварыНаСкладахОстатки.КоличествоОстаток ПОМЕСТИТЬ Остатки ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&СписокНоменклатур)) КАК ТоварыНаСкладахОстатки ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Товары.Номенклатура, Товары.Количество, ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток ИЗ Товары КАК Товары ЛЕВОЕ СОЕДИНЕНИЕ Остатки КАК Остатки ПО Товары.Номенклатура = Остатки.Номенклатура |
|||
35
selenat
19.12.13
✎
17:44
|
(34) и в случае большого количества строк в документе реализации получил бы на порядок более медленный за счет левого соединения запрос, чем в варианте с объединением и группировкой. Потестируй.
|
|||
36
H A D G E H O G s
19.12.13
✎
17:53
|
(35) Мой будет более медленным, но не на порядки если твой вложенный так и остается, как есть, а не помещается еще куда-нибудь вглубь других вложенных.
Более медленным он будет только из за помещения данных во временные таблицы, но это все равно пару сотен миллисекунд. |
|||
37
selenat
19.12.13
✎
17:57
|
(36) ты протестировал или просто предполагаешь, что это так? Штука в том, что за прошедшие года я таким приемом оптимизировал немало запросов, естественно с многочисленными замерами производительности. Нередко бывало, что писал запрос с левым соединением, потому что так проще писать, а потом когда видел, что не удовлетворяет меня полученная скорость, переписывал все по образцу второго примера.
|
|||
38
selenat
19.12.13
✎
18:02
|
Не изучал теоретическую сторону этого вопроса, но могу предположить, что причина кроется в том, что написано в (22):
"Максимальная размерность результата при соединении M*N, при объединении M + N, где M и N - размер таблиц". Только речь не о размере результата (мы предполагаем, что результат нам удалось получить идентичным для обоиз вариантов запроса), а о количестве операций по выполнению запросов. |
|||
39
selenat
19.12.13
✎
18:02
|
Всем пока, завтра можем продолжить интересный разговор. :)
|
|||
40
Serginio1
19.12.13
✎
18:08
|
(34) Тогда во втором запросе лучше добавить индекс по Номенклатура
В варианте с 30 Запрос будет использовать либо Хэш таблицу либо индекс в зависимости от размера. И твой вариант может быть значительно медленнее |
|||
41
Serginio1
19.12.13
✎
18:34
|
(0) Есть алгоритм Джойнов который использует индексы.
Принцип его таков берем первые строки и сравниваем. Если они не равны то продвигаем наименьшую до тех пор пока не будет больше или равна. При равных двигаемся вперед по двум таблицам. По такому принципу работает сортровка слиянием wiki:%D1%EE%F0%F2%E8%F0%EE%E2%EA%E0_%F1%EB%E8%FF%ED%E8%E5%EC При этом нет бинарного поиска и объединение быстрее. Например сортировка QuickSort значительно быстрее чем вставками. Но и сортировка слиянием тоже хороша. |
|||
42
DVN
20.12.13
✎
07:54
|
(30) Спасибо, теперь понял о чем Вы говорили.. надо будет попробовать.. а то у меня есть запросик с промежуточными таблицами в >400к строк :)
|
|||
43
Sammo
20.12.13
✎
08:16
|
(30) У меня есть очень грустный опыт использования в () в качества параметра виртуальной таблицы.
В случае, когда данное условие накладывалось на измерение не первое/второе (3,4 или ниже), то иногда получалось быстрее это условие переместить в ГДЕ. Особенно это было видно на неселктивных измерениях и измерениях с составным типом. За пример спасибо, конечно. |
|||
44
selenat
20.12.13
✎
08:48
|
Надо пожалуй пояснить еще кое-что по поводу примера в 30. По поводу параметра &СписокНоменклатуры. Я как-то не сказал, что чтобы запрос в результате дал именно левое соединение, в этом списке должна быть вся та же номенклатура, которая идет в самом документе реализации. На практике я бы вообще не использовал внешний параметр, а сделал бы по типу (34). Т.е. засунул бы состав реализации во временную таблицу (причем еще и сгруппировал бы ее по номенклатуре, а то у меня в примере отсутствие этой группировки является ошибкой), а в параметре виртуальной таблицы остатков использовал именно эту временную таблицу, а не параметр. Но это уже частности. Интересен другой вопрос. В более общем случае бывает, что присоединяемая таблица имеет записи, которые не должны попасть в итоговый результат. Для нашего случая предположим, что в параметре &СписокНоменклатуры есть элементы, которых нет в документе реализации. В этом случае запрос пишется примерно так:
ВЫБРАТЬ ВложенныйЗапрос.Номенклатура, СУММА(ВложенныйЗапрос.Количество) КАК Количество, СУММА(ВложенныйЗапрос.Остаток) КАК Остаток, СУММА(ВложенныйЗапрос.СлужебноеПоле) КАК СлужебноеПоле ИЗ (ВЫБРАТЬ РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура, РеализацияТоваровУслугТовары.Количество КАК Количество, 0 КАК Остаток, 1 КАК СлужебноеПоле ИЗ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ТоварыНаСкладахОстатки.Номенклатура, 0, ТоварыНаСкладахОстатки.КоличествоОстаток, 0 ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&СписокНоменклатуры)) КАК ТоварыНаСкладахОстатки) КАК ВложенныйЗапрос СГРУППИРОВАТЬ ПО ВложенныйЗапрос.Номенклатура ИМЕЮЩИЕ СУММА(ВложенныйЗапрос.СлужебноеПоле) > 0 Ну или в качестве служебного поля можно использовать булев тип, а при группировке не СУММА(), а МАКСИМУМ(). |
|||
45
selenat
20.12.13
✎
08:51
|
(43) у меня с параметрами виртуальной таблицы всегда отрабатывало быстрее, особенно если как в моем примере регистр остатков проиндексирован по номенклатуре. Но вообще можно это проверять в каждом конкретном случае. Метод ведь позволяет использовать его и с конструкцией ГДЕ вместо параметра виртуальной таблицы.
|
|||
46
selenat
20.12.13
✎
09:08
|
Выигрыш в скорости у такого метода сильно зависит от размера соединяемых таблиц. На маленьких таблицах разницы практически нет, при том что синтаксис левого соединения все-таки удобнее. На больших таблицах выигрыш может быть многократный. Один раз у меня был случай, когда обработкой корректировались старые данные в базе, когда таблицы были реально огромные. Так вот левое соединение просто повесило базу, через пару часов я устал ждать и просто прибил сеанс. А после переписывания по этому методу запрос прекрасно себе отработал за несколько минут. Вот, как-то так...
|
|||
47
H A D G E H O G s
20.12.13
✎
11:57
|
Померил я 3 метода в профайлере.
План запросов - одинаковый. Единственное - с временными таблицами - медленней, потому что в них помещаются данные. Возьмите профайлер. |
|||
48
H A D G E H O G s
20.12.13
✎
12:04
|
1881 строк в документе, размер остаточной таблицы регистра - 3093.
|
|||
49
H A D G E H O G s
20.12.13
✎
12:05
|
(40) Нет. Никак нельзя добавлять регистр. Где вы видели РТУ больше 1000 строк?
|
|||
50
H A D G E H O G s
20.12.13
✎
12:05
|
(40) Нет. Никак нельзя добавлять индекс. Где вы видели РТУ больше 1000 строк?
|
|||
51
selenat
20.12.13
✎
12:17
|
(47) Странно это. Попробую проверить чуть позже по свободе на том примере, который я здесь приводил. Сейчас могу только сказать, что много раз решал таким способом проблемы и не склонен думать, что мне это все приснилось. :)
|
|||
52
selenat
20.12.13
✎
13:49
|
Еще не проверял, но пока ходил по делам появились мысли по этому поводу. Я так полагаю, что план запроса, который составляет 1С не всегда однозначно определяется только текстом запроса. Существуют дополнительные факторы, которые влияют на то, как 1С интерпретирует написанный нами запрос. В частности в нашем примере с левым соединением наверняка план запроса был бы другим, если бы поле номенклатуры было составным. Вполне вероятно, что существуют и другие факторы, которые влияют на это. И получается, что когда мы используем левое соединение, мы даем инструкции 1С в отношении того, какой результат хотим получить, но не контролируем оптимальность пути, которым 1С этого результата достигает. Нам может повезти и 1Ска выберет оптимальный путь, но может и не повезти. В варианте с объединением и группировкой мы даем инструкции не только относительно результирующей таблицы, но и относительно того, каким путем она должна быть получена. Т.е. мы даем 1Ске меньше произвола в отношении построения плана запроса. Правдоподобно звучит?
|
|||
53
H A D G E H O G s
20.12.13
✎
13:56
|
(52) Правдоподобно.
Поэтому, дабы совсем не было волностей у 1С - я все делаю через Временные таблицы, ибо фиг знает, как потом запрос переписать придется и куда ваш Вложенный запрос засунется. Но ваш метод - неплох. |
|||
54
selenat
20.12.13
✎
13:58
|
(48) кстати, не понятно как у тебя таблица остатков получилась больше таблицы остатков регистра. Я конечно понимаю, что у тебя там могут быть записи относящиеся к другим измерениям регистра, типа характеристики, серии и т.д. Но по логике примера в этом случае все это должно быть сгруппировано по номенклатуре. Т.е. количество строк в присоединяемой таблице обязано быть меньше или равно количеству различных элементов номенклатуры в документе.
|
|||
55
selenat
20.12.13
✎
13:59
|
(53) Насчет временных таблиц полностью солидарен. Я бы тоже на практике использовал их. Но это не противоречит тому, чтобы получив данные во временные таблицы, использовать их потом не в виде левого соединения, а в виде объединения и дальнейшей группировки.
|
|||
56
selenat
20.12.13
✎
14:00
|
В примере просто старался максимально упростить структуру запроса для наглядности идеи.
|
|||
57
H A D G E H O G s
20.12.13
✎
14:05
|
(54) Я имел ввиду всю таблицу остатков регистра, по всем измерениями.
|
|||
58
selenat
20.12.13
✎
14:06
|
(57) ок, не суть важно.
|
|||
59
H A D G E H O G s
20.12.13
✎
14:06
|
(55)
"Но это не противоречит тому, чтобы получив данные во временные таблицы, использовать их потом не в виде левого соединения, а в виде объединения и дальнейшей группировки." Вот это тоже годно! |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |