Flag vs Tabelle geteilt

9

Ich entwerfe eine Tabelle mit Elementen, die (möglicherweise) mehrere zehn Millionen Datensätze enthalten. Einige Elemente können erst verwendet werden, wenn sie vom Administrator "genehmigt" wurden. Mit "Verwendung" meine ich, dass solche Elemente in keiner anderen Tabelle referenziert werden, bis sie "genehmigt" sind. Bis zu 50% der Artikel können zu einem bestimmten Zeitpunkt "nicht genehmigt" werden. Aufzeichnungen können "genehmigt" werden, aber nicht umgekehrt.

Ich betrachte zwei Gestaltungsmöglichkeiten:

  • ein bisschen Flagge
  • eine separate Tabelle mit "nicht genehmigten" Artikeln - wenn der Artikel genehmigt wird, wird er in die "normale" Tabelle verschoben (die Erneuerung der Artikel-ID ist kein Problem).

Ich denke, die zweite Option ist viel besser. Das Bit-Flag benötigt nur ein Byte pro Zeile, ist also kein Problem. Wenn wir jedoch eine Million genehmigter und eine Million nicht genehmigter Datensätze in derselben Tabelle haben, erhöht sich die Scanzeit für Vorgänge mit genehmigten Datensätzen.

Die Frage ist: Sollte ich stattdessen die erste Option (Bit-Flag) in Betracht ziehen? Hat es in der beschriebenen Situation irgendwelche Vorteile?

Dima
quelle
1
Es kann hilfreich sein, sich daran zu erinnern, dass Sie gefilterte Indizes verwenden können, um den Zugriff auf die genehmigten Datensätze zu beschleunigen. brentozar.com/archive/2013/11/…
Mendosi
Leider werden gefilterte Indizes in parametrisierten Abfragen nicht verwendet.
Dima
@ Dima das stimmt nicht ganz. Wenn ein gefilterter Index das Sagen hat WHERE status='A'und eine Abfrage das Sagen hat WHERE status = 'A' AND (... other columns and parameters here...), wird der Index möglicherweise weiterhin verwendet.
Ypercubeᵀᴹ

Antworten:

6

Sie können es mit partitionierten Ansichten in beide Richtungen verwenden .

Sie erstellen für jeden Status eine zugrunde liegende Tabelle, die durch Einschränkungen erzwungen wird, mit sich gegenseitig ausschließenden Werten. Dann eine Ansicht, die UNIONs die zugrunde liegenden Tabellen zusammenfasst. Auf die Ansicht oder jede Basistabelle kann explizit verwiesen werden. Wenn der Status einer Zeile in der Ansicht UPDATEd ist, löscht das DBMS ihn aus einer Basistabelle und fügt ihn in die dem neuen Status entsprechende ein. Jede Basistabelle kann unabhängig von ihrem Verwendungsmuster indiziert werden. Der Optimierer löst Indexreferenzen in eine einzelne entsprechende Basistabelle auf, wenn dies möglich ist.

Die Vorteile sind
a) flachere Indizes. Rechnen Sie jedoch mit dem Index-Fan-Out. Bei dieser Skalierung und Aufteilung zwischen Ihren Statuswerten ist es möglich, dass die Indizes in den aufgeteilten Tabellen dieselbe Tiefe haben wie in der kombinierten Tabelle.
b) Es muss kein Anwendungscode geändert werden. Die Daten erscheinen weiterhin als fortlaufendes Ganzes.
c) Zukünftige neue Statuswerte können durch Hinzufügen einer neuen Basistabelle mit Einschränkungen und erneutes Erstellen der Ansicht aufgenommen werden.

Die Kosten sind all diese Datenbewegungen; Für jede Statusaktualisierung werden zwei Seiten und zugehörige Indizes geschrieben. Es gibt viel zu tun. So viel Bewegung wird auch zu Fragmentierung führen.

Michael Green
quelle
5

eine Tabelle mit Elementen, die (möglicherweise) mehrere zehn Millionen Datensätze enthalten.

Das ist eigentlich nicht so viel, wenn man bedenkt, was SQL Server effizient handhaben kann. Natürlich erinnere ich mich an einen meiner früheren Jobs, bei dem eine der größten Tabellen (ein Einzelinstanzsystem) 2 Millionen Zeilen hatte und das war der größte, mit dem ich mich jemals befasst hatte. Dann hatte der nächste Job 17 Produktionsinstanzen mit einigen Tabellen mit Hunderten von Millionen Zeilen, und alle wurden zu einem Data Warehouse mit mehreren Faktentabellen mit über 1 Milliarde Zeilen zusammengefasst. Verstehen Sie mich nicht falsch, ich verspotte nicht zig Millionen Zeilen, ich betone nur, dass SQL Server mit einem guten Datenmodell und einer ordnungsgemäßen Indizierung (und Indexpflege) viel kann .

Bis zu 50% der Artikel können zu einem bestimmten Zeitpunkt "nicht genehmigt" werden.

Hmm. Das klingt nicht richtig. Die Rate der "Genehmigungen" von Einträgen ist halb so hoch wie die Rate, neue Einträge zu erhalten? Für jeweils 2 neue Einträge wird nur 1 "genehmigt"? In Ihrem Beispiel von 2 Millionen Zeilen und jeweils 1 Million für "genehmigt" und "nicht genehmigt" erwarten Sie einige Jahre später mit weiteren 10 Millionen Einträgen jeweils 6 Millionen für "genehmigt" und "nicht genehmigt"? Oder ist es so, dass die 1 Million "nicht genehmigten" etwas konstant bleiben, so dass bei 10 Millionen neuen Einträgen 11 Millionen "genehmigt" und immer noch 1 Million "nicht genehmigt" sein werden?

Aufzeichnungen können "genehmigt" werden, aber nicht umgekehrt.

Das ist wahr heute , aber die Dinge ändern sich im Laufe der Zeit und so besteht immer die Möglichkeit, dass das Unternehmen beschließt, "nicht genehmigen" oder vielleicht einen anderen Status wie "archiviert" usw. Zuzulassen.

Schauen wir uns also die Auswahlmöglichkeiten an:

Flag (oder möglicherweise sogar TINYINT"Status")

  • Etwas langsamer für Abfragen jedes Status
  • Im Laufe der Zeit flexibler / einfach, eine Änderung wie einen dritten Status (z. B. "Archiviert") mit nur einem neuen Lookup-Statuswert zu integrieren. Keine neue Tabelle (unbedingt), neuer Code, nur aktualisierter Code.
  • Weniger Arbeit (z. B. Code, Tests usw.) und weniger Raum für Fehler beim Aktualisieren einer einzelnen TINYINTSpalte
  • Weniger kompliziert = geringere Wartungskosten im Laufe der Zeit, kürzere Schulungszeit für neue Mitarbeiter
  • (möglicherweise) Geringere Auswirkungen auf das Transaktionsprotokoll, wenn eine Tabelle aktualisiert wird
  • Benötigen Sie nur eine Nachschlagetabelle für "RecordStatus" und FK zwischen den beiden Tabellen.

Zwei separate Tabellen (eine für "genehmigt", eine für "nicht genehmigt")

  • Etwas schneller für Abfragen zu jedem Status
  • Im Laufe der Zeit weniger flexibel / schwieriger, Änderungen wie einen dritten Status (z. B. "Archiviert") zu berücksichtigen; Ein neuer Status würde höchstwahrscheinlich eine andere Tabelle und definitiv neuen und aktualisierten Code erfordern.
  • Mehr Arbeit (z. B. Code, Tests usw.) und mehr Raum für Fehler beim Verschieben von Datensätzen von der Tabelle "Nicht genehmigt" in die Tabelle "Genehmigt"
  • Komplizierter = höhere Wartungskosten im Laufe der Zeit, längere Schulungszeit für neue Mitarbeiter
  • (möglicherweise) Größere Auswirkung auf das Transaktionsprotokoll, wenn eine Tabelle gelöscht und eine eingefügt wird
  • Kein Grund zur Sorge über „ Erneuerung des Artikels ID “: Unapproved Tabelle hat ID - Spalte , die eine ist IDENTITYSpalte und Approved Tabelle hat Spalten - ID , die ist nicht ein IDENTITY(da es nicht benötigt wird). Daher bleiben die ID-Werte konsistent, wenn sich der Datensatz zwischen Tabellen bewegt.

Persönlich würde ich mich zunächst zu der einzelnen Tabelle mit der StatusIDSpalte beugen. Die Verwendung von zwei Tabellen scheint eine überkomplizierte, vorzeitige Optimierung zu sein. Diese Art der Optimierung kann diskutiert werden, wenn die Anzahl der Datensätze mehrere Hundert Millionen beträgt und die Indizierung keine Leistungssteigerungen bringt.

Solomon Rutzky
quelle
Es ist eine Tabelle mit sich schnell bewegenden Daten: Sehr oft mit vielen neuen Zeilen gefüllt, werden häufig Zeilen gelöscht. Ich habe versucht, alle Details (wie Geschäftsentscheidung, Kundencodierung usw.) zu entfernen, um mich nur auf ein einziges Thema zu konzentrieren. Grundsätzlich haben wir die Tabelle des alten Designs mit einer kleinen Flagge. Und ich weiß zu 100%, dass Zeilen, in denen das Flag auf 1 gesetzt ist, in keiner anderen Tabelle verwendet werden. Ich habe das Gefühl, dass sie nur dort stattfinden und möglicherweise an einen separaten Tisch verschoben werden. Die Tabelle wird fast bei jeder Abfrage an die Datenbank gescannt. Eine Reduzierung des "Gewichts" kann also möglicherweise die CPU / IO-Operationen reduzieren.
Dima
3
Ein weiterer Vorteil der geteilten Tabellen: Sie können FKs haben, die nur auf die Tabelle "Genehmigt" verweisen.
Ypercubeᵀᴹ
Das andere Problem bei geteilten Tabellen für eine einzelne Entität ist die Integrität von Einschränkungen. Referenzen von anderen Tischen werden nicht gut abgespielt, wenn sich die Aufzeichnung bewegt. Dazu muss Code geschrieben werden, um diese Probleme zu
umgehen,