При условии, что типы данных совместимы - т.е. не требуется (неявное) преобразование - оптимизатор может использовать индекс для объединения таблиц.
В моих таблицах миллионы строк, поэтому объединение без использования индекса занимает много времени
Это зависит!
Если вы выбираете больше всего* строк из обеих таблиц, это может быть быстрее для полного сканирования обеих. Затем хеш соединяет результаты.
Например, это объединяет все строки из обеих таблиц. Вы получаете все, поэтому нет необходимости использовать индекс:
create table t1 (
c1, c2
) as
select cast ( level as nvarchar2(30) ) , rpad ( 'stuff', 100, 'f' )
from dual
connect by level <= 1000;
create table t2 (
c1, c2, c3
) as
select cast ( level as nvarchar2(255) ) , mod ( level, 333 ) , rpad ( 'stuff', 100, 'f' )
from dual
connect by level <= 1000;
create index i1
on t1 ( c1 );
create index i2
on t2 ( c1 );
create index i2_c2
on t2 ( c2 );
exec dbms_stats.gather_table_stats ( user, 't1' ) ;
exec dbms_stats.gather_table_stats ( user, 't2' ) ;
set serveroutput off
alter session set statistics_level = all;
select * from t1
join t2
on t1.c1 = t2.c1;
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
-------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1000 |00:00:00.01 | 45 |
|* 1 | HASH JOIN | | 1 | 1000 | 1000 |00:00:00.01 | 45 |
| 2 | TABLE ACCESS FULL| T1 | 1 | 1000 | 1000 |00:00:00.01 | 18 |
| 3 | TABLE ACCESS FULL| T2 | 1 | 1000 | 1000 |00:00:00.01 | 27 |
-------------------------------------------------------------------------------------
Что, если вы получаете несколько * строк из одной таблицы?
Вы захотите использоватьИндекс, чтобы найти их. И - при условии, что каждая из этих ссылок содержит только несколько строк в другой таблице, - использовать индекс для второй таблицы в соединении вложенных циклов. Как показано в этом примере, который получает три строки из одной таблицы. Каждый из которых соединяется друг с другом:
select * from t1
join t2
on t1.c1 = t2.c1
where t2.c2 = 0;
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 3 |00:00:00.01 | 13 |
| 1 | NESTED LOOPS | | 1 | 3 | 3 |00:00:00.01 | 13 |
| 2 | NESTED LOOPS | | 1 | 3 | 3 |00:00:00.01 | 10 |
| 3 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 3 | 3 |00:00:00.01 | 5 |
|* 4 | INDEX RANGE SCAN | I2_C2 | 1 | 3 | 3 |00:00:00.01 | 2 |
|* 5 | INDEX RANGE SCAN | I1 | 3 | 1 | 3 |00:00:00.01 | 5 |
| 6 | TABLE ACCESS BY INDEX ROWID | T1 | 3 | 1 | 3 |00:00:00.01 | 3 |
-------------------------------------------------------------------------------------------------
Обратите внимание, что оба столбца объединения зависят от nvarchar2
или varchar2
. Это несовместимые типы. Поэтому, если вы смешаете и сопоставите их, оптимизатор не сможет использовать индекс для столбцов соединения.
Переключение t1.c1 с nvarchar2
-> varchar2
в предыдущих примерах показывает это. Теперь, несмотря на получение нескольких строк из обеих таблиц, оптимизатор полностью сканирует t3
:
create table t3 as
select cast ( c1 as varchar2(30) ) c1, c2 from t1;
select * from t3
join t2
on t3.c1 = t2.c1
where t2.c2 = 0;
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 3 |00:00:00.01 | 24 |
|* 1 | HASH JOIN | | 1 | 3 | 3 |00:00:00.01 | 24 |
| 2 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 3 | 3 |00:00:00.01 | 5 |
|* 3 | INDEX RANGE SCAN | I2_C2 | 1 | 3 | 3 |00:00:00.01 | 2 |
| 4 | TABLE ACCESS FULL | T3 | 1 | 1000 | 1000 |00:00:00.01 | 19 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."C1"=SYS_OP_C2C("T3"."C1"))
3 - access("T2"."C2"=0)
Обратите внимание на операцию SYS_OP_C2C
на t3.c1
? Это функция. Это означает, что база данных не может использовать индекс (не на основе функций) для этого столбца. Итак, у вас есть полное сканирование.
Примечание * Мало и большинство из них являются относительными! Там нет абсолютных значений для них. Я обсуждаю это далее в этой серии видео .