У меня есть база данных Oracle 10.2.0.3 и такой запрос:
select count(a.id)
from LARGE_PARTITIONED_TABLE a
join SMALL_NONPARTITIONED_TABLE b on a.key1 = b.key1 and a.key2 = b.key2
where b.id = 1000
Таблица LARGE_PARTITIONED_TABLE (a) имеет около 5 миллионов строк и разделена столбцом, отсутствующим в запросе.Таблица SMALL_NONPARTITIONED_TABLE (b) не секционирована и содержит около 10000 строк.
Статистика актуальна, и в столбцах key1 и key2 таблицы a есть сбалансированные по высоте гистограммы таблицы.
Таблица a имеет первичный ключ и глобальный, нераздельный уникальный индекс для столбцов key1, key2, key3, key4 и key5.
План объяснения для запроса отображает следующие результаты:
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | 4 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 31 | | |
| 2 | NESTED LOOPS | | 406 | 12586 | 4 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN| INDEX_ON_TABLE_B | 1 | 19 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN| PRIMARY_KEY_INDEX_OF_TABLE_A | 406 | 4872 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("b"."id"=1000)
4 - access("a"."key1"="b"."key1" and
"a"."key2"="b"."key2")
Таким образом, строки (количество элементов), оцененные для шага 4, равны 406 .
Теперь трассировка tkprof показывает следующее:
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE (cr=51 pr=9 pw=0 time=74674 us)
7366 NESTED LOOPS (cr=51 pr=9 pw=0 time=824941 us)
1 INDEX RANGE SCAN INDEX_ON_TABLE_B (cr=2 pr=0 pw=0 time=36 us)(object id 111111)
7366 INDEX RANGE SCAN PRIMARY_KEY_INDEX_OF_TABLE_A (cr=49 pr=9 pw=0 time=810173 us)(object id 222222)
Таким образом, кардинальность в действительности была 7366 , а не 406!
Мой вопрос такой: Откуда Oracle получает предполагаемую мощность из 406в этом случае и как я могу улучшить его точность , чтобы оценка соответствовала тому, что действительно происходит во время выполнения запроса?
Обновление: Вот фрагмент трассировки 10053, который я выполнил по запросу.
NL Join
Outer table: Card: 1.00 Cost: 2.00 Resp: 2.00 Degree: 1 Bytes: 19
Inner table: LARGE_PARTITIONED_TABLE Alias: a
...
Access Path: index (IndexOnly)
Index: PRIMARY_KEY_INDEX_OF_TABLE_A
resc_io: 2.00 resc_cpu: 27093
ix_sel: 1.3263e-005 ix_sel_with_filters: 1.3263e-005
NL Join (ordered): Cost: 4.00 Resp: 4.00 Degree: 1
Cost_io: 4.00 Cost_cpu: 41536
Resp_io: 4.00 Resp_cpu: 41536
****** trying bitmap/domain indexes ******
Best NL cost: 4.00
resc: 4.00 resc_io: 4.00 resc_cpu: 41536
resp: 4.00 resp_io: 4.00 resp_cpu: 41536
Using concatenated index cardinality for table SMALL_NONPARTITIONED_TABLE
Revised join sel: 8.2891-e005 = 8.4475e-005 * (1/12064.00) * (1/8.4475e-005)
Join Card: 405.95 = outer (1.00) * inner (4897354.00) * sel (8.2891-e005)
Join Card - Rounded: 406 Computed: 405.95
Так вот откуда исходит значение 406,Как ответил Адам, кардинальное число присоединений равно join selectivity * filter cardinality (a) * filter cardinality (b)
, что видно на второй-последней строке приведенной выше цитаты следа.
Что я не понимаю, так это строка Revised join sel
.1/12064 - это селективность индекса, используемого для поиска строки из таблицы b (12064 строки в таблице и выбор на основе уникального идентификатора).Но что с того?
Кажется, что кардинальность рассчитывается путем умножения мощности фильтра таблицы b (4897354) на селективность таблицы a (1/12064).Зачем?Как избирательность в таблице a связана с тем, сколько строк ожидается найти в таблице b, , когда соединение a -> b не основано на a.id?
Откуда берется число 8.4475e-005 (его больше нигде нет на всем пути следования)?Не то чтобы это влияло на вывод, но я все же хотел бы знать.
Я понимаю, что оптимизатор, вероятно, выбрал правильный путь здесь.Но все же кардинальность просчитана - и это может оказать существенное влияние на путь выполнения, который выбирается с этого момента (как в случае, если у меня IRL - этот пример является упрощением этого).