Однорядные подзапросы в Oracle - каков план соединения? - PullRequest
0 голосов
/ 08 октября 2008

Я только что обнаружил, что Oracle позволяет вам делать следующее:

SELECT foo.a, (SELECT c 
               FROM bar 
               WHERE foo.a = bar.a) 
from foo

Пока только одна строка в строке соответствует любой строке в foo.

План объяснения, полученный от разработчика PL / SQL, таков:

SELECT STATEMENT, GOAL = ALL_ROWS               
 TABLE ACCESS FULL  BAR 
 TABLE ACCESS FULL  FOO 

Это на самом деле не определяет, как таблицы объединяются. Коллега утверждал, что это более эффективно, чем обычное соединение. Это правда? Какова стратегия объединения в таком утверждении select и почему оно не отображается в плане объяснения?

Спасибо.

Ответы [ 2 ]

4 голосов
/ 08 октября 2008

План, который у вас там, вообще не дает много информации.

Используйте SQL * Plus и используйте dbms_xplan, чтобы получить более подробный план. Ищите скрипт с именем utlxpls.sql.

Это дает немного больше информации: -

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1837 | 23881 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| BAR  |    18 |   468 |     2   (0)| 00:00:01 |
|   2 |  TABLE ACCESS FULL| FOO  |  1837 | 23881 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("BAR"."A"=:B1)

Note
-----
   - dynamic sampling used for this statement

18 rows selected.

Я не создавал индексы или внешние ключи и не собирал статистику по таблицам, что могло бы изменить план и выбранный механизм соединения. Oracle на самом деле выполняет соединение типа NESTED LOOPS. Шаг 1, ваш вложенный выбор, выполняется для каждой строки, возвращаемой из FOO.

Этот способ выполнения SELECT не быстрее. Это может быть то же самое или медленнее. В общем, попробуйте объединить все в главном предложении WHERE, если оно не станет ужасно нечитаемым.

2 голосов
/ 08 октября 2008

Если вы создадите нормальный индекс для бара (a), CBO должен быть в состоянии использовать, но я уверен, что он не сможет выполнять хеш-соединения. Подобные запросы имеют смысл только в том случае, если вы используете агрегатную функцию и у вас есть несколько однострочных подзапросов в верхнем SELECT. Тем не менее, вы всегда можете переписать запрос как:

SELECT foo.a, bar1.c, pub1.d
FROM foo
JOIN (SELECT a, MIN(c) as c
      FROM bar
      GROUP BY a) bar1
  ON foo.a = bar1.a
JOIN (SELECT a, MAX(d) as d
      FROM pub
      GROUP BY a) pub1
  ON foo.a = pub1.a

Это позволило бы CBO использовать больше параметров, в то же время это позволило бы вам легко извлекать несколько столбцов из дочерних таблиц без необходимости сканировать одни и те же таблицы несколько раз.

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