Innerhalb einer Webanwendung, an der ich arbeite, werden alle Datenbankvorgänge mithilfe einiger über Entity Framework ORM definierter generischer Repositorys abstrahiert.
Um jedoch ein einfaches Design für die generischen Repositorys zu haben, müssen alle beteiligten Tabellen eine eindeutige Ganzzahl definieren ( Int32
in C #, int
in SQL). Bisher war dies immer der PK des Tisches und auch der IDENTITY
.
Fremdschlüssel werden häufig verwendet und verweisen auf diese ganzzahligen Spalten. Sie sind sowohl für die Konsistenz als auch für die Generierung von Navigationseigenschaften durch den ORM erforderlich.
Die Anwendungsschicht führt normalerweise die folgenden Vorgänge aus:
- Erstes Laden der Daten aus der Tabelle (*) -
SELECT * FROM table
- Update -
UPDATE table SET Col1 = Val1 WHERE Id = IdVal
- Löschen -
DELETE FROM table WHERE Id = IdVal
- Einfügen -
INSERT INTO table (cols) VALUES (...)
Weniger häufige Operationen:
- Masseneinfügung -
BULK INSERT ... into table
gefolgt von (*) allen Datenladevorgängen (um generierte Bezeichner abzurufen) - Massenlöschung - Dies ist eine normale Löschoperation, aus Sicht von ORM jedoch "voluminös":
DELETE FROM table where OtherThanIdCol = SomeValue
- Massenaktualisierung - Dies ist ein normaler Aktualisierungsvorgang, aus Sicht von ORM jedoch "umfangreich":
UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue
* Alle kleinen Tabellen werden auf Anwendungsebene zwischengespeichert und fast alle SELECTs
erreichen die Datenbank nicht. Ein typisches Muster ist die Anfangslast und viele INSERT
s, UPDATE
s und DELETE
s.
Aufgrund der aktuellen Anwendungsnutzung ist die Wahrscheinlichkeit sehr gering, dass jemals 100 Millionen Datensätze in einer der Tabellen erreicht werden.
Frage: Gibt es aus Sicht eines Datenbankadministrators erhebliche Probleme, die durch diese Einschränkung des Tabellenentwurfs auftreten können?
[BEARBEITEN]
Nach dem Lesen der Antworten (danke für das großartige Feedback) und der Artikel, auf die verwiesen wird, muss ich weitere Details hinzufügen:
Aktuelle Anwendungsspezifikationen - Ich habe die aktuelle Webanwendung nicht erwähnt, da ich verstehen möchte, ob das Modell auch für andere Anwendungen wiederverwendet werden kann. In meinem speziellen Fall handelt es sich jedoch um eine Anwendung, die viele Metadaten aus einem DWH extrahiert. Quelldaten sind ziemlich unübersichtlich (auf seltsame Weise denormalisiert, haben einige Inkonsistenzen, in vielen Fällen keine natürliche Kennung usw.) und meine App generiert klar getrennte Entitäten. Außerdem werden viele der generierten Bezeichner (
IDENTITY
) angezeigt, damit der Benutzer sie als Geschäftsschlüssel verwenden kann. Dies schließt neben einem massiven Code-Refactoring die Verwendung von GUIDs aus ."Sie sollten nicht die einzige Möglichkeit sein, eine Zeile eindeutig zu identifizieren" (Aaron Bertrand ♦) - das ist ein sehr guter Rat. Alle meine Tabellen definieren auch einen EINZIGARTIGEN KONSTRAINT, um sicherzustellen, dass Geschäftsduplikate nicht zulässig sind.
Front-End-App-gesteuertes Design im Vergleich zum datenbankgesteuerten Design - die Auswahl des Designs wird durch diese Faktoren verursacht
Entity Framework-Einschränkungen - PKs mit mehreren Spalten sind zulässig, ihre Werte können jedoch nicht aktualisiert werden
Benutzerdefinierte Einschränkungen : Durch die Verwendung eines einzelnen Ganzzahlschlüssels werden Datenstrukturen und Nicht-SQL-Code erheblich vereinfacht. Beispiel: Alle Wertelisten haben einen Integer-Schlüssel und einen angezeigten Wert. Noch wichtiger ist, dass jede zum Cachen markierte Tabelle in der Lage ist, eine
Unique int key -> value
Karte zu erstellen .
Komplexe Auswahlabfragen - dies wird so gut wie nie vorkommen, da alle kleinen Tabellendaten (<20-30 KB) auf Anwendungsebene zwischengespeichert werden. Dies macht das Leben ein wenig schwieriger beim Schreiben von Anwendungscode (schwieriger beim Schreiben von LINQ), aber die Datenbank wird viel besser getroffen:
Listenansichten - erzeugen
SELECT
beim Laden keine Abfragen (alles wird zwischengespeichert) oder Abfragen, die so aussehen:SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)
Alle anderen erforderlichen Werte werden über Cache-Lookups (O (1)) abgerufen, sodass keine komplexen Abfragen generiert werden.
Ansichten bearbeiten - erzeugt
SELECT
Anweisungen wie diese:SELECT allcolumns FROM BigTable WHERE PKId = value1
(alle Filter und Werte sind int
s)