Der aktuelle SQL Tuning Tipp beschäftigt sich mit der Optimierung einer 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.
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 |
-------------------------------------------------------------------------------------
Share this article