Was passiert bei „großen“ Einfügungen in eine Tabelle mit einem zusammengesetzten Clusterschlüssel?

8

Meine SQL-Kenntnisse sind begrenzt, daher sind die Begriffe, die ich verwenden werde, höchstwahrscheinlich nicht die richtigen.

Ich habe eine Tabelle, in der Testergebnisse für mehrere Standorte gespeichert werden.

Die Tests werden in verschiedenen Datenbanken an verschiedenen Standorten aufgezeichnet (keine Netzwerkverbindung) und der "Master" -Standort "importiert" regelmäßig die Testergebnisse von den anderen Standorten.

Ich plane, einen zusammengesetzten Cluster-Primärschlüssel für die Spalten LocationId (int) und Date (datetime) in dieser Reihenfolge zu verwenden. Der Grund dafür ist, dass alle Ergebnisse für einen Standort zusammengehalten werden sollen, und ich werde fast nie eine Abfrage nach Datumsbereich, sondern nach Datumsbereich und Standort durchführen.

Die Zeilengröße beträgt 80 bis 100 Byte, und die Anzahl der Testergebnisse sollte einige Millionen nicht überschreiten. Bei einem typischen "Import" werden 50 bis 100.000 Ergebnisse von einem anderen Speicherort eingefügt.

Was passiert beim Import? Wird SQL die vorhandenen Zeilen "verschieben", um das Clustering beizubehalten, oder wird die Tabelle "fragmentiert"? Könnte dies zu einem großen Leistungseinbruch führen, wenn der Import zeilenweise erfolgt? Sollte ich mich lieber nicht um die Reihenfolge der Zeilen kümmern und einfach eine Identitätsspalte als Primärschlüssel und einen Index für die Datumsspalte hinzufügen, um bei meinen Abfragen zu helfen?

Sacha K.
quelle

Antworten:

19

Heilige Kuh, hier hast du viele Fragen. Lassen Sie uns das zusammenfassen.

F: Wird SQL die vorhandenen Zeilen "verschieben", um das Clustering beizubehalten, oder wird die Tabelle "fragmentiert"?

Stellen Sie sich eine Datenbank als eine Sammlung von Seiten vor - wörtliche Zettel, die auf Ihrem Schreibtisch liegen. Denken Sie jetzt an das Wörterbuch. Wenn Sie dem Wörterbuch weitere Wörter hinzufügen möchten, können Sie diese an Ort und Stelle hinzufügen, wenn die Seiten leer sind.

Wenn Sie zum ersten Mal mit einem leeren Wörterbuch beginnen, ist dies relativ einfach. Aber denken Sie an ein ausgereiftes Wörterbuch mit Tausenden von Papierseiten, die alle voll sind.

Wenn Sie diesem ausgereiften Wörterbuch weitere Wörter hinzufügen möchten, ist wahrscheinlich kein Platz mehr auf der Seite vorhanden. SQL Server "zerreißt" eine Seite - es nimmt eine brandneue Seite an eine andere Stelle und verschiebt einige der Wörter auf diese neue Seite. Die neue Seite befindet sich am Ende des Wörterbuchs. Die gute Nachricht ist, dass unmittelbar nach dieser Aktion eine halb leere Seite am Ende Ihres Wörterbuchs und auch in der Mitte angezeigt wird, beide mit Platz zum Hinzufügen von Wörtern.

Wenn Sie sie zufällig in dieser Reihenfolge hinzufügen, ist das so. (Aus diesem Grund wird die Art und Weise, wie Sie Daten laden, immer wichtiger.)

Könnte dies zu einem großen Leistungseinbruch führen, wenn der Import zeilenweise erfolgt?

Vergessen Sie den Index für eine Sekunde - das Hinzufügen von Daten zeilenweise ist unabhängig von der Indizierungsstruktur einfach ineffizient. SQL Server ist ein satzbasiertes System. Wann immer Sie in Sätzen arbeiten können, sollten Sie dies wahrscheinlich tun.

Was passiert, wenn ich die Daten abfrage?

Du hast das nicht gefragt, aber ich frage es für dich, hahaha.

Denken Sie an die Folgen unserer Beilagen zurück. Jetzt haben wir ein Wörterbuch, das meistens geordnet ist, aber wenn Sie zu einigen Punkten des Wörterbuchs gelangen, müssen Sie nach hinten springen, um von einigen anderen Seiten zu lesen. Wenn diese Seiten alle in Ihrem Speicher zwischengespeichert sind (RAM, Pufferpool usw.), wird der Overhead einfach nicht so groß sein. Der meiste Speicherzugriff erfolgt ohnehin zufällig - es ist nicht so, dass SQL Server Ihr Wörterbuch der Reihe nach im Speicher speichert.

Wenn Sie andererseits die Daten von herkömmlichen magnetischen Festplatten abrufen müssen (Spinnrost), können Sie einen Leistungsvorteil erzielen, wenn diese Daten in der richtigen Reihenfolge gespeichert werden. Das eigentliche Entwurfsziel hierbei ist jedoch, die Daten aus dem RAM abzurufen, anstatt sie von Laufwerken abzurufen. Der Unterschied zwischen defragmentierten Daten auf der Festplatte und fragmentierten Daten auf der Festplatte ist bei weitem nicht so groß wie der Unterschied zwischen dem Abrufen von der Festplatte und dem Abrufen aus dem RAM .

Sollte ich mich lieber nicht um die Reihenfolge der Zeilen kümmern und einfach eine Identitätsspalte als Primärschlüssel und einen Index für die Datumsspalte hinzufügen, um bei meinen Abfragen zu helfen?

Bingo: Dies ist der Unterschied zwischen physischem Datenbankdesign und logischem Datenbankdesign. Programmierer müssen sich anfangs viel um das physische Datenbankdesign kümmern, aber solange Ihre Datenbank beispielsweise weniger als 100 GB groß ist, können Sie das logische Design sozusagen per Post korrigieren. Legen Sie dort zunächst ein Identitätsfeld an, gruppieren Sie es und überprüfen Sie das Indexdesign nach einigen Monaten erneut, um die Leistung zu maximieren.

Nachdem Sie jedoch mit dieser Art der Entscheidungsfindung vertraut sind, sind Sie von Anfang an besser in der Lage, Indizes zu schätzen. Trotzdem denke ich anfangs normalerweise nicht viel über Indexdesign nach. Benutzer scheinen die Daten nie so abzufragen, wie ich es erwartet hätte.

Brent Ozar
quelle
1
Die eins nach der anderen Beilage war eine theoretische Frage. In Bezug auf die Leistung erschien mir zweifelhaft, dass "Zeilen physisch in derselben Reihenfolge wie der Clustered-Index auf der Festplatte gespeichert werden", wie Sie es an den meisten Stellen gelesen haben.
Sacha K
Ich werde für eine Identitätsspalte gehen. Die Daten werden "am Ende" hinzugefügt und natürlich nach Datum sortiert. Gleiche Daten für verschiedene Standorte werden nicht "nahe beieinander" sein, aber das ist mir überhaupt nicht wichtig.
Sacha K