Wir haben eine Handvoll Zeilen in unserer Datenbank gefunden, die gegen eine aktive Einschränkung verstoßen. Wie ist das möglich?
Die Einschränkung ist aktiv, da wir nicht einfach manuell eine Zeile hinzufügen können, die diese Einschränkung umgeht. Wenn wir jedoch laufen CHECKCONSTRAINTS(Files)
, stellen wir fest, dass es während unserer Testläufe gelegentlich umgangen wurde. Die fraglichen Reihen wurden alle innerhalb einer halben Sekunde voneinander erstellt, was auf eine Art Rennbedingung hindeutet.
Hier ist die Einschränkung, die auf die Tabelle angewendet wird. Die Regel soll die Eindeutigkeit des Namens in einem bestimmten übergeordneten Ordner sicherstellen:
ALTER TABLE Files ADD CONSTRAINT UniqueNameInParentFolder CHECK
CheckUniqueNameInFolder(ParentFoldersID, Name) = 1;
Diese Einschränkung ruft eine Funktion auf, die folgendermaßen aussieht:
-- first check for the new name in the Folders table
IF ((SELECT COUNT(*) FROM Folders
WHERE ParentFoldersID = @FoldersID AND Name = @Name) = 0)
BEGIN
-- then check for it in the Files table
IF ((SELECT COUNT(*) FROM Files
WHERE ParentFoldersID = @FoldersID AND Name = @Name) <= 1)
RETURN 1
END
RETURN 0
Einzelne Zeilen werden innerhalb von Transaktionen hinzugefügt, daher fällt es mir schwer zu verstehen, wie sich doppelte Zeilen über diese Einschränkung hinausschleichen.
quelle
Folders
es dort auch eine ähnliche Anzahl von Verstößen gibt. Wir verwenden derzeitREAD_COMMITTED_SNAPSHOT
.Antworten:
Überprüfungsbeschränkungen, die auf UDFs basieren, sind Müll. Parallelität, RBAR, Isolation usw., wie Sie herausgefunden haben. Einige Links:
Alex K: Skalare UDFs, die in CHECK-Einschränkungen eingeschlossen sind, sind sehr langsam und können bei Aktualisierungen mit mehreren Zeilen fehlschlagen
Tony Rogerson
Der sicherste Weg für SQL Server wäre in diesem Fall die Verwendung von Standardeinschränkungen wie eindeutigen und Fremdschlüsseln. Ich kann nicht verstehen, warum Sie die Ordnertabelle auf eine Einschränkung der Dateitabelle überprüfen
Edit: eine Datei und einen Ordner mit dem gleichen Namen in einem bestimmten übergeordneten Ordner verhindern nur , verwenden Sie eine indizierte Sicht. Doppelte Dateien oder doppelte Ordner erfordern die Eindeutigkeit auf Tabellenebene.
Oder ein Auslöser.
Aber niemals eine UDF in einer Prüfbedingung
quelle
Diese CheckUniqueNameInFolder-Funktion überprüft kaum etwas. Unter dieser Einschränkungsprüfung können viele Duplikate hinzugefügt werden. Es gibt zwei verschiedene SELECTS, die nacheinander ausgeführt werden (daher kann die von der ersten Auswahl überprüfte Bedingung zum Zeitpunkt der Ausführung der zweiten Auswahl ungültig werden), und in jedem Fall gibt die Einschränkung bestenfalls an, dass bei der Prüfung kein Duplikat vorhanden war aufgetreten ist, bedeutet in keiner Weise, dass beim Einfügen / Aktualisieren kein Duplikat vorhanden ist . Da die Überprüfungen die zu überprüfenden Schlüssel im U- oder X-Modus nicht sperren , können mehrere Einfügungen gleichzeitig erfolgen. Führen Sie die Überprüfung durch, suchen Sie kein Duplikat und alle fügen denselben Eintrag ein.
Die einzige Möglichkeit, eine eindeutige Einschränkung ordnungsgemäß durchzusetzen, besteht in der Verwendung einer eindeutigen Einschränkung .
Erstellen Sie eine berechnete Spalte mit dem vollständigen Pfad Ihrer 'Dateien' und erzwingen Sie die Eindeutigkeit des gesamten Pfads mit einer EINZIGARTIGEN Einschränkung oder verwenden Sie möglicherweise eine EINZIGARTIGE Einschränkung für
(ParentFolderID, Name)
. Speichern Sie Ordner und Dateien nicht separat, sondern verwenden Sie eine gemeinsame Tabelle für Ordner und Dateien (z. B. Einträge), da sie denselben Namespace belegen .quelle
Das Ausführen innerhalb einer Transaktion auf Standardebene
read committed
schlägt unter Last fehl.Die Lesevorgänge schließen sich nicht gegenseitig aus und werden serialisiert, sodass zwei gleichzeitige Transaktionen beide lesen können, dass die Zeile nicht vorhanden ist. Sie können
UPDLOCK,ROWLOCK,HOLDLOCK
demSELECT
.quelle