Соединить столбец одного типа, но разной длины в 2 таблицах в Oracle - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть 2 таблицы, каждая из которых имеет столбец sub_id типа nvarchar2, но разной длины (одна - 30, другая - 255). У меня есть индексы БД, созданные в обеих этих таблицах в соответствующих столбцах sub_id. Я выполняю объединение этих таблиц в столбце sub_id.

В моих таблицах миллионы строк, поэтому объединение без использования индекса занимает много времени. Я не уверен, используются ли здесь индексы, так как я подозреваю, что разница в длине столбца может привести к полному сканированию таблицы.

Пожалуйста, предоставьте понимание, поскольку я довольно плохо знаком с такими основными понятиями администратора базы данных. Я попытался прочитать больше об этом, но смог найти что-то достаточно конкретное.

РЕДАКТИРОВАТЬ: Другой запрос, можем ли мы иметь эти 2 столбца sub_id как один varchar2, а другой как nvarchar, и индексы также используются?

1 Ответ

1 голос
/ 05 ноября 2019

При условии, что типы данных совместимы - т.е. не требуется (неявное) преобразование - оптимизатор может использовать индекс для объединения таблиц.

В моих таблицах миллионы строк, поэтому объединение без использования индекса занимает много времени

Это зависит!

Если вы выбираете больше всего* строк из обеих таблиц, это может быть быстрее для полного сканирования обеих. Затем хеш соединяет результаты.

Например, это объединяет все строки из обеих таблиц. Вы получаете все, поэтому нет необходимости использовать индекс:

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? Это функция. Это означает, что база данных не может использовать индекс (не на основе функций) для этого столбца. Итак, у вас есть полное сканирование.

Примечание * Мало и большинство из них являются относительными! Там нет абсолютных значений для них. Я обсуждаю это далее в этой серии видео .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...