News zu Oracle

SQL Tuning Tipp: Subquery in SELECT-Klausel

Im Rahmen von SQL-Tuning-Maßnahmen sieht man zuweilen, dass Subqueries zur Ermittlung von Spaltenwerten direkt in der SELECT-Klausel verwendet werden. Obwohl syntak­tisch korrekt, ist das regel­mäßig ein Stolperstein für den Optimizer. Er kommt offen­kundig mit der Abschätzung “echter” Joins besser zurecht.

Da der Rückgabewert der Subquery nur ein einzei­liger Skalar oder NULL sein kann (da andern­falls die Query fehlschlagen würde), erreicht man mit Umstellung auf LEFT OUTER JOIN das selbe Ergebnis. Aus dem genannten Grund sind weder mehr als eine Zeile auf der “rechten” Seite des Joins zu erwarten noch besteht die Gefahr der Eliminierung von Ergebniszeilen der “linken” Seite durch den Join, da es sich ja um einen OUTER Join handelt.

Subquery in der SELECT-Klausel

SELECT first_name, last_name,
  (SELECT department_name
  FROM departments
  WHERE department_id = e.department_id)
FROM employees e;
-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |   107 |  1926 |    14   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |     1 |    16 |     1   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | DEPT_ID_PK  |     1 |       |     0   (0)| 00:00:01 |
|   3 |  TABLE ACCESS FULL          | EMPLOYEES   |   107 |  1926 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

Die ursprüng­liche Query wird ähnlich einem NESTED LOOP ausge­führt. Für jede der 107 Zeilen aus EMPLOYEES wird über je einen INDEX UNIQUE SCAN der Indexeintrag des zugehö­rigen Departments gesucht und über je einen weiteren ROWID-Zugriff der department_name aus der DEPARTMENTS-Tabelle ermittelt. Das kann bei ausrei­chend großer “äußerer” Tabelle ein sehr unper­for­manter Zugriffspfad sein. NESTED LOOPs performen nur bei geringer Kardinalität der “äußeren” Tabelle gut.

Ersetzung durch einen Join

SELECT first_name, last_name, department_name
FROM employees e 
  LEFT JOIN departments d using (department_id);
----------------------------------------------------------------------------------
| Id  | Operation          | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |             |   107 |  3638 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN OUTER   |             |   107 |  3638 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMPLOYEES   |   107 |  1926 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| DEPARTMENTS |    27 |   432 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------

Der LEFT OUTER JOIN hingegen wird über einen (outer) HASH JOIN abgewi­ckelt, der insbe­sondere bei großer “äußerer” Tabelle viel besser performt, als ein NESTED LOOP. Das spiegelt sich im angege­benen Beispiel vor allem in der Cost-Schätzung wider.

Hier findest du weitere Posts zu den Themen SQL Tuning bzw. Performance Tuning aus unserem News Bereich. 
icon-arrow_right_medium-violet-blue.svg

Share this article

Facebook 
Twitter 
LinkedIn 
XING 
WhatsApp 
Email