Самостоятельное соединение с естественным соединением - PullRequest
0 голосов
/ 24 мая 2018

В чем разница между

select * from degreeprogram  NATURAL JOIN degreeprogram ;

и

select * from degreeprogram d1 NATURAL JOIN degreeprogram d2;

в оракуле?Я ожидал, что они возвращают один и тот же набор результатов, однако, они этого не делают.Второй запрос выполняет то, что я ожидаю: он объединяет два отношения, используя одинаковые именованные атрибуты, и поэтому возвращает те же кортежи, которые хранятся в программе степени.Однако первый запрос сбивает меня с толку: здесь каждый кортеж встречается несколько раз в наборе результатов -> какое условие соединения используется здесь?

Спасибо

Ответы [ 4 ]

0 голосов
/ 25 мая 2018

Я бы назвал это ошибкой.Этот запрос:

select * from degreeprogram d1 NATURAL JOIN degreeprogram d2;

преобразуется в

select col1, col2, ... -- all columns
from degreeprogram d1
join degreeprogram d2 using (col1, col2, ...)

и выдает все строки таблицы, где все столбцы не равны нулю (поскольку using(col) никогда не соответствует нулю).

Однако этот запрос:

select * from degreeprogram NATURAL JOIN degreeprogram;

недопустим в соответствии со стандартным SQL, поскольку каждая таблица должна иметь уникальное имя или псевдоним в запросе.Oracle пропускает это, но при этом должно делать что-то еще, чтобы разделять экземпляры таблиц (например, создавать для них внутренний псевдоним).Очевидно, что это не так, и результат умножается на количество строк в таблице.Ошибка.

0 голосов
/ 24 мая 2018

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

0 голосов
/ 25 мая 2018

Так называемый natural join дает указание базе данных

  1. Найти все имена столбцов, общие для обеих таблиц (в данном случае degreeprogram и degreeprogram, которые, конечно, имеют одинаковыестолбцы.)
  2. Создание условия объединения для каждой пары совпадающих имен столбцов в форме table1.column1 = table2.column1 (в этом случае для каждого столбца в degreeprogram. будет один)

Поэтому запрос, подобный этому

select count(*) from demo natural join demo;

, будет преобразован в

select count(*) from demo, demo where demo.x = demo.x;

Я проверил это, создав таблицу с одним столбцом и двумя строками:

create table demo (x integer);

insert into demo values (1);
insert into demo values (2);
commit;

и затем отслеживание сеанса :

SQL> alter session set tracefile_identifier='demo_trace';

Session altered.

SQL> alter session set events 'trace [SQL_Compiler.*]';

Session altered.

SQL> select /* nj test */ count(*) from demo natural join demo;

  COUNT(*)
----------
         4

1 row selected.

SQL> alter session set events 'trace [SQL_Compiler.*] off';

Session altered.

Затем в файле twelve_ora_6196_demo_trace.trc я нашел следующую строку:

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT COUNT(*) "COUNT(*)" FROM "WILLIAM"."DEMO" "DEMO","WILLIAM"."DEMO" "DEMO" WHERE "DEMO"."X"="DEMO"."X"

и несколько строк спустя:

try to generate single-table filter predicates from ORs for query block SEL$58A6D7F6 (#0)
finally: "DEMO"."X" IS NOT NULL

(Это просто оптимизация поверх сгенерированного запроса выше, поскольку столбец X может иметь значение NULL, но объединение позволяет оптимизатору сделать вывод, что требуются только ненулевые значения.t заменить соединения.)

Отсюда и план выполнения:

-----------------------------------------+-----------------------------------+
| Id  | Operation              | Name    | Rows  | Bytes | Cost  | Time      |
-----------------------------------------+-----------------------------------+
| 0   | SELECT STATEMENT       |         |       |       |     7 |           |
| 1   |  SORT AGGREGATE        |         |     1 |    13 |       |           |
| 2   |   MERGE JOIN CARTESIAN |         |     4 |    52 |     7 |  00:00:01 |
| 3   |    TABLE ACCESS FULL   | DEMO    |     2 |    26 |     3 |  00:00:01 |
| 4   |    BUFFER SORT         |         |     2 |       |     4 |  00:00:01 |
| 5   |     TABLE ACCESS FULL  | DEMO    |     2 |       |     2 |  00:00:01 |
-----------------------------------------+-----------------------------------+
Query Block Name / Object Alias(identified by operation id):
------------------------------------------------------------
 1 - SEL$58A6D7F6         
 3 - SEL$58A6D7F6         / DEMO_0001@SEL$1
 5 - SEL$58A6D7F6         / DEMO_0002@SEL$1
------------------------------------------------------------
Predicate Information:
----------------------
3 - filter("DEMO"."X" IS NOT NULL)

Альтернативаага, давайте посмотрим, что с этим делает dbms_utility.expand_sql_text.Я не совсем уверен, что с этим делать, учитывая приведенный выше файл трассировки, но он показывает аналогичное расширение, происходящее:

SQL> var result varchar2(1000)
SQL> exec dbms_utility.expand_sql_text('select count(*) from demo natural join demo', :result)

PL/SQL procedure successfully completed.

RESULT
----------------------------------------------------------------------------------------------------------------------------------
SELECT COUNT(*) "COUNT(*)" FROM  (SELECT "A2"."X" "X" FROM "WILLIAM"."DEMO" "A3","WILLIAM"."DEMO" "A2" WHERE "A2"."X"="A2"."X") "A1"

Урок: NATURAL JOIN - зло.Все это знают.

0 голосов
/ 24 мая 2018

NATURAL JOIN означает объединение двух таблиц на основе всех столбцов, имеющих одинаковые имена в обеих таблицах.

Я предполагаю, что для каждого столбца в вашей таблице Oracle внутренне пишет условие, подобное:

degreeprogram.column1 = degreeprogram.column1

(что вы не сможете написать самостоятельно из-за неоднозначно определенной ошибки в столбце ORA-00918)

И затем, я полагаю, Oracle оптимизирует это до

degreeprogram.column1 is not null

Итак, вы не совсем получаете CROSS JOIN вашей таблицы с собой - только CROSS JOIN из тех строк, которые не имеют нулевых столбцов.

ОБНОВЛЕНИЕ: Поскольку это был выбранный ответЯ просто добавлю из ответа Торстена Кеттнера, что такое поведение, вероятно, является ошибкой со стороны Oracle.В 18c Oracle ведет себя правильно и возвращает ошибку ORA-00918 при попытке NATURAL JOIN таблицы к себе.

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