Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SAP Sybase SQL Anywhere 16.0 (Deutsch) » SQL Anywhere Server - SQL-Benutzerhandbuch » Performanceverbesserungen, Diagnosen und Monitoring » Tipps zum Verbessern der Performance

 

Tipp: Aufbauen effizienter SQL-Abfragen

Um die Performance bei der Abfrageverarbeitung zu verbessern, können Sie anhand der folgenden Tipps effizientere Abfragen aufbauen. Diese Tipps spiegeln Optimierungen wieder, die der Optimierer möglicherweise während der Abfrageverarbeitung wählen würde, um die Abfrage effizienter zu gestalten. Wenn Sie diese Effizienzen in die Abfrage integrieren, muss der Optimierer in der Regel weniger Arbeit verrichten.

Tipp Vorher und nachher Erklärung

Eliminieren Sie nicht benötigte DISTINCT-Bedingungen.

Vorher:

SELECT DISTINCT p.ID, p.Quantity
FROM Products p;

Nachher:

SELECT p.ID, p.Quantity
FROM Products p;

Das DISTINCT-Schlüsselwort in der ersten Anweisung ist unnötig, weil die Products-Tabelle den Primärschlüssel "p.ID" enthält, der Teil der Ergebnismenge ist.

Eliminieren Sie nicht benötigte DISTINCT-Bedingungen.

Vorher:

SELECT DISTINCT *
FROM SalesOrders o JOIN Customers c
   ON o.CustomerID = c.ID
WHERE c.State = 'NY';

Nachher:

SELECT  *
FROM SalesOrders o JOIN Customers c
   ON o.CustomerID = c.ID
WHERE c.State = 'NY';

Die erste Abfrage enthält die Primärschlüssel beider Tabellen, d.h., jede Zeile im Ergebnis muss unterschiedlich sein.

Entschachteln Sie Unterabfragen.

Vorher:

SELECT s.*
FROM SalesOrderItems s
WHERE EXISTS ( SELECT *
 FROM Products p
 WHERE s.ProductID = p.ID
  AND p.ID = 300 
  AND p.Quantity > 20);

Nachher:

SELECT s.*
FROM Products p JOIN SalesOrderItems s
   ON p.ID = s.ProductID
WHERE p.ID = 300 AND p.Quantity > 20;

Das Umschreiben von verschachtelten Abfragen in Joins führt häufig zu einer effizienteren Ausführung und effektiveren Optimierung. Allgemein werden korrelierte Unterabfragen mit nicht mehr als einer Tabelle in der FROM-Klausel, die in den Prädikaten ANY, ALL und EXISTS benutzt werden, immer entschachtelt. Eine nicht korrelierte Unterabfrage oder eine Unterabfrage mit mehr als einer Tabelle in der FROM-Klausel wird entschachtelt, wenn aufgrund der Abfragesemantik erkennbar ist, dass die Unterabfrage nicht mehr als eine Zeile liefert.

In diesem Beispiel kann die Unterabfrage höchstens eine Zeile für jede Zeile im Außenblock in Übereinstimmung bringen. Weil hier immer nur eine Zeile gefunden wird, ist die Konvertierung in einen Inner-Join möglich.

Entschachteln Sie Unterabfragen.

Vorher:

SELECT p.*
FROM Products p
WHERE EXISTS
   ( SELECT *
     FROM SalesOrderItems s
     WHERE s.ProductID = p.ID
       AND s.ID = 2001);

Nachher:

SELECT DISTINCT p.*
FROM Products p JOIN SalesOrderItems s
   ON p.ID = s.ProductID
WHERE s.ID = 2001;

Die Abfrage unter "Vor" enthält ein konjunktives EXISTS-Prädikat in der Unterabfrage, das mit mehr als einer Zeile übereinstimmen kann. Sie kann mit DISTINCT in der SELECT-Liste in einen Inner-Join konvertiert werden.

Entschachteln Sie Unterabfragen.

Vorher:

SELECT *
FROM Products p
WHERE p.ID =
    ( SELECT s.ProductID
      FROM SalesOrderItems s
      WHERE s.ID = 2001
         AND s.LineID = 1 );

Nachher:

SELECT p.*
FROM Products p, SalesOrderItems s
WHERE p.ID = s.ProductID
   AND s.ID = 2001
   AND s.LineID = 1;

Eliminieren Sie Unterabfragen in Vergleichen, bei denen die Unterabfrage für jede Zeile im Außenblock mit höchstens einer Zeile übereinstimmt.

Ziehen Sie beim Abfragen einer indizierten Spalte in Erwägung, ein IN-Prädikat zu verwenden.

Vorher:

SELECT *
FROM SalesOrders
WHERE SalesRepresentative = 902 
   OR SalesRepresentative = 195;

Nachher:

SELECT *
FROM SalesOrders
WHERE SalesRepresentative IN ( 195, 902 );

In der umgeschriebenen Form kann das IN-Listen-Prädikat als sargable (als Suchargument nutzbar) behandelt und für den Abruf über den Index genutzt werden. Außerdem kann der Optimierer die IN-Liste sortieren, damit sie mit der Sortierfolge des Indexes übereinstimmt, was einen effizienteren Abruf zur Folge hat.

Die IN-Liste darf nur Konstanten oder Werte enthalten, die während einer Ausführung des Abfrageblocks konstant bleiben, z.B. äußere Referenzen.

Eliminieren Sie nicht benötigte Joins.

Vorher:

SELECT s.ID, s.LineID, p.ID
FROM SalesOrderItems s KEY JOIN Products p
FOR READ ONLY;

Nachher:

SELECT s.ID, s.LineID, s.ProductID
FROM SalesOrderItems s
WHERE s.ProductID IS NOT NULL
FOR READ ONLY;

Ziehen Sie die Eliminierung von Joins in Erwägung, wenn Folgendes zutrifft:

  • Der Join ist ein Primärschlüssel-Fremdschlüssel-Join und in der Abfrage werden lediglich Primärschlüsselspalten aus der Primärtabelle referenziert. In diesem Fall wird die Primärschlüsseltabelle eliminiert, falls sie nicht aktualisierbar ist.

  • Der Join ist ein Primärschlüssel-Primärschlüssel-Join zwischen zwei Instanzen in derselben Tabelle. In diesem Fall wird eine der Tabellen eliminiert, falls sie nicht aktualisierbar ist.

  • Der Join ist ein Outer-Join und der nullwertliefernde Tabellenausdruck gibt für jede Zeile der beibehaltenen Seite des Outer-Joins höchstens eine Zeile zurück. Keiner der von dem nullwertliefernden Ausdruck erzeugten Ausdrücke wird im Rest der Abfrage nach dem Outer-Join benötigt.

In diesem Fall ist der Join ein Primärschlüssel-Fremdschlüssel-Join, sodass die Primärschlüsseltabelle "Products" eliminiert werden kann. Die zweite Abfrage ist also der ersten semantisch gleichwertig, weil im Ergebnis keine Zeile aus der SalesOrderItems-Tabelle erscheint, die einen NULL-Fremdschlüssel zu "Products" enthält.

Eliminieren Sie nicht benötigte Joins.

Vorher:

SELECT s.ID, s.LineID
FROM SalesOrderItems s 
 LEFT OUTER JOIN Products p 
   ON p.ID = s.ProductID
WHERE s.Quantity > 5 
FOR READ ONLY;

Nachher:

SELECT s.ID, s.LineID
FROM SalesOrderItems s  
WHERE s.Quantity > 5 
FOR READ ONLY;

In der ersten Abfrage kann das Schlüsselwort OUTER JOIN eliminiert werden, weil der nullwertliefernde Tabellenausdruck für jede Zeile der beibehaltenen Seite höchstens eine Zeile erzeugen kann und keine der Spalten von "Products" oberhalb der LEFT OUTER JOIN-Anweisung verwendet wird.

Eliminieren Sie unnötige Konvertierungen der Groß- und Kleinschreibung.

Vorher:

SELECT *
FROM Customers
WHERE UPPER(Surname) = 'SMITH';

Nachher:

SELECT *
FROM Customers
WHERE Surname = 'SMITH';

In einer Datenbank, die keine Groß- und Kleinschreibung berücksichtigt, kann die erste Abfrage so umgeschrieben werden, dass der Optimierer die Möglichkeit hat, einen Index für "Customers.Surname" zu verwenden.

Standardmäßig führt der Datenbankserver Zeichenfolgenvergleiche ohne Berücksichtigung von Groß- und Kleinschreibung durch, es sei denn, es werden explizite Anweisungen zur Textkonvertierung gegeben (Verwendung von UPPER, UCASE, LOWER oder LCASE). Durch Eliminieren unnötiger Konvertierungen der Groß- und Kleinschreibung können die Prädikate in sargable-Prädikate umgewandelt und dann für Indexabrufe der entsprechenden Tabelle verwendet werden.

Ziehen Sie das Inlining von Funktionen in Erwägung.

Vorher:

CREATE FUNCTION F1( arg1 INT, arg2 INT )
RETURNS INT
BEGIN
 RETURN arg1 * arg2
END;
SELECT F1( e.EmployeeID, 2.5 ) 
FROM Employees e;

Nachher:

SELECT CAST( e.EmployeeID AS INT ) * CAST( 2.5 AS INT ) 
FROM Employees e;

Ein Inlining einer benutzerdefinierten Funktion ist möglich, wenn diese eine der folgenden Voraussetzungen erfüllt:

  • Sie enthält eine einzige RETURN-Anweisung.

  • Sie deklariert eine einzige Variable, weist die Variable zu und gibt einen einzigen Wert zurück.

  • Sie deklariert eine einzige Variable, führt in dieser Variablen eine SELECT-Anweisung aus und gibt einen einzigen Wert zurück.

Dieser Tipp ist nicht anwendbar auf temporäre Funktionen, rekursive Funktionen und Funktionen mit NOT DETERMINISTIC-Klausel.

Außerdem ist dieser Tipp nicht anwendbar, wenn die betreffende Funktion mit einer Unterabfrage als Argument oder aus einer temporären Prozedur heraus aufgerufen wird.

Ziehen Sie das Inlining einfacher gespeicherter Prozeduren in Erwägung.

Vorher:

CREATE PROCEDURE Test1( arg1 INT )
 BEGIN
  SELECT * FROM Employees WHERE EmployeeID=arg1
 END;
SELECT * FROM Test1( 200 );

Nachher:

SELECT * FROM ( 
      SELECT * FROM Employees 
      WHERE EmployeeID=CAST( 200 AS INT ) ) 
   AS Test1;

Das Inlining einer gespeicherten Prozedur ist möglich, wenn diese beim Aufrufen in der FROM-Klausel einer Abfrage nur als eine einzige SELECT-Anweisung festgelegt wird. Wenn eine Prozedur inline ist, wird sie als abgeleitete Tabelle umgeschrieben. Dieser Tipp gilt nicht für Prozeduren, in denen Standardargumente verwendet werden oder deren Hauptteil etwas anderes enthält als eine einzige SELECT-Anweisung.

 Siehe auch