Имя: Пароль:
1C
1С v8
Оператор "ИЛИ", конструкция "ВЫБОР" и вероятность фуллскана при них
0 Drac0
 
23.05.13
11:04
Добрый день!

Насколько известно, например из статьи http://kb.1c.ru/articleView.jsp?id=44#or , наличие логического оператора "ИЛИ" в "ГДЕ" и в условии соединения может приводить к фуллскану.

Но вот есть пара вопросов:
   1. можно ли где-нибудь найти дополнительные критерии, возникновения этого;
   2. помогает ли замена ИЛИ на конструкцию ВЫБОР избежать этого? Например, конструкцию вида "Поле1 = 1 ИЛИ Поле1 = 2" заменить на "ВЫБОР КОГДА Поле1 = 1 ТОГДА ИСТИНА КОГДА Поле1 = 2 ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ"
1 Ненавижу 1С
 
гуру
23.05.13
11:07
1. почему может, а не всегда приводит?
2. не помогает
2 Ёпрст
 
23.05.13
11:07
case еще более усугубит ситуацию
3 Ненавижу 1С
 
гуру
23.05.13
11:08
помогает "объединить все"
4 Drac0
 
23.05.13
11:13
(1) Таки всегда? Или бывают ситуации, когда это безобидно.

(3) Но не в ДС :(
5 Ненавижу 1С
 
гуру
23.05.13
11:17
(4) что есть ДС?
6 1Сергей
 
23.05.13
11:18
(5) демонический список
7 Ненавижу 1С
 
гуру
23.05.13
11:18
(6) тогда накуй он нужен такой ))
8 Drac0
 
23.05.13
11:19
(7) Да, не, штука хорошая, но вот все эти ограничения делают ее слишком уж узкоспециализированной.
9 Drac0
 
23.05.13
15:29
Интересно, а в случае опционального фильтра тоже "ИЛИ" провоцирует фуллскан?

Например,
ГДЕ
  &БезФильтра ИЛИ Таб.Поле1 = &ЗначениеФильтра

?
10 Wern
 
23.05.13
15:37
На самом деле там не все так очевидно, мс скул, умный, он может и сам разрулить "или" если будет возможность, пробовал, зачастую оптимизатор строит нормальный план. Но вот гарантировать этого нельзя.
11 viktor_vv
 
23.05.13
15:44
Если "или" по одному полю, то не так уж все печально.
Если поле попало в индекс, то как правило Index Seek ... Where.
12 Drac0
 
23.05.13
15:44
(10) Как я понимаю, вероятность выше в простых случаях?

Сейчас в Динамическом списке заменил ИЛИ в условие соединения на подзапрос с объединением (что тоже не особо радует) и получил прирост в скорости в 2-3 раза.
13 Drac0
 
23.05.13
15:46
(11) В (12) был случай как раз с одним полем:

ПО Таб.Поле1 = &Парам1 ИЛИ Таб.Поле1 = &Парам2
14 H A D G E H O G s
 
23.05.13
15:47
Не верьте всему, что пишут на заборе всякие Ненавижу.

Если будет 2 индексированных поля и по ним будет ИЛИ - будет 2 IndexScan
15 H A D G E H O G s
 
23.05.13
15:48
(9) Будет IndexScan, все норм.
16 ИсчадиеADO
 
23.05.13
15:48
работа оптимизатора запроса зависит от версии мс скуля? (ну там обычный или энтерпрайз)?
17 H A D G E H O G s
 
23.05.13
15:49
Блин, пардон,
IndexScan читать как IndexSeek
18 H A D G E H O G s
 
23.05.13
15:49
(16) Нет.
19 Пират
 
23.05.13
15:50
(16) работа оптимизатора запроса зависит от версии сервера 1С
20 viktor_vv
 
23.05.13
15:51
(14) По двум полям-то скорее всего, а вот по одному полю скорее всего index seek.
(13) В условиях соединения не проверял, смотрел план для where.
21 H A D G E H O G s
 
23.05.13
15:51
К примеру

ВЫБРАТЬ
   Номенклатура.код
ИЗ
   Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.код = &код или
    Номенклатура.Артикул = &Артикул

вызовет 2 IndexSeek по индексам с Кодом и Артикулом, потом MergeJoin, а, затем, как ни прискорбно, KeyLookup, ну а что поделать. Но KeyLookup - это мелочи.
22 Ненавижу 1С
 
гуру
23.05.13
15:51
(14) хз конечно, но когда я писал про
А=Б ИЛИ (А ЕСТЬ NULL И Б ЕСТЬ NULL)
мне сказали, что индексам хана
23 H A D G E H O G s
 
23.05.13
15:52
(20) IndexSeek везде, я опечатался.
24 ИсчадиеADO
 
23.05.13
15:53
(19) не, я именно скуль имел ввиду. Слышал, что скорость коррелированных подзапросов как раз зависит от версии
25 viktor_vv
 
23.05.13
15:54
(23) Если для этих полей есть отдельные индексы, то да.
26 H A D G E H O G s
 
23.05.13
15:54
(21) А вот если 2 поля, и одно - неиндексное - тогда table(clasteredIndex)Scan, без вариантов. Ибо проще один раз табличку посмотреть, чем сначало в индексе шариться, а потом опять таки табличку смотреть.
27 H A D G E H O G s
 
23.05.13
15:55
(25) А если - один?
28 Drac0
 
23.05.13
15:57
(21) В этом варианте в ИЛИ разные поля, а если будет:

ВЫБРАТЬ
   Номенклатура.код
ИЗ
   Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Артикул = &Артикул_1 или
    Номенклатура.Артикул = &Артикул_2

В этом случае как будет?
29 H A D G E H O G s
 
23.05.13
15:58
(28) IndexSeek + LookUp

Норм.
30 acsent
 
23.05.13
15:59
ИЛИ по идексироему полю нормально отрабатывает
31 H A D G E H O G s
 
23.05.13
15:59
(30) см (26)
32 acsent
 
23.05.13
16:00
(31) по неидексируемым полям ваще без разницы как отбор накладывать.
Хуже уже не будет )))
33 viktor_vv
 
23.05.13
16:02
(27) А если один индекс в котором оба поля, то одно из полей по или точно не попадет в индекс.
34 Drac0
 
23.05.13
16:04
(29) Тогда почему такие рекомендации в  http://kb.1c.ru/articleView.jsp?id=44#or ? Излишняя осторожность?
35 H A D G E H O G s
 
23.05.13
16:04
(33) Да, IndexScan.
Это печально.
36 H A D G E H O G s
 
23.05.13
16:05
(34) Access Denied
37 H A D G E H O G s
 
23.05.13
16:08
(32) Ну почему же.
Есть же
И
38 H A D G E H O G s
 
23.05.13
16:08
ВЫБРАТЬ
   Номенклатура.Наименование
ИЗ
   Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.код = &код и
    Номенклатура.Весовой = Истина


IndexSeek+KeyLookup

Отлично все.
39 acsent
 
23.05.13
16:08
(37) отбор по неиндексируемым полям - это всегда тайбл скан
40 acsent
 
23.05.13
16:09
(38) код - индексируемое поле
41 H A D G E H O G s
 
23.05.13
16:09
(40) Я об этом раньше сказал.
42 H A D G E H O G s
 
23.05.13
16:12
Короче, речь о том, что
Индексное и Неиндескное поле
IndexSeek+Lookup при И
TableScan при ИЛИ

Оба Индексных
2 IndexSeek полюбому

Индексное поле и Константа
IndexSeek

Несколько условий на индексное поле
IndexSeek

Общий индекс на 2 поля:
IndexScan  (это я пока не осмыслил)
43 Drac0
 
23.05.13
16:14
(36) Цитирую сюда:

"Использование логического ИЛИ в условиях
Рекомендации
Использование логического ИЛИ в секции ГДЕ запроса
Не следует использовать ИЛИ в секции ГДЕ запроса. Это может привести к тому, что СУБД не сможет использовать индексы таблиц и будет выполнять сканирование, что увеличит время работы запроса и вероянтность возникновения блокировок. Вместо этого следует разбить один запрос на несколько и объединить результаты.

Например, запрос

 

ВЫБРАТЬ Товар.Наименование ИЗ Справочник.Товары КАК Товар ГДЕ Артикул = "001" ИЛИ Артикул = "002"
 

следует заменить на запрос

 

ВЫБРАТЬ Товар.Наименование ИЗ Справочник.Товары КАК Товар ГДЕ Артикул = "001"
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ Товар.Наименование ИЗ Справочник.Товары КАК Товар ГДЕ Артикул = "002"

Использование ИЛИ в условиях соединения
Не рекомендуется использовать логическое ИЛИ в условиях соединения, то есть в секции ПО запроса. Это так же может привести к выбору неоптимального плана и медленной работе запроса. Простого универсального способа переписать такой запрос без использования ИЛИ не существует. Следует проанализировать решаемую задачу и попытаться найти другой алгоритм ее решения.

"
44 viktor_vv
 
23.05.13
16:16
(42)
Общий индекс на 2 поля:
IndexScan  (это я пока не осмыслил)

Тут все просто. Вот структура индекса

"Поле1,Поле2" рассматривай "или" как два отдельных условия.
В первом случае условие по Поле1 попадет в индекс, так как это поле первое в индексе.
А вот отдельное условие по Поле2 не попадет, так как оно второе, а для поля1 значения нет.
45 acsent
 
23.05.13
16:17
(43) для мс скл -  пох
46 viktor_vv
 
23.05.13
16:18
(43) Тут ключева фраза "Это может привести к тому, что СУБД не сможет использовать индексы таблиц". Слово "может привести", а может и не привести.
47 Drac0
 
23.05.13
16:21
(46) Вот именно этот момент и озадачил при прочтении :)
48 H A D G E H O G s
 
23.05.13
16:22
(44) Тоесть, СоставнойИндекс по 2-м полям нужен только для оператора
И
?
49 acsent
 
23.05.13
16:24
(48) конечно
50 H A D G E H O G s
 
23.05.13
16:25
(49) Зато... Зато...
Зато я на велике быстрее гоняю!
51 Drac0
 
23.05.13
16:31
Хм ... любопытно все это :) Надо, в  общем, добраться уже до скуля и смотреть, что там из 1Сных вопросов получается в конкретном случае, а не избегать ИЛИ как огня ...
52 Пират
 
23.05.13
16:32
(46) > Это может привести к тому, что СУБД не сможет использовать индексы таблиц

Какие ваши доказательства?
53 Пират
 
23.05.13
16:32
+(52) > Это может привести к тому, что СУБД ...

А может и не привести?
54 acsent
 
23.05.13
16:33
(53) 1с не предоставляет доказательств
55 Пират
 
23.05.13
16:34
(54) мне очень нравится сочетание "это может привести к тому..."

Жизнеутверждающе. Пойдешь в лес - волк может сожрать, а может и не сожрать :)
56 Drac0
 
23.05.13
16:36
(54) Дык ,получается, неопределнность возникает на уровне 1С или SQL? Или на данный момент никакой неопределнности нет уже на 100%.
57 H A D G E H O G s
 
23.05.13
16:37
(56) Все определено.
58 viktor_vv
 
23.05.13
16:38
(52) Я просто привел цитату из рекомендации (43) , это не мое утверждение. А то что может привести или не привести, это выше обсуждалось.
59 Пират
 
23.05.13
16:39
> что увеличит время работы запроса и вероянтность возникновения блокировок.

С каких пор грязное чтение вызывает блокировку?
60 viktor_vv
 
23.05.13
16:40
(56) На сторное SQL, так как план запроса, то есть как получить данные, описанные в запросе решает планировщик скуля, причем на основании достаточно большого количества факторов.
61 ptiz
 
23.05.13
16:41
Пути SQL часто неисповедимы.

Долго ломал голову, но так и не победил простейший запрос:
ВЫБРАТЬ ...
ИЗ
   РегистрСведений.ЦеныНоменклатурыПоКлиентам КАК ЦеныНоменклатурыПоКлиентам
ГДЕ
   Период <= &Дата
   И ДатаОкончания >= &Дата
   И Контрагент = &Контрагент
И Активность

Строчка "И Активность " - приводит к тормозам, но не всегда, зависит это от погоды на Луне и вспышек на Солнце.
Ну и от обновления статистики тоже зависит :) Как обновишь, так появляются тормоза, переставляешь условия местами - всё работает быстро до следующего обновления статистики.

Выкинул это условие в итоге от греха подальше.
62 Пират
 
23.05.13
16:43
(61) работай со срезом, строчка "И Активность" не понадобится
63 viktor_vv
 
23.05.13
16:44
(55) Именно так. Причем сам запрос может не меняться, но от входных параметров может меняться план запроса, и скуль уходит в даун.
64 H A D G E H O G s
 
23.05.13
16:45
(63) Отличная отмазка.
65 Drac0
 
23.05.13
16:48
(64) Т.е. вы на 100% уверены в правильности своего мнения?

Хм, надо бы помоделировать разные ситуации.
66 Пират
 
23.05.13
16:49
(65) это может привести к тому, что клавиатура поломается
67 viktor_vv
 
23.05.13
16:50
(64) Если бы это не было правда. Сам нарывался. Правда на прямых запросах к семерке. Когда ставишь период отчета чуть больше, и скуль уходит в кросс джойн, хотя в самом запросе им и не пахнет.
Там правда слегка кривоватые соединения были, но факт есть.
Переписал с использованием временных таблиц, все стало стабильно предсказуемым.
68 H A D G E H O G s
 
23.05.13
16:51
(65) Нет.
Это я к тому, что в дофига случаев граждане товарищи отнекиваются от разбора полетов и звучит фраза:

"SQL выбрал неправильный план запроса, с кем не бывает".

Ладно там чьято левая база, но скорее всего даже в своей базе не будут ковырять.
69 Пират
 
23.05.13
16:51
(67) может просто кривой запрос был?
70 H A D G E H O G s
 
модератор
23.05.13
16:52
(66) Это может привести к тому, что Пират покинет эту ветку по причине флуда и отсутствия фраз по делу.
71 viktor_vv
 
23.05.13
16:56
(68) Ну это да, железная отмазка :). Но при желании все можно разрулить :).
72 Drac0
 
23.05.13
16:59
(68) Ну, тут уже стоит трезво оценивать затраты на копание. Иначе можно все сроки завалить копаясь в интересной, но далеко не глобальной проблеме.
73 ptiz
 
23.05.13
17:02
(62) Там такой размер регистра, что от среза как раз пришлось отказаться :)
74 H A D G E H O G s
 
23.05.13
17:02
(72) 95% случаев тормозов в моей практике - это ошибки в 1С коде (ДокументВыборка, Обращение через точку (в цикле), Ссылка.Ссылка в Запросе) Это находится на 1-2-3 ЗамеромПроизводительности.
75 Drac0
 
23.05.13
17:06
(74) В 1С-ном коде это действительно все просто отыскивается. А вот отладка запроса задача, согласитесь, нетривиальная. Оценить код самого запроса на стороне 1С порой недостаточно.
76 viktor_vv
 
23.05.13
17:10
(69) Я и не спорю что кривой. Но факт остается. Абсолютно один и тот же запрос при разных параметрах выполнялся на склуе по разному, именно план запроса строился другой.
77 H A D G E H O G s
 
24.05.13
13:44
Вернемся к старым песням....

Вот у меня есть условие мощное, которое по идее должно сводиться к ClusteredIndexSeek и KeyLookup на большую таблицу, а оно сводиться к кривому плану запроса, в котором тока ClusteredIndexSeek с Warning-ом
"Columns with no statistics"

Вот така фигня, малята.
78 H A D G E H O G s
 
24.05.13
13:44
Вот запрос:

ВЫБРАТЬ
   Движения.СерияНоменклатуры,
   Движения.Номенклатура,
   Движения.Количество
ПОМЕСТИТЬ ДвиженияОбщие
ИЗ
   РегистрНакопления.ТоварыОрганизаций КАК Движения
ГДЕ
   Движения.Период МЕЖДУ &НачалоПериода И &КонецПериода
   И Движения.Организация = &Организация
   И Движения.Активность = ИСТИНА
   И (Движения.Номенклатура, Движения.СерияНоменклатуры) В
           (ВЫБРАТЬ
               НоменклатураИСерия.Номенклатура,
               НоменклатураИСерия.СерияНоменклатуры
           ИЗ
               НоменклатураИСерия КАК НоменклатураИСерия)
79 H A D G E H O G s
 
24.05.13
13:46
Когда я оставляю только

ГДЕ
   Движения.Период МЕЖДУ &НачалоПериода И &КонецПериода
   И Движения.Организация = &Организация
   И Движения.Активность = ИСТИНА

тогда - норм, ClusteredIndexSeek
80 H A D G E H O G s
 
24.05.13
13:47
Вот это я понимаю, SQL построил кривой план запроса, с пояснениями, так сказать :-)
81 H A D G E H O G s
 
24.05.13
13:51
(77) Ненене, KeyLookup не должно быть, это же Clustered!

Понапридумывали технологий, блин.

Warning
"Columns with no statistics" - насколько серьезно?
82 viktor_vv
 
24.05.13
13:51
А НоменклатураИСерия это что за таблица ?
83 viktor_vv
 
24.05.13
13:53
Columns with no statistics это нету статистики, а потому скль в ступоре как делать, ну и делает слегка пальцем в небо.
84 H A D G E H O G s
 
24.05.13
13:53
(82) Временная таблица, предварительно отобранная.
85 viktor_vv
 
24.05.13
13:55
Может тогда есть смысл проиндексировать ее и внутренним соединением заменить

И (Движения.Номенклатура, Движения.СерияНоменклатуры) В
           (ВЫБРАТЬ
               НоменклатураИСерия.Номенклатура,
               НоменклатураИСерия.СерияНоменклатуры
           ИЗ
               НоменклатураИСерия КАК НоменклатураИСерия)
86 H A D G E H O G s
 
24.05.13
13:55
(83) Обновлял статистику по табличке с Fullscan тока что - бесполезно.
Там уже есть созданная статистика для тех же колонок, что в кластерном индексе.
87 H A D G E H O G s
 
24.05.13
13:55
(85) Счаст попробую.
88 viktor_vv
 
24.05.13
13:57
(85)+ А то это у тебя опять "или" по разным поля, еще и "В". Если еще и НоменклатураИСерия с приличным количеством элементов, то не айс.
89 H A D G E H O G s
 
24.05.13
13:58
(88) Нет у меня там ИЛИ
90 H A D G E H O G s
 
24.05.13
13:59
(88) ВнутреннееСоединение помогло.
91 H A D G E H O G s
 
24.05.13
13:59
(90) Без индексации ВТ
92 H A D G E H O G s
 
24.05.13
13:59
Я в шоке.
93 viktor_vv
 
24.05.13
14:00
Хотя насчет "или" это я может и погрячился. Не свосем догоняю как это "В" выполнится на скуле.
94 H A D G E H O G s
 
24.05.13
14:00
Вот он пример неопределенности Гейзенберга... :-)
95 viktor_vv
 
24.05.13
14:02
(92) Ну а че "В" в ГДЕ вполне себе можно представить как перебор с условием в цикле, образно говоря.
96 H A D G E H O G s
 
24.05.13
14:03
(95) И? Причем тут тогда этот Warning ?
97 viktor_vv
 
24.05.13
14:08
(96) Это у скуля надо спросить :). А в "Или" вполне могло развернуться вот это

(Движения.Номенклатура, Движения.СерияНоменклатуры) В

Надо почитать есть ли у скуля подобный синтаксис, или это одинэсовская контрукция, которая потом некоторым образом транслируется.
98 viktor_vv
 
24.05.13
14:09
(97) Если есть возможность глянь скулевый запрос, получившийся с
(Движения.Номенклатура, Движения.СерияНоменклатуры) В
99 H A D G E H O G s
 
24.05.13
14:12
(98) вот это условие в sql

AND EXISTS(SELECT
1
FROM #tt2 T2 WITH(NOLOCK)
WHERE (T1._Fld18873RRef = T2._Q_001_F_000RRef) AND (T1._Fld18875RRef = T2._Q_001_F_001RRef))
100 H A D G E H O G s
 
24.05.13
14:14
как выразился Fragster , это "связанный подзапрос" (вроде так), но он не может подойти к аппарату, он на Нимфостарте...

Походу SQL не может его переварить нормально.
101 H A D G E H O G s
 
24.05.13
14:15
А сервак у нас на 8.2.17, а 1С вроде обещала в 8.2.18 что то исправить в операторе
В
102 viktor_vv
 
24.05.13
14:19
(99) А, коррелированный подзапрос, или связанный. Ну таки да, тормознутый он. Как раз к нему и подходит сравнение с запросом в цикле.
103 viktor_vv
 
24.05.13
14:28
А попробуй еще разбить, ради эксперимента,

И (Движения.Номенклатура, Движения.СерияНоменклатуры) В
           (ВЫБРАТЬ
               НоменклатураИСерия.Номенклатура,
               НоменклатураИСерия.СерияНоменклатуры
           ИЗ
               НоменклатураИСерия КАК НоменклатураИСерия)

на

И (Движения.Номенклатура В
           (ВЫБРАТЬ
               НоменклатураИСерия.Номенклатура
           ИЗ
               НоменклатураИСерия КАК НоменклатураИСерия))
И ( Движения.СерияНоменклатуры В
           (ВЫБРАТЬ
               НоменклатураИСерия.СерияНоменклатуры
           ИЗ
               НоменклатураИСерия КАК НоменклатураИСерия))

и посмотри как он его в скуль переварит.
104 H A D G E H O G s
 
24.05.13
14:41
(103) переварил норм.

AND T1._Fld18873RRef IN
(SELECT
T2._Q_001_F_000RRef AS Q_002_F_000RRef
FROM #tt4 T2 WITH(NOLOCK)) AND T1._Fld18875RRef IN
(SELECT
T3._Q_001_F_001RRef AS Q_003_F_000RRef
FROM #tt4 T3 WITH(NOLOCK))

Но warning остался.
105 viktor_vv
 
24.05.13
14:52
А по скорости как ? А warning это наверное к временной таблице, по ней наверное статистику не строит.
106 H A D G E H O G s
 
24.05.13
14:58
(105) Ненене, статистики нет по регистратору в кластерном индексе.
107 H A D G E H O G s
 
24.05.13
14:58
По времени - никак, не перезапущу я счаст боевой SQL
108 viktor_vv
 
24.05.13
15:12
(107) Понятно, спасибо.