Was sind die ersten Dinge, die Sie versuchen, wenn Sie eine Abfrage oder eine gespeicherte Prozedur haben, für die eine Leistungsoptimierung erforderlich ist?
Was sind die ersten Dinge, die Sie versuchen, wenn Sie eine Abfrage oder eine gespeicherte Prozedur haben, für die eine Leistungsoptimierung erforderlich ist?
Antworten:
Hier ist die praktische Liste der Dinge, die ich immer jemandem gebe, der mich nach der Optimierung fragt.
Wir verwenden hauptsächlich Sybase, aber die meisten Ratschläge gelten allgemein.
SQL Server enthält zum Beispiel eine Vielzahl von Leistungsüberwachungs- / Optimierungsbits. Wenn Sie jedoch nichts dergleichen haben (und vielleicht sogar, wenn Sie dies tun), würde ich Folgendes in Betracht ziehen ...
99% der Probleme, die ich gesehen habe, werden durch das Einfügen zu vieler Tabellen in einen Join verursacht . Die Lösung hierfür besteht darin, die Hälfte des Joins (mit einigen Tabellen) durchzuführen und die Ergebnisse in einer temporären Tabelle zwischenzuspeichern. Führen Sie dann den Rest der Abfrage aus, die in dieser temporären Tabelle verknüpft ist.
#temp
Tabellen sind möglicherweise viel leistungsfähiger als @table
Variablen mit großen Volumes (Tausende von Zeilen).Etwas abseits des Themas, aber wenn Sie die Kontrolle über diese Probleme haben ...
High Level und High Impact.
CREATE INDEX
Stellen Sie sicher, dass für Sie Indizes verfügbar sind WHERE
und JOIN
Klauseln sind. Dies beschleunigt den Datenzugriff erheblich.
Wenn Ihre Umgebung eine ist Data Mart oder ein Warehouse handelt, sollten für fast alle denkbaren Abfragen zahlreiche Indizes vorhanden sein.
In einer Transaktionsumgebung sollte die Anzahl der Indizes geringer und ihre Definitionen strategischer sein, damit die Indexpflege die Ressourcen nicht belastet. (Bei der Indexpflege müssen die Blätter eines Index geändert werden, um eine Änderung der zugrunde liegenden Tabelle wie bei INSERT, UPDATE,
und widerzuspiegelnDELETE
Operationen .)
Beachten Sie auch die Reihenfolge der Felder im Index - je selektiver (höhere Kardinalität) ein Feld ist, desto früher sollte es im Index erscheinen. Angenommen, Sie fragen nach gebrauchten Autos:
SELECT i.make, i.model, i.price
FROM dbo.inventory i
WHERE i.color = 'red'
AND i.price BETWEEN 15000 AND 18000
Der Preis hat im Allgemeinen eine höhere Kardinalität. Möglicherweise sind nur ein paar Dutzend Farben verfügbar, aber möglicherweise Tausende verschiedener Preisvorstellungen.
idx01
Bietet unter diesen Indexoptionen den schnelleren Pfad, um die Abfrage zu erfüllen:
CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)
Dies liegt daran, dass weniger Autos den Preis erfüllen als die Farbauswahl, sodass die Abfrage-Engine weitaus weniger Daten zu analysieren hat.
Es ist bekannt, dass zwei sehr ähnliche Indizes nur in der Feldreihenfolge unterschiedlich sind, um Abfragen (Vorname, Nachname) in einem und (Nachname, Vorname) in dem anderen zu beschleunigen.
Ein Trick, den ich kürzlich gelernt habe, ist, dass SQL Server sowohl lokale Variablen als auch Felder in einer Update-Anweisung aktualisieren kann.
UPDATE table
SET @variable = column = @variable + otherColumn
Oder die besser lesbare Version:
UPDATE table
SET
@variable = @variable + otherColumn,
column = @variable
Ich habe dies verwendet, um komplizierte Cursor / Joins bei der Implementierung rekursiver Berechnungen zu ersetzen, und habe auch viel an Leistung gewonnen.
Hier sind Details und Beispielcode, die zu fantastischen Leistungsverbesserungen geführt haben: http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal. aspx
Angenommen, MySQL hier, verwenden Sie EXPLAIN, um herauszufinden, was mit der Abfrage passiert, stellen Sie sicher, dass die Indizes so effizient wie möglich verwendet werden, und versuchen Sie, Dateisortierungen zu beseitigen. Hochleistungs-MySQL: Optimierung, Backups, Replikation und mehr ist ein großartiges Buch zu diesem Thema, ebenso wie MySQL Performance Blog .
@ Terrapin Es gibt noch ein paar andere Unterschiede zwischen isnull und coalesce, die erwähnenswert sind (neben der ANSI-Konformität, die für mich sehr wichtig ist).
Wenn Sie in SQL Server ein ODER in einer where-Klausel verwenden, wird die Leistung manchmal erheblich beeinträchtigt. Anstatt den OP zu verwenden, wählen Sie einfach zwei aus und verbinden Sie sie miteinander. Sie erhalten die gleichen Ergebnisse bei 1000-facher Geschwindigkeit.
Ich beginne im Allgemeinen mit den Joins - ich werde jeden einzelnen einzeln aus der Abfrage streichen und die Abfrage erneut ausführen, um eine Vorstellung davon zu bekommen, ob es einen bestimmten Join gibt, mit dem ich ein Problem habe.
In all meinen temporären Tabellen möchte ich (falls zutreffend) eindeutige Einschränkungen hinzufügen, um Indizes und Primärschlüssel (fast immer) zu erstellen.
declare @temp table(
RowID int not null identity(1,1) primary key,
SomeUniqueColumn varchar(25) not null,
SomeNotUniqueColumn varchar(50) null,
unique(SomeUniqueColumn)
)
Ich habe es mir zur Gewohnheit gemacht, immer Bindungsvariablen zu verwenden. Es ist möglich, dass Bindungsvariablen nicht helfen, wenn das RDBMS keine SQL-Anweisungen zwischenspeichert. Wenn Sie jedoch keine Bindevariablen verwenden, hat das RDBMS keine Möglichkeit, Abfrageausführungspläne und analysierte SQL-Anweisungen wiederzuverwenden. Die Einsparungen können enorm sein: http://www.akadia.com/services/ora_bind_variables.html . Ich arbeite hauptsächlich mit Oracle, aber Microsoft SQL Server funktioniert fast genauso.
Nach meiner Erfahrung sind Sie es wahrscheinlich nicht, wenn Sie nicht wissen, ob Sie Bindungsvariablen verwenden oder nicht. Wenn Ihre Anwendungssprache sie nicht unterstützt, suchen Sie eine, die dies unterstützt. Manchmal können Sie Abfrage A beheben, indem Sie Bindungsvariablen für Abfrage B verwenden.
Danach spreche ich mit unserem DBA, um herauszufinden, was das RDBMS am meisten schmerzt. Beachten Sie, dass Sie nicht fragen sollten: "Warum ist diese Abfrage langsam?" Das ist so, als würden Sie Ihren Arzt bitten, Ihren Anhang herauszunehmen. Sicher, Ihre Anfrage könnte das Problem sein, aber es ist genauso wahrscheinlich, dass etwas anderes schief geht. Als Entwickler neigen wir dazu, in Codezeilen zu denken. Wenn eine Linie langsam ist, korrigieren Sie diese Linie. Ein RDBMS ist jedoch ein wirklich kompliziertes System, und Ihre langsame Abfrage kann das Symptom eines viel größeren Problems sein.
Viel zu viele SQL-Tuning-Tipps sind Idole des Frachtkultes. In den meisten Fällen hängt das Problem nicht oder nur minimal mit der von Ihnen verwendeten Syntax zusammen. Daher ist es normalerweise am besten, die sauberste Syntax zu verwenden, die Sie können. Anschließend können Sie nach Möglichkeiten suchen, die Datenbank (nicht die Abfrage) zu optimieren. Passen Sie die Syntax nur an, wenn dies fehlschlägt.
Sammeln Sie wie bei jeder Leistungsoptimierung immer aussagekräftige Statistiken. Verwenden Sie keine Wanduhrzeit, es sei denn, es ist die Benutzererfahrung, die Sie einstellen. Schauen Sie sich stattdessen Dinge wie CPU-Zeit, abgerufene Zeilen und von der Festplatte abgelesene Blöcke an. Zu oft optimieren die Leute für das Falsche.
Das Ausführen der Abfrage mit WITH (NoLock) ist an meiner Stelle so ziemlich Standard. Jeder, der beim Ausführen von Abfragen an den 10-Gigabyte-Tabellen erwischt wurde, ohne dass diese herausgenommen und erschossen wurden.
Konvertieren Sie NOT IN-Abfragen nach Möglichkeit in LEFT OUTER JOINS. Wenn Sie beispielsweise alle Zeilen in Tabelle 1 suchen möchten, die von einem Fremdschlüssel in Tabelle 2 nicht verwendet werden, können Sie Folgendes tun:
SELECT *
FROM Table1
WHERE Table1.ID NOT IN (
SELECT Table1ID
FROM Table2)
Aber Sie erhalten damit eine viel bessere Leistung:
SELECT Table1.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.Table1ID
WHERE Table2.ID is null
@ DavidM
Angenommen, MySQL hier, verwenden Sie EXPLAIN, um herauszufinden, was mit der Abfrage los ist, und stellen Sie sicher, dass die Indizes so effizient wie möglich verwendet werden ...
In SQL Server erhalten Sie mit dem Ausführungsplan dasselbe: Er zeigt Ihnen, welche Indizes betroffen sind usw.
Nicht unbedingt ein SQL-Leistungstrick an sich, aber definitiv verwandt:
Eine gute Idee wäre, wenn möglich memcached zu verwenden, da es viel schneller wäre, die vorkompilierten Daten direkt aus dem Speicher abzurufen, als sie aus der Datenbank abzurufen. Es gibt auch eine Variante von MySQL, die in Memcached integriert wurde (von Drittanbietern).
Stellen Sie sicher, dass Ihre Indexlängen so klein wie möglich sind. Auf diese Weise kann die Datenbank mehr Schlüssel gleichzeitig aus dem Dateisystem lesen und so Ihre Joins beschleunigen. Ich gehe davon aus, dass dies mit allen DBs funktioniert, aber ich weiß, dass dies eine spezifische Empfehlung für MySQL ist.
Ich achte auf:
SET NOCOUNT ON
Normalerweise die erste Zeile in meinen gespeicherten Prozeduren, es sei denn, ich muss sie tatsächlich verwenden @@ROWCOUNT
.
Verwenden Sie in SQL Server die Anweisung nolock. Damit kann der Befehl select ausgeführt werden, ohne warten zu müssen - normalerweise werden andere Transaktionen abgeschlossen.
SELECT * FROM Orders (nolock) where UserName = 'momma'
Entfernen Sie die Cursor überall dort, wo dies nicht erforderlich ist.
Entfernen Sie Funktionsaufrufe in Sprocs, in denen viele Zeilen die Funktion aufrufen.
Mein Kollege verwendete Funktionsaufrufe (als Beispiel lastlogindate von userid), um sehr breite Datensätze zurückzugeben.
Mit der Optimierung beauftragt, habe ich die Funktionsaufrufe im Sproc durch den Funktionscode ersetzt: Ich habe die Laufzeit vieler Sprocs von> 20 Sekunden auf <1 gesenkt.
Ich benutze gerne
isnull(SomeColThatMayBeNull, '')
Über
coalesce(SomeColThatMayBeNull, '')
Wenn ich die Unterstützung mehrerer Argumente, die Ihnen die Koaleszenz bietet, nicht benötige.
http://blog.falafel.com/2006/04/05/SQLServerArcanaISNULLVsCOALESCE.aspx
Stellen Sie gespeicherten Prozedurnamen nicht "sp_" voran, da alle Systemprozeduren mit "sp_" beginnen und SQL Server beim Aufrufen Ihrer Prozedur härter suchen muss, um Ihre Prozedur zu finden.
set transaction isolation level read uncommitted
Verhindert tote Sperren, bei denen die Transaktionsintegrität nicht unbedingt erforderlich ist (was normalerweise der Fall ist).
Ich gehe immer zuerst zum SQL Profiler (wenn es sich um eine gespeicherte Prozedur mit vielen Verschachtelungsebenen handelt) oder zum Abfrageausführungsplaner (wenn es sich um einige SQL-Anweisungen ohne Verschachtelung handelt). In 90% der Fälle können Sie das Problem sofort mit einem dieser beiden Tools finden.