Angemessene Möglichkeit, die Abfrageleistung im Laufe der Zeit vorherzusagen

7

Ich habe eine SQL Server 2012-Datenbank, mit der ich Daten aus verarbeiteten Dateien speichere. Wir lesen Daten aus einem Ordner, verarbeiten sie mit Python und speichern die Ergebnisse in der Datenbank.

Eines der ersten Dinge, die wir in unserem ETL-Prozess tun, ist zu überprüfen, ob die Datei bereits verarbeitet wurde. Wir machen einfach ein:

SELECT id FROM table1 WHERE basename = <basename>

Wenn es ein Ergebnis gibt, überspringen wir die Datei, wenn es kein Ergebnis gibt, verarbeiten wir die Datei. Im Moment dauert diese Abfrage ~ 250ms mit ~ 5m Datensätzen. Wir haben bereits einen nicht gruppierten Index für die basenameSpalte.

Wir werden ungefähr 100-200.000 Datensätze pro Monat hinzufügen. Wir bekommen die Dateien in Stapeln. Wir sehen also möglicherweise 2k-Dateien und 2 Stunden später weitere 2k-Dateien. An manchen Tagen erhalten wir 10.000 Dateien, an anderen Tagen erhalten wir möglicherweise nur 4.000 Dateien.

Wenn alle anderen Variablen gleich bleiben, gibt es eine Faustregel für die Projektion, wenn bei dieser Abfrage Leistungsprobleme auftreten (Abfragen, die länger als 1 Sekunde dauern), außer 15 bis 20 Millionen Datensätze in die Tabelle einzufügen und zu sehen, was passiert?

Tabelle DDL:

CREATE TABLE [dbo].[raw_records](
[id] [int] IDENTITY(1,1) NOT NULL,
[basename] [varchar](512) NULL,
[filename] [varchar](1024) NULL,
[file_size] [int] NULL,
[machine] [varchar](10) NULL,
[insert_timestamp] [datetime] NULL,
[raw_xml] [xml] NULL,
[process_status] [varchar](2048) NULL,

PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

Index:

CREATE NONCLUSTERED INDEX [basename_index] ON [dbo].[raw_records]
(
    [basename] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

Diese Tabelle wurde lange vor Beginn meiner Arbeit erstellt. Ich gehe also davon aus, dass jemand gerade die filenamemaximale Länge von 1024 festgelegt hat, um "genug" zu halten. Sicher veränderbar.

Die erstellten Dateien haben einen Zeitstempel und eindeutige Informationen im Dateinamen selbst (z. B. system1_metadata_timestamp.xml) ein "System" konnte (oder sollte) niemals eine Datei mit demselben Zeitstempel erstellen.

select max(len(basename)), max(len(filename)) from dbo.raw_records;

Rückgabe: basename- 143, filename- 168. Wahrscheinlich eine gute Sache, um auf maximal 260 zu wechseln.

process_statusWahrscheinlich muss es auch nicht so lange dauern, aber ich halte es für vernünftig, dies zu erraten, da die Spalte Fehlermeldungen aus der Verarbeitungsphase enthält. Ich habe eine Abfrage ausgeführt und hatte maximal 600 Zeichen. Wir fragen diese Spalte jedoch normalerweise nicht ab. Es ist nur informativer für das Debuggen.

Ich gehe die Anwendung durch, um solche Sachen aufzuräumen. An bestimmten Stellen komme ich nicht davon weg, aber an anderen kann ich leider nicht viel dagegen tun (z. B. muss die XML-Spalte tatsächlich abgerufen werden, um Daten daraus zu extrahieren). Diese Frage ergab sich einfach daraus, dass ich die Leistung der fraglichen Abfrage gesehen habe und nicht wollte, dass sie mir entgeht. Es ist das erste, was für jede Datei ausgeführt wird. Wenn dies nicht funktioniert, wird auch nichts anderes ausgeführt.

Kevin Vasko
quelle

Antworten:

12

Wenn ein guter Index vorhanden ist, sollte die Zeit, die zum Auffinden einer passenden Zeile benötigt wird, ungefähr logarithmisch skaliert werden, solange Sie Platz für den Index im Speicher haben.

Ich würde den Index UNIQUEerstellen, da der Basisname eindeutig sein muss, da sonst Ihr Workflow ungültig ist und der Index effizienter wird.

CREATE UNIQUE INDEX IX_raw_records_basename
ON dbo.raw_records (basename);

Überprüfen Sie den Ausführungsplan für die Abfrage, um sicherzustellen, dass der Index verwendet wird.

Stellen Sie sicher, dass genügend Speicherplatz für den Index vorhanden ist. Wenn die Parallelität kein großes Problem darstellt, sollten Sie für eine sehr große Anzahl von Zeilen geeignet sein.

Ich würde die Länge der Spalten basenameund erneut überdenken, filenameda das Abfrageoptimierungsprogramm die Länge verwendet, um zu berechnen, wie viel Speicher zum Ausführen der Abfrage zugewiesen werden muss. Wenn die basenameSpalte beispielsweise nie mehr als 20 Zeichen enthält, Sie sie jedoch als 512 Zeichen definiert haben, ist die Speicherzuweisung für SELECT basename FROM dbo.raw_records;25,6-mal höher als tatsächlich erforderlich. Spaltenlängen sind tatsächlich viel wichtiger als die meisten Menschen erkennen.

Sie können die Abfrage auch so ändern, SELECT 1 FROM table1 WHERE basename = <basename>dass Sie sie nicht einmal benötigen, idda Sie nur versuchen, ihre Existenz zu überprüfen. Tun Sie nur das, was Sie wirklich brauchen. Es sieht so aus, als würde der Index, den Sie in Ihrer Frage anzeigen, dafür gut funktionieren.

Max Vernon
quelle
1
Ich habe das gute Gefühl, dass die Person, die daran gearbeitet hat, dies ursprünglich gefunden hat. stackoverflow.com/questions/4377740/…
Kevin Vasko
Ich bin nicht sicher, ob der Workflow ungültig ist, wenn jede Datei zu mehreren Zeilen führt, solange eine gesamte Datei in einer einzelnen Transaktion geladen wird (sodass eine ganze Datei entweder geladen wird oder fehlschlägt).
jpmc26
Wenn Speicherplatz ein Problem darstellt, sollten Sie außerdem die Datenkomprimierung des Index und / oder der Basistabelle in Betracht ziehen. Dies sollte es dem Index ermöglichen, in einen kleineren Speicherbedarf zu passen. Sie müssten überprüfen, ob die ROW- oder PAGE-Komprimierung besser ist oder nicht
Steve
0

Behandle es so, wie es ist ... Ein Inszenierungstisch. Landen Sie die Datendateien dort gerade lange genug, um den ETL-Prozess abzuschließen und dann die Tabelle abzuschneiden. Behalten Sie einfach den Dateinamen und das Datum in einer "FileProcessLog" -Tabelle, damit Sie aufzeichnen können, welche Dateien verarbeitet wurden, wann sie verarbeitet wurden und wie lange es gedauert hat. Die tatsächlichen Rohdateien langfristig in Ihrer Datenbank zu belassen, wird kein Kummer sein ... Möchten Sie wirklich Terabytes archivierter Dateien in alle nächtlichen Backups einbeziehen?

Jason A. Long
quelle
Ich möchte die Tabelle nicht abschneiden. Ja, ich könnte einen Verweis auf die Dateien speichern, aber diese Dateien sind im Durchschnitt nur ~ 3 KB groß, sodass das Speichern im Dateisystem keinen signifikanten Vorteil bietet (z. B. Bilder oder andere Binärdaten). Die überwiegende Mehrheit von ihnen ist nur 1-2KB. Die XML-Daten werden verarbeitet und in einer verarbeiteten Tabelle gespeichert. In dieser Tabelle werden alle Daten gespeichert, die wir für die Wiederaufbereitung nach Bedarf haben, da es Zeiten gibt, in denen Benutzer die Art und Weise optimieren möchten, in der die Daten übersetzt werden sollen. Wir sprechen auch nur von 10-15 GB Daten für Daten im Wert von einem Jahr.
Kevin Vasko
Ich werde immer etwas unruhig, wenn ich XML- und große VARCHAR-, NVARCHAR- und BINARY-Datentypen sehe, da immer das Potenzial besteht, große Datenmengen in sie zu packen (2 Gigs für XML und einen der "MAX" -Datentypen). ... Das heißt, 10 - 15 Gigs pro Jahr sind immer noch kein Grund zum Niesen. Wenn ich in dieser Angelegenheit die Wahl habe, würde ich es vorziehen, inaktive Dateien auf einem Dateiserver zu speichern, als sie in meiner Datenbank zu behalten. Ich werde in der Datenbank aufzeichnen, wo sie sich befinden, falls ich sie später benötige, aber ich möchte sie lieber nicht in meine geplante DB-Wartungsarbeit aufnehmen ...
Jason A. Long
-4

Wie bekommst du Parameter, mit denen du abfragst? Es ist effektiver, wenn Sie Ihre Abfragen basierend auf int-Spalten und nicht varchar ausführen können. Auch wenn Sie nur an der Existenz einer solchen Zeile in Ihrer Tabelle interessiert sind, können Sie Ihre Abfrage in ändern

SELECT 1 FROM table1 WHERE id = <id>

In diesem Fall müssen Sie nicht mehr Spalten in den Index aufnehmen, damit weniger Speicher benötigt wird und eine bessere Leistung erzielt wird.

Artashes Khachatryan
quelle
1
Wie würde das OP die idNummer im Voraus kennen? Sie müssten das irgendwie in der Tabelle nachschlagen.
Max Vernon
Der entscheidende Punkt der Antwort, wenn es möglich ist. Aber selbst wenn dies nicht der Fall ist, können sie nur 1 anstelle der ID auswählen und die ID in den Index aufnehmen.
Artashes Khachatryan
Ich kann SELECT 1eine Möglichkeit zur weiteren Optimierung nutzen. Das basenamesteht in der WHERE...Klausel und wird von einem Ordner-Watchdog abgerufen (ich erhalte das Ereignis einer Datei, die in den Ordner kopiert wurde, den ich gerade beobachte).
Kevin Vasko
5
SELECT 1, SELECT id, Es spielt keine Rolle , wenn (id)der Clustered - Index ist. Das idist sowieso in jedem nicht gruppierten Index enthalten.
Ypercubeᵀᴹ