|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Всем привет! Сложилась интересная и непонятная пока для меня ситуаций. Есть таблица T1 ~7.5 млн строк/3.5 млн страниц (pagesize=2k). Есть индекс Index1: Код: sql 1.
leafcnt = 19029; indexheight = 2 есть выборка по типу: Код: sql 1. 2. 3. 4. 5. 6.
статистика по данным такая: Код: sql 1.
выдает ~400 000 записей. Код: sql 1.
выдает около 350 записей. Что ожидается: выборка должна проходить по индексу Index1 с позиционированием по ключу C1 + C2. Что дает оптимизатор: Код: sql 1. 2. 3. 4. 5. 6. 7.
При этом, если объем in для С1 скоратить до 6 значений, позиционирование по двум ключам: Код: sql 1. 2. 3. 4. 5. 6. 7.
статистика по индексу и таблице обновлена. Индекс перестраивались неоднократно. Посмотрел на стоимость - с чего-то резко возрастает Код: sql 1.
при добавлении 7-го значения... При 6 значениях selectivity = 0.003155239 , при 7 значениях в in selectivity = 0.01743903 и дальше в принципе не сильно варьируется вплоть до 18 значений. Вопрос - что могло привести к такому резкому скачку в оценке selectivity? ... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 11:35 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
после скачка оценки сервер заявил, что ему слишком дорогу два ключа поддержать (с чего - опять же не понимаю). Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 12:15 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, Покажите Код: sql 1.
и полные планы на обеих запросах(с 6 значениями и больше 6) ... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 12:38 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
cherrex_Den, сорри за портянки, но так нагляднее для запроса 6 rows of OR/IN values Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
для запроса 7 rows of OR/IN values Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33.
... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 13:02 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, Я так подозреваю, что когда оптимизатор видит мало значений в in, он выбирает стратегию nl join по обеим колонкам, если видит много значений то выбирает nl join по одной колонки, а по второй просто restrict. Вариант такой: сдернуть абстрактный план с запроса где 6 значений и подсунуть его запросу с 18 значениями, проверить IO с абстрактным планом и без него, если с планом меньше, то так и оставить! ... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 13:47 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Попробую конечно, но в продакшен такое не смогу включить (там довольно сложная схема построения запроса) и это только единичный пример выборки, а могут быть иные условия и явно должен быть другой план ... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 14:19 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
абстрактрный план с 6 значений имеет явное указание этих 6 значений. Может быть я что-то не так смотрю? ... |
|||
:
Нравится:
Не нравится:
|
|||
07.02.2014, 15:25 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, у тебя же при таком раскладе where (C1 in (v1,v2,v3,.....,vn)) AND (C2 in (v1,v2,v3,v4)) в результат пропадают все возможные сочетания значений с1 и с2, естественно, что их количество растет очень быстро, а вместе с ним и результирующая селективность. ... |
|||
:
Нравится:
Не нравится:
|
|||
08.02.2014, 06:26 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
извините, не так написал, селективность как раз падает, число записей по оценке растет... ... |
|||
:
Нравится:
Не нравится:
|
|||
08.02.2014, 06:29 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
MasterZivизвините, не так написал, селективность как раз падает, число записей по оценке растет... Так оно понятно, что селективность падает, но с какого сервер предпочитает делать скан по одному полю индекса, вместо использования обоих полей? В любом же случае "перебрать" индекс по двум ключам - оно быстрее, нежели выполнять полный скан всего индекса... Вот это для меня не совсем понятно... ... |
|||
:
Нравится:
Не нравится:
|
|||
09.02.2014, 00:11 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83MasterZivизвините, не так написал, селективность как раз падает, число записей по оценке растет... Так оно понятно, что селективность падает, но с какого сервер предпочитает делать скан по одному полю индекса, вместо использования обоих полей? В любом же случае "перебрать" индекс по двум ключам - оно быстрее, нежели выполнять полный скан всего индекса... Вот это для меня не совсем понятно... по двум -- да, но у тебя-то не два ... Сколько кстати ? давай посчитаем... ... |
|||
:
Нравится:
Не нравится:
|
|||
09.02.2014, 01:50 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83 абстрактрный план с 6 значений имеет явное указание этих 6 значений. Может быть я что-то не так смотрю? Совсем не туда! Код: sql 1.
Но это не поможет! В AP можно указать какой индекс использовать, а вот заставить его 2 колонки использовать, я что-то не нашел! ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 09:03 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
MasterZivMikle83пропущено... Так оно понятно, что селективность падает, но с какого сервер предпочитает делать скан по одному полю индекса, вместо использования обоих полей? В любом же случае "перебрать" индекс по двум ключам - оно быстрее, нежели выполнять полный скан всего индекса... Вот это для меня не совсем понятно... по двум -- да, но у тебя-то не два ... Сколько кстати ? давай посчитаем... Эм. Индекс создан как раз по двум полям, для которых указаны условия в Select. И при небольшом объеме IN-a как раз-таки сервер ведет себя ожидаемо: Код: sql 1. 2. 3. 4. 5. 6. 7.
но при расширении выборки по С1 - "забывает" про возможность использовать эту связку. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 09:55 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
cherrex_DenНо это не поможет! В AP можно указать какой индекс использовать, а вот заставить его 2 колонки использовать, я что-то не нашел! Да, действительно в обоих случаях абстрактные планы одинаковы, что несколько странно :( Все-таки сайбез не дает полностью управлять планами запросов и что-то оставляет на оптимизатор... ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 10:13 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
сам абстрактный план: Код: sql 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 10:16 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, Я тоже ожидал, что планы будут разные! Но увы.... Можно попробовать переписать запрос, загнать все что в IN во временную таблицу с одним полем. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 10:44 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
cherrex_DenMikle83, Я тоже ожидал, что планы будут разные! Но увы.... Можно попробовать переписать запрос, загнать все что в IN во временную таблицу с одним полем. Делал так - просто одно поле - не помогает - индекс используется по одному полю. Сделал "кросс-таблицу" по обоим полям, т.е. записал в нее все возможные сочетания C1 + C2 и приджойнил - вот тогда сервер использует индекс по полной (оба ключевых поля использует при джойне). Но сложность ситуации в том, что запрос прилетает с клиентской части, там работает что-то типа конструктора запросов. Т.е. по сути набирается несколько условий и они преобразуются в IN. Заставить их использовать промежуточную таблицу - будет сложно. Думаю в сторону создания некоторых вычисляемых полей в таблице на основе С1 и С2, которые будут "группировать" значения С1 и С2. Далее индекс по этим вычисляемым полям. Проверил - на минимальных выборках это помогает. Сейчас буду пробовать на основной таблице "проделать" это, но пугает перестроение всех индексов в момент создания вычисляемого поля = ресурсоемкий процесс, соотв. отправлю его в ночь. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 11:22 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83cherrex_DenНо это не поможет! В AP можно указать какой индекс использовать, а вот заставить его 2 колонки использовать, я что-то не нашел! Да, действительно в обоих случаях абстрактные планы одинаковы, что несколько странно :( Все-таки сайбез не дает полностью управлять планами запросов и что-то оставляет на оптимизатор... Есть абстрактные планы и полные планы. В случае полного плана очень немного остаётся на волю оптимизатора. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 12:58 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, Я тебе всё же предлагаю: -- дать полный DLL нужных таблиц -- дать конкретный полный запрос. -- дать его план. -- дать конкретный перечень значений в IN. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 13:00 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
MasterZiv, к сожалению не смогу выложить DDL боевых таблиц. Но! Эффект воспроизводится на следующем кейсе: создаем таблицу: Код: sql 1. 2.
заполняем таблицу: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
создаем индекс: Код: sql 1.
и смторим план на выборках со случайными значениями: Код: sql 1. 2. 3.
получаем использование двух ключей С1+С2. А при более широкой выборке Код: sql 1. 2. 3. 4.
получаем использование только одного ключа С1 ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 13:23 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
пропустил создание темповой таблицы, но там все тривиально Код: sql 1. 2.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 13:28 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, Переставьте поля в индексе! Что будет? Код: sql 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 14:35 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
cherrex_DenMikle83, Переставьте поля в индексе! Что будет? Код: sql 1.
Прикольный эффект. Используются оба ключа для поиска... Нашел весьма занимательную вещь: если в селекте поставить первую колонку из индекса - сервер выбирает стратегию "одного ключа", если поставить вторую - то сканит по двум ключам... Т.е. при индексе (С2,С1) Код: sql 1.
выдает Код: sql 1.
если ставлю запрос Код: sql 1.
выдает Код: sql 1.
загадко однако... ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 15:56 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
хотя, при указании первой колонки индекса - не требуется читать все листья индекса, может быть оно и верно, что используется только один ключ, но далеко не прозрачно поведение сервера... ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 16:17 |
|
ASE15.7 непонятная оценка оптимизатора по составному индексу
|
|||
---|---|---|---|
#18+
Mikle83, Наверное мы все таки зря ругаем оптимизатор. Все на вашем примере. Код: sql 1. 2. 3. 4. 5. 6.
|ROOT:EMIT Operator (VA = 4) | | |NESTED LOOP JOIN Operator (VA = 3) (Join Type: Inner Join) | | | | |SCAN Operator (VA = 0) | | | FROM OR List | | | OR List has up to 31 rows of OR/IN values. | | | | |RESTRICT Operator (VA = 2)(0)(0)(0)(1)(0) | | | | | | |SCAN Operator (VA = 1) | | | | FROM TABLE | | | | #T1 | | | | Index : Index1 | | | | Forward Scan. | | | | Positioning by key. | | | | Keys are: | | | | C1 ASC | | | | Using I/O Size 64 Kbytes for index leaf pages. | | | | With LRU Buffer Replacement Strategy for index leaf pages. | | | | Using I/O Size 8 Kbytes for data pages. | | | | With LRU Buffer Replacement Strategy for data pages. Table: #T1 scan count 31, logical reads: (regular= 155 apf=0 total= 155 ), physical reads: (regular=0 apf=0 total=0), apf IOs used=0 поменяли поля в индексе Код: sql 1. 2. 3. 4. 5. 6.
|ROOT:EMIT Operator (VA = 5) | | |NESTED LOOP JOIN Operator (VA = 4) (Join Type: Inner Join) | | | | |NESTED LOOP JOIN Operator (VA = 2) (Join Type: Inner Join) | | | | | | |SCAN Operator (VA = 0) | | | | FROM OR List | | | | OR List has up to 5 rows of OR/IN values. | | | | | | |SCAN Operator (VA = 1) | | | | FROM OR List | | | | OR List has up to 31 rows of OR/IN values. | | | | |SCAN Operator (VA = 3) | | | FROM TABLE | | | #T1 | | | Index : Index1 | | | Forward Scan. | | | Positioning by key. | | | Keys are: | | | C2 ASC | | | C1 ASC | | | Using I/O Size 64 Kbytes for index leaf pages. | | | With LRU Buffer Replacement Strategy for index leaf pages. | | | Using I/O Size 8 Kbytes for data pages. | | | With LRU Buffer Replacement Strategy for data pages. Table: #T1 scan count 155, logical reads: (regular= 465 apf=0 total= 465 ), physical reads: (regular=0 apf=0 total=0), apf IOs used=0 Так что как-то так. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.02.2014, 23:47 |
|
|
start [/forum/topic.php?fid=55&msg=38554276&tid=2009876]: |
0ms |
get settings: |
9ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
137ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
63ms |
get tp. blocked users: |
1ms |
others: | 15ms |
total: | 260ms |
0 / 0 |