Hintergrund: Professioneller Werkzeugentwickler. SQL/DB-Laie.
Einrichten: .Net 3.5 Winforms-Anwendung, die mit MS SQL Server 2008 kommuniziert.
Szenario: Ich befülle eine Datenbank mit Informationen, die ich aus einer großen Anzahl von Dateien extrahiert habe. Dabei handelt es sich um etwa 60 Millionen Datensätze, denen jeweils eine Nachricht beliebiger Größe zugeordnet ist. Mein ursprünglicher Plan war ein nvarchar(max) Feld im Datensatz, um die Nachrichten zu speichern, aber nach einem Testlauf mit einer Teilmenge der Daten würde dies die Datenbank zu groß machen (hochgerechnet 113 GB). Beim Ausführen einiger Abfragen auf diesem anfänglichen Testdatensatz (1,3 GB Datenbank) entdeckte ich, dass es eine beträchtliche Menge an Nachrichtenduplikaten gab und dass wir dies nutzen konnten, um die Nachrichtendaten auf etwa ein Sechstel zu verkleinern. Ich habe einige Ansätze ausprobiert, um dies zu erreichen, aber keiner war zufriedenstellend. Ich habe jetzt ein paar Tage lang herumgesucht, aber entweder a) scheint es keine gute Antwort zu geben (unwahrscheinlich), oder b) ich weiß nicht, wie ich das, was ich brauche, gut genug ausdrücken kann (wahrscheinlicher).
In Betracht gezogene/erprobte Ansätze:
- Masseneinfügung von Nachrichten in Datensätze mit einer nvarchar(max) Feld. - zu viel Redundanz aufweisen.
- Bleiben Sie bei dieser Meldungsspalte, aber finden Sie einen Weg, die Datenbank dazu zu bringen, die Meldungen zu "komprimieren". - keine Ahnung, wie man das macht.
- Fügen Sie eine Nachrichtentabelle für eindeutige Nachrichten hinzu, deren Schlüssel eine ID ist, auf die der/die Hauptdatensatz/e "zeigen". - funktioniert zwar prinzipiell, aber die Umsetzung der Eindeutigkeit erweist sich als mühsam und verlangsamt sich, wenn mehr Nachrichten hinzugefügt werden.
- Entfernen Sie Duplikate auf dem Client. - erfordert, dass alle Nachrichten für jede Bevölkerungsgruppe an den Kunden weitergeleitet werden. Dies ist nicht skalierbar, da sie in den Speicher passen müssen.
- Hinzufügen einer zusätzlichen (indizierten) Hash-Spalte zur Nachrichtentabelle und Übermittlung der Nachrichten mit einem entsprechenden (lokal erzeugten) Hash-Wert. Suchen Sie danach, um die Nachrichten einzugrenzen, die tatsächlich getestet werden müssen. - kompliziert, es muss einen besseren Weg geben.
Dieser dritte Ansatz läuft auf die Erstellung einer String-Dictionary-Tabelle hinaus. Nach einigen Iterationen dieser Idee kam ich zu folgendem Ergebnis:
-
Die Datenbank hat eine Nachrichtentabelle, die eine (automatisch zugewiesene) int ID Primärschlüssel zu einer nvarchar(max) Nachricht.
-
Der Client stapelt die Nachrichten und übergibt mehrere Datensätze zum Einfügen an eine gespeicherte Prozedur.
-
Die gespeicherte Prozedur iteriert durch den Stapel eingehender Datensätze und für jede Nachricht:
i. Die Tabelle des Nachrichtenverzeichnisses wird auf eine vorhandene Instanz der Nachricht geprüft (SELECT).
ii. Falls gefunden, merken Sie sich die ID der vorhandenen Nachricht.
iii. Wenn nicht gefunden, fügen Sie einen neuen Nachrichtendatensatz ein und merken Sie sich die ID des neuen Datensatzes (OUTPUT).
-
Die IDs für alle Nachrichten (alte und neue) werden als Ergebnismenge von der Prozedur zurückgegeben.
-
Der Client erzeugt die Haupttabellensätze mit Einträgen ( int Fremdschlüssel) für die Nachrichten, die mit den von der Prozedur zurückgegebenen IDs ausgefüllt werden.
Probleme:
- Die Suche nach vorhandenen Nachrichten wird mit zunehmender Anzahl von Nachrichten immer langsamer und wird zum begrenzenden Faktor.
- Ich habe versucht, Indizierung (UNIQUE) die Nachricht Spalte, aber Sie können nicht indexieren eine nvarchar( max ) Spalte.
- Ich habe mir die Volltextsuchfunktionen von MS SQL Server 2008 angesehen, aber das scheint mir zu viel des Guten zu sein.
- Ich habe darüber nachgedacht, zu versuchen, die Nachrichten in Stapeln zusammenzufassen, aber ich sehe keine Möglichkeit, die entsprechende Liste der IDs (alte und neue) leicht zu erhalten, in der richtigen Reihenfolge ) an den Kunden zurückzugeben.
Ich habe den Eindruck, dass ich versuche, eine Art Normalisierung meiner Daten zu erreichen, aber nach meinem Verständnis von Datenbankdesign ist dies eher eine "Zeilennormalisierung" als eine echte Normalisierung, bei der es um eine "Spaltennormalisierung" geht. Ich bin überrascht, dass dies nicht schon überall mit entsprechender Unterstützung benötigt wird.
Meine Frage lautet also: Was ist hier der richtige Ansatz?
Jede Hilfe ist sehr willkommen.
Sam