News:
SQL Tuning Tipp: „SELECT 0“ in einer [NOT] EXISTS-Subquery

Wenn nur die Existenz der Ergebniszeile in einer Subquery von Interesse ist, ist es nicht erforderlich (teils sogar schädlich), konkrete Tabellenspalten oder gar Aggregate zu selektieren.

Icon Unternehmen

Das Selektieren einer konkreten Spalte ist schadlos, wenn diese Spalte Bestandteil eines in der Subquery sowieso verwendeten Indexes ist. Auch aktuelle Optimizerversionen bügeln diesen faux-pax bereits im Hintergrund aus. Andernfalls muss zum Ermitteln des Spaltenwertes unnötigerweise zusätzlich zum Index- noch ein Tabellenzugriff erfolgen.

Aggregate (z.B. count()) in einer Subquery, die für den Test auf Enthaltensein genutzt wird, ist unperformanter als EXISTS / IN, da das Aggregat in jedem Fall errechnet wird. Unabhängig davon, gegen welchen Wert es letztendlich verglichen wird.

Gutes Beispiel

SELECT *
FROM employees m
WHERE EXISTS (
  SELECT 0 --oder e.manager_id
  FROM employees e
  WHERE e.manager_id = m.employee_id);

-----------------------------------------------------------------------------------------
| Id  | Operation              | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                | 31250 |  3448K|  4798   (1)| 00:00:58 |
|*  1 |  HASH JOIN             |                | 31250 |  3448K|  4798   (1)| 00:00:58 |
|   2 |   SORT UNIQUE          |                |  1000K|    12M|     9   (0)| 00:00:01 |
|   3 |    INDEX FAST FULL SCAN| EMP_MANAGER_IX |  1000K|    12M|     9   (0)| 00:00:01 |
|   4 |   TABLE ACCESS FULL    | EMPLOYEES      |  1000K|    95M|    38  (24)| 00:00:01 |
-----------------------------------------------------------------------------------------

Schlechtes Beispiel

SELECT *
FROM employees m
WHERE (
  SELECT count(*)
  FROM employees e
  WHERE m.manager_id = e.employee_id) > 0;

-------------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |  1000K|    95M|   855K  (1)| 02:51:02 |
|*  1 |  FILTER             |               |       |       |            |          |
|   2 |   TABLE ACCESS FULL | EMPLOYEES     |  1000K|    95M|    40  (28)| 00:00:01 |
|   3 |   SORT AGGREGATE    |               |     1 |    13 |            |          |
|*  4 |    INDEX UNIQUE SCAN| EMP_EMP_ID_PK |     1 |    13 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------------