![]() |
Datenbank: MSSQL Server • Version: xy • Zugriff über: TADO
Eigenartiger Effekt mit int-Primary Keys ?
Hallo Delphi-Gemeinde,
ich habe eine Anwendung geschrieben, welche mittler weile seit über 10 Jahren mehr oder weniger erfolgreich läuft. Eher mehr ;-) Ich nutze zum Erstellen der Primärschlüssel eine eigene Funktion, welche aus einer Primärschlüssel-Tabelle einen Integer-Wert ermittelt, diesen um Eins hoch zählt ... usw. Die AutoIdent-Funktion des MsSQL-Servers nutze ich nicht, da meine Anwendung teilweise auch auf anderen Datenbanken (z.B. dBase, Clipper ...) läuft, welche AutoIdent-Funktionen nicht kennen. Zum Löschen von Datensätzen gibt es in meiner Anwendung eine Regel: Der Primärschlüssel wird negativ gesetzt und somit ist der Datensatz als gelöscht markiert. Kunden-Anforderung! (Aufgeräumt wird später).
Code:
TransactionLook ist aktiviert.
UPDATE tabelle SET id=ABS(id)*-1 WHERE id=:ID;
Mit dieser Regel läuft meine Anwendung seit Anfang an eigentlich recht stabil. Mittlerweile ist meine Anwendung soweit fortgeschritten, dass es in einigen Kundeninstallationen einen Primärschlüssel im 5 Mio-Bereich verwendet. Und natürlich ist die Anwendung mittlerweile so groß, dass es sehr schwer ist, SQL-Fehler zu identifizieren. Voll allem dann, wenn es sich um einen Folgefehler handelt. Das Problem: Der SQL-Befehl:
Code:
, wobei ID mit "5366038" belegt ist, schlägt fehl, da ein doppelter Primärschlüssel nicht zugelassen ist.
UPDATE tabelle SET id=ABS(id)*-1 WHERE id=:ID;
Das heißt, es soll eine Datensatz gelöscht markiert werden, welcher bereits gelöscht markiert ist. Und tatsächlich existiert zwei Datensätze, jeweils mit einem positiven ID und einem "gleichen" negativen ID. Das das nicht klappt ist klar. Interessanter Weise tritt dieser Fehler NUR im MSSQL-2008R2 und MSSQL-2012 auf und immer bei den gleichen Schlüsseln 5366038 bzw. 5365874. Ich habe ca. 20 Installationen am laufen, die diesen Fehler produziert haben. Und es betrifft immer einen dieser beiden Schlüssel. Ich habe das ganze Programm durchwühlt und nach einer Ursache im Code gesucht, konnte aber nichts finden. Aber Tatsache, dass dieser Fehler immer bei den gleichen IDs auftritt, bringt mir zu der Überzeugung, dass der Fehler nicht in meinem Programm-Code zu suchen ist, sondern wo anders. Von Visual Studio 20xy MFC-Klassen kenne ich das Phänomen, dass dort ein Integer-Wert festgelegt wurde, welcher quasi als NULL definiert ist. Das war ein Bug von M$, welcher irgendwie gefixt wurde. So soll (wenn ich das richtig verstanden haben) der (z.B.) SQL-Befehl:
Code:
vom MSSQL-Server als
UPDATE tabelle SET id=ABS(id)*-1 WHERE id=5365874;
Code:
übersetzt/interpretiert worden sein.
UPDATE tabelle SET id=ABS(id)*-1 WHERE id =NULL;
Kann es sein, dass in den Delphi-ADO-Klassen ein ähnliches Phänomen existiert? Meine IDE: Delphi-2009 auf MS-Server 2008-R2. Die Parameter (:ID) werden mit SetParam gesetzt, nicht direkt im SQL-Statement. Die Verbindung zum SQL-Server wird über einen eigenen ConnectionString per SQLOLEDB aufgebaut. Habt ihr ähnliche Erfahrungen? |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Hallo,
dass es "versteckte" Integer-Werte gibt, habe ich noch nie gehört. Quelle ? Dein Problem solltest du doch an Deinem Rechner nachstellen können? Ich denke eher, dass du Ids doppelt vergeben hast. Genau dafür ist ja das Identity zumindestens beim MS-SQL da. Andere DBs haben halt andere Mittel, um eindeutige Werte zu erzeugen. Zumindestens sollte jedes DB einen Unique Index anbieten, wobei das bei Dir nicht geholfen hätte (wegen dem negativ machen). Heiko |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Vorschläge habe ich nicht, nur drei Fragen:
1. Wie markierst/löschst Du Fremdschlüssel? 2. Wieso setzt Du die ID auf einen negativen Wert, anstatt einfach ein 'Deleted'-Flag zu pflegen? 3. Welchen transaction Isolation level verwendest Du? |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Nach der Beschreibung im Eröffnungsposting kann ich mir die Sache nicht anders erklären: Irgendwann wird ein PK negativ zu setzen versucht, wobei eine Kopie des Records mit dem positiven PK entsteht.
Vielleicht kann der DB-Server gar nicht anders handeln, wenn z.B. FKs in anderen Tabellen existieren, die auf diesen "positiven" PK deiner problematischen Tabelle verweisen, so daß dieser gar nicht gelöscht werden kann? Könntest du eventuell mal nachprüfen, ob irgendwelche FKs anderer Tabellen diese beiden problematischen Records über ihre PKs referenzieren? Zusätzlich würde ich einmal versuchen, einen neuen Datensatz mit diesem problematischen PK anzulegen und danach zu löschen, und zwar debuggenderweise. Damit solltest du eigentlich punktgenau auf die Stelle stoßen, die den Fehler auslöst. Beobachten oder gar nachvollziehen konnte ich dieses Verhalten bislang jedoch nicht (MsSQL, Firebird, MySQL). Wenn ich mal viel Zeit und Muse habe, probier ich's vielleicht mal aus ... |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Zitat:
dann würde das Problem gleich beim zweiten ANLEGEN und nicht erst beim LÖSCHEN auffallen. Zitat:
|
AW: Eigenartiger Effekt mit int-Primary Keys ?
Zitat:
![]() Das dieser Effekt/Bug tatsächlich existiert haben ich live gesehen! Geschrieben ist das Ganze im VS2010 in der afxdb.h Zitat:
Zitat:
Aber die 5 Mio Datensätze davor machen auch keine Probleme. Und in diesen 5 Mio Datensätzen sind ca. 20% mit negativem ID. Ja, gelöscht wird viel! Ein Großteil davon durchaus berechtigt. Zitat:
Delphi-Quellcode:
ruft?
TAdoConnection.BeginTrans
Zitat:
Code:
Ein Unique Index über tbbame,idname existiert
// PseudoCode
TAdoCon.BeginTrans; UPDATE nidents SET id=id+1 WHERE tbname=:TableName AND idname=:PkName; SELECT id from nidents where tbname=:TableName AND idname=:PkName; TAdoCon.CommitTrans; |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Hallo,
nun das Bsp. beschreibt aber, dass der Nutzer die falsche Dummy-Variable benutzt hat. Murks ist das trotzdem ... Ich wollte doch aber wissen, ob du das nachstellen kannst. Heiko |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Zitat:
Zitat:
Grundsätzlich halte ich auch weiterhin für problematisch, wenn man ohne ausreichende Grundkenntnisse versucht, funktionierende Anwendungen für ein produktives Umfeld schreiben zu wollen. |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Zitat:
Zitat:
Zitat:
Um diese Frage zu beantworten, verwende den Profiler, oder schau Dir die Eigenschaften der Connection an. Wenn Du weißt, wie der Isolationlevel ist, dann weißt Du auch, wie sich der Server beim konkurrierenden Lesen verhält. Natürlich ist das ärgerlich und irgendwo ist der Wurm. Aber ich lege meine Hand ins Feuer, das der SQL-Server mit NULL-Werten richtig umgehen kann. Zeig doch mal die Definition der Tabelle mit den doppelten Ids. Wichtig ist auch die Definition vom Index sowie die Definition der 'idents-Tabelle'. Beim SSMS gibt es die Funktion 'Generate Script'. Dort musst Du dann die eine Tabelle auswählen und in den Eigenschaften (ein Button auf der 3. Seite) noch einstellen, das auch der Index geskriptet werden soll. Das stellst Du dann hier ein und dann schauen wir weiter. Du kannst versuchen, dein Updatestatement sicher zu machen, indem Du die 'OUTPUT' Klausel verwendest (obwohl Du damit nicht mehr kompatibel zu dBase bist).
Code:
Damit hast Du eine atomare Anweisung, die garantiert transaktionssicher ist. Allerdings sind Probleme aufgrund der Nebenläufigkeit i.a. zufälliger Natur, d.h. Du müsstest eher zufällige doppelte Schlüssel beobachten.
UPDATE nidents
SET id=id+1 OUTPUT id WHERE tbname=:TableName AND idname=:PkName; Auch wenn es zum Haareraufen ist: Meist sitzt der Fehler 80cm vom Bildschirm entfernt. Nebenbei: Wer will heutzutage noch kompatibel zu dbase sein, wo es doch freie Datenbanken gibt? |
AW: Eigenartiger Effekt mit int-Primary Keys ?
Zunächst einmal, alle Schlüssel dienen der internen Verwaltung von Daten. Wer von extern darauf zugreift und diese manipuliert gehört geteert und gefedert.
Was deinen Fehler angeht, wenn der/die Schlüssel bereits existieren, dann arbeitet Dein Schlüsselgenerator eben nicht zuverlässig, da das nicht auftreten darf. Was heißt überhaupt negativ setzen? id:=id*-1 oder id:=id or $F000000 ? Und wieviele Bits haben Deine Integers eigentlich? Wenn auch DBase versorgt werden muß, konnte das eigentlich schon mit 32Bit-Werten umgehen? Gruß K-H |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:26 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz