Странное поведение полного внешнего объединения в Oracle - как это можно объяснить? - PullRequest
8 голосов
/ 15 марта 2012

Я заметил странное поведение FULL OUTER JOIN в Oracle 11. Я соединял таблицы из схемы HR, в частности, СОТРУДНИКИ и ОТДЕЛЕНИЯ.

Например, следующий запрос возвращает 123 строки:

    SELECT * FROM employees e
    FULL JOIN departments d ON e.department_id = d.department_id

Однако, что сложно понять - когда я помещаю набор определенных столбцов в предложение select, запрос возвращает 122 строки (пропущенная строка предназначена для сотрудника, которому не назначен отдел - тот, который дополнительно возвращается с левым соединением по сравнению с внутренним соединением):

    SELECT first_name, last_name, department_name FROM employees e
    FULL JOIN departments d on e.department_id = d.department_id

Даже когда я считаю строки, он возвращает 122 (COUNT(*)) !!! ЧТО ЗДЕСЬ ПРОИСХОДИТ? В чем разница между SELECT * и SELECT COUNT(*)?

План объяснения для SELECT * ...:

SELECT STATEMENT                                      122
  VIEW                 VW_FOJ_0                       122
    HASH JOIN                          FULL OUTER     122
      Access Predicates
        E.DEPARTMENT_ID = D.DEPARTMENT_ID
      TABLE ACCESS     DEPARTMENTS     FULL            27
      TABLE ACCESS     EMPLOYEES       FULL           107

и для SELECT COUNT(*) ...:

SELECT STATEMENT                                             1
  SORT                                     AGGREGATE         1
    VIEW               VW_FOJ_0                            122
      HASH JOIN                            FULL OUTER      122
        Access Predicates
          E.DEPARTMENT_ID = D.DEPARTMENT_ID
        INDEX          DEPT_ID_PK          FAST FULL SCAN   27
        INDEX          EMP_DEPARTMENT_IX   FAST FULL SCAN  107

Ответы [ 2 ]

6 голосов
/ 15 марта 2012

Оптимизатор не должен выбирать использование индекса для EMP.DEPT_ID во втором запросе, поскольку он может иметь значения NULL.Это то, что заставляет его исключать одну строку из результатов.

Единственное не ошибочное объяснение, о котором я могу думать в данный момент, состоит в том, что вы каким-то образом создали ограничения в режиме DISABLE RELY, так что оптимизатор думает, чтополе не может содержать NULL.В этом случае было бы правильно использовать индекс с учетом неверной информации в ограничениях.Однако кажется, что опция RELY недоступна для ограничений NOT NULL, поэтому я не вижу, как это может быть проблемой.Тем не менее, внимательно посмотрите на все ограничения таблиц.

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

alter session set "_optimizer_native_full_outer_join"=off; 
1 голос
/ 15 марта 2012

(Не могу написать это в комментарии)

Результаты соответствуют планам выполнения.

План выполнения count (*) использует индекс EMP_DEPARTMENT_IX, который содержит все dept_ids от Employess.Таблица.Но индексы не содержат нулей.Таким образом, этот план выполнения "потеряет" emps с нулевым значением_тдела.

Однако следует объяснить, почему Oracle выбрал этот план выполнения в случае

select first_name, last_name, department_name

и

select count(*)

против

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