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 basename
Spalte.
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 filename
maximale 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_status
Wahrscheinlich 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.
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?
quelle
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
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.
quelle
id
Nummer im Voraus kennen? Sie müssten das irgendwie in der Tabelle nachschlagen.SELECT 1
eine Möglichkeit zur weiteren Optimierung nutzen. Dasbasename
steht in derWHERE...
Klausel und wird von einem Ordner-Watchdog abgerufen (ich erhalte das Ereignis einer Datei, die in den Ordner kopiert wurde, den ich gerade beobachte).SELECT 1
,SELECT id
, Es spielt keine Rolle , wenn(id)
der Clustered - Index ist. Dasid
ist sowieso in jedem nicht gruppierten Index enthalten.