Laden...

GUID als Primärschlüssel

Erstellt von Paragenius vor 18 Jahren Letzter Beitrag vor 17 Jahren 8.168 Views
P
Paragenius Themenstarter:in
14 Beiträge seit 2005
vor 18 Jahren
GUID als Primärschlüssel

Moin, moin

Ich will eine GUID als Primärschlüssel in meiner MSDE-DB verweden. Welchen Typ sollte ich dort für die ID-Spalte benutzen?

Gruss

Paragenius

3.728 Beiträge seit 2005
vor 18 Jahren

uniqueidentifier

P
Paragenius Themenstarter:in
14 Beiträge seit 2005
vor 18 Jahren
Danke

@Rainbird: Danke für die schnelle Antwort!

Gibt es irgendwo eine Übersicht über die diversen DB-Typen und welche man dafür in C# verwendet?

4.221 Beiträge seit 2005
vor 18 Jahren

Original von Paragenius
@Rainbird: Danke für die schnelle Antwort!

Gibt es irgendwo eine Übersicht über die diversen DB-Typen und welche man dafür in C# verwendet?

Guckst Du unter: OleDbType

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

P
Paragenius Themenstarter:in
14 Beiträge seit 2005
vor 18 Jahren
432 Beiträge seit 2005
vor 18 Jahren
GUID non clustered und zusätzlicher int clustered?

hallo zusammen

insbesondere hallo rainbird.

folgende frage steht im raum:

guid als primary key mit newid() als default = performanceverlust !
guid als primary key mit NEWSEQUENTIALID() als default = kontrollverlust auf seite der anwendung, da codeseitig NEWSEQUENTIALID() nicht unterstützt wird.

bleibt doch als ausweg nur die folgende empfehlung von bob yexley:
siehe unter http://yexley.net/blogs/bob/archive/2005/01/13/1101.aspx

GUID als primary key non clustered, unique clustered identity als eindeutiger sekundärschlüssel zur umgehung des performanceverlustes bei "wahlloser" GUID erzeugung, oder? :


CREATE TABLE [dbo].[kannweg](
	[ID]           [uniqueidentifier] NOT NULL CONSTRAINT [def_kannweg_ID]  DEFAULT (newsequentialid()),
	[IntID]        [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
	[Angabe_xyz]   [nvarchar](50) COLLATE Latin1_General_CI_AS NULL,

   CONSTRAINT [pk_kannweg] PRIMARY KEY NONCLUSTERED ([ID] ASC) WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
   CONSTRAINT [sk_kannweg] UNIQUE CLUSTERED ([IntID] ASC)      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]


GUIDs are great to use as a primary key, especially in an environment where you may need to match records between databases or keeping the ID's when deploying to new environments.

There is just one thing you should really do when you use GUIDs as your primary key. I didn't see anyone mention it so thought I would throw it in. The default index type for a primary key is a clustered key. If your primary key is a GUID, you want to uncheck that option. You should then add another column, or use an existing one, that has an ever increasing or decreasing value and make that your clustered key. Otherwise, you could run into some performance problems, as SQL server is inserting records all over the place instead of at the end of the table. It can also cause fragmentation of your database.

Having an additional ever increasing or decreasing column (identity) that is your clustered key, allows SQL Server to use that clustered index to insert records at the end. The GUIDs will not be in any order, and will cause SQL Server to insert the recods at seemingly random spots throughout the database.

You don't have to use the new column in any joins or anything. Just let it sit there and give SQL Server something to work with when doing inserts and such.

I
1.739 Beiträge seit 2005
vor 18 Jahren

Will man es etwas unabhängiger haben, geht auch jeder Datentyp der mindestens 128 Bit breit sein kann.
Also ein String(was es bei der DB auch bedeutet) oder ein Numerischer Wert würden es auch tun.

153 Beiträge seit 2006
vor 17 Jahren

Original von Paragenius
Moin, moin

Ich will eine GUID als Primärschlüssel in meiner MSDE-DB verweden. Welchen Typ sollte ich dort für die ID-Spalte benutzen?

Gruss

Paragenius

Servus!

Welchen Datentyp verwendet mann für diesen Zweck sinnvollerweise bei MySql.

3.728 Beiträge seit 2005
vor 17 Jahren
MySQL

Einen string Datentyp mit fester länge. Das ist dann zwar um einiges langsamer (da der SQL Server den uniqueidentifier als Zahl und nicht als String speichert), aber geht nicht anders (Zumindest mit dem Standard-Tabellenschema). Auf jeden Fall einen Index drauf setzen, sonst kannst Du Kaffee trinken gehn.

B
249 Beiträge seit 2005
vor 17 Jahren

Frage: Wieso muss es denn eine GUID als Primärschlüssel sein? Könntest du nicht einen "normalen" PK Definieren. Also numeric, identity und autoincrement auf 1. Für dein Feld mit der GUID kannst du doch eine uniqueconstraint erstellen.
Also das ist nur die Idee, wie ich es kenne. Oder ist dies keine perfomante Lösung?

Also bei mehreren hunderttausend Datensätzen, geht eine Abfrage schon mal seine 8 Sekunden. Ist das normal, oder liegt das an der Struktur?

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo zusammen,

Frage: Wieso muss es denn eine GUID als Primärschlüssel sein? Könntest du nicht einen "normalen" PK Definieren. Also numeric, identity und autoincrement auf 1. Für dein Feld mit der GUID kannst du doch eine uniqueconstraint erstellen.

genau so kenne ich das auch. Ich gehe davon aus, dass die DB selbst weiß was am performantesten ist, deshalb verwende ich als PK immer den Default. Wenn ich dann aber eine eigene Key Verwaltung zusätzlich benötige (z.B. GUID), dann lege ich mir so wie vorgeschlagen eine weitere Spalte als unique an...

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

460 Beiträge seit 2004
vor 17 Jahren

Hallo,

da stimme ich norman_timo vollkommen zu, GUIDs innerhalb der DB machen keinen Sinn. Wenn man externe DB anbinden möchte dann sind GUIDs unersetzlich. Aber innerhalb einer DB wird nur viel Speicherplatz verschwendet.

153 Beiträge seit 2006
vor 17 Jahren

Ich gebe euch grundsätzlich recht. GUIDs sind wirklich Platzverschwendung.

Ich wollte mir halt das Programmier-Leben erleichtern.

Bei Verwendung von Auto-Increment Integern als PK ist der Abgleich bei einer Master/Detail-Relation schon etwas aufwändig. Hier prinzipiell meine Vorgehensweise anhand vom Beispiel Customers - Orders. Wäre nett, wenn mir jemand bestätigen könnte, ob ich damit richtig liege:

Jede Bestellung (Order) verweist über eine Spalte customers_id auf den PK der Customers-Tabelle. (Relation im DataSet).
1.Wenn ich einen neuen Customer mit Bestellungen hinzufüge, setze ich die ID auf null, damit die ID vom Server vergeben wird. Würde ich die vom DataSet vergebene ID verwenden, könnte es sein, dass die bereits von einem anderen Benutzer zwischenzeitig angelegt wurde, das Insert würde dann zu einem Fehler führen. 1.Als nächstes muss ich die vom Server vergebene ID auslesen. Um sie den Orders zuzuweisen (Hierzu habe ich mir die Vorherige ID des Customers gemerkt). 1.Allerdings kann es sein, dass die vom Server neu vergebene ID bereits vom Dataset für einen anderen Customer verwendet wird und ich muss wieder tätig werden.

Das Alles wäre mir mit einer GUID erspart geblieben.

S
8.746 Beiträge seit 2005
vor 17 Jahren

Im Prinzip ist der Einwand berechtigt. Mir persönlich ist ADO.NET u.a. deswegen viel zu stark auf bestimmte Anwendungsszenarien zugeschnitten, bei denen Updates kaum ein Rolle spielen. Es ist schon sehr bezeichnend, dass man wirklich einiges an Code schreiben muss um AutoIncrements bei Relationen saubern zu handbaben. Damit hat man dann den Master-Detail-Code an drei Stellen verteilt: DB-Constraints, ADO.NET-Relations und RowUpdate-Code. Da freut man sich auf jede Änderung des DB-Modells....

Alternativ kann man sich natürlich nach jedem Update das DataSet komplett neu ziehen.... 😉

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo zusammen,

also bei solchen Anforderungen wähle ich einfach eine DB, die Transaktionen beherrscht (ich glaub es gibt nur wenige, die es nicht können), dann kann ich mir bequem in einer Transaktion eine neue ID vergeben lassen, und diese auch wieder auslesen, OHNE dass mir jemand dazwischenfunkt.

Beziehungseise verhindert ist es damit nicht, aber auf jeden Fall ist damit sichergestellt, dass eine konkrete ID korrekt angelegt wird, und auch im Programm richtig zugeordnet werden kann.

Danach sollte es doch kein Problem sein, diese ID auch in anderen Tabellen zu verwenden, oder?

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

153 Beiträge seit 2006
vor 17 Jahren

Hallo nochmal.

Dass das Ganze innerhalb einer Transaktion ablaufen muss habe ich vergessen zu erwähnen.

Damit wird aber nicht verhindert, dass im DataSet eine ID vergeben wird, die auf dem Server bereits verwendet wird.
Zur Erklärung: Ich lese beim Starten alle Daten in das DataSet und am Ende des Programms erfolgt der komplette Abgleich mit dem Server. Dazwischen besteht keine Datenbankverbindung.

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo Icarus666,

so ganz kann ich das noch nicht nachvollziehen.

Du liest die Daten ein? Dann existiert doch eine ID, oder nicht? Warum verwendest Du diese dann nicht?

Es ist auch möglich eine 2. Spalte mit einem Foreign Key zu definieren. Also wäre z.B. in Deinem Fall die Customer die "Haupttabelle" von der alle anderen abhängen würden (Aufträge, Bestellungen etc...)

Dann würde jede abhängige Tabelle einen Foreign-Key auf die Haupttabelle besitzen, und somit ist die Zuordenbarkeit wieder hergestellt. Diese Foreign Keys sollten ebenfalls wie die lokale ID indiziert werden.

Dann hat jedes Element eine lokale ID (z.B. Bestellung), und mit Hilfe des Foreign Keys erlangst Du Kenntnisse über den Kunden (dessen lokale ID).

Deshalb verstehe ich das noch nicht so ganz, wie Du es realisieren möchtest.

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

S
8.746 Beiträge seit 2005
vor 17 Jahren

Wenn du einen Datensatz im DataSet einfügst dann bekommt dieser Datensatz eine temporäre AutoIncrement-ID. Der Trick ist, dass temporäre IDs und Server-IDs nicht im gleichen Bereich laufen. Überlicherweise erreicht man das, indem man die temporären IDs mit -1 beginnen läßt und einen negativen Schrittwert einstellt, also -1, -2, etc.!

Server-IDs sind dagegen nur positiv. Damit kann der Fall nicht auftreten, dass eine zwischenzeitliche DB-Aktualisierung zu doppelten IDs führt.

Trotzdem immer noch lästig aufwändig das Ganze.....

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo zusammen,

ah, jetzt weiß ich was gemeint ist 😉

Ok, ich mache mir immer die Arbeit, die Spalten einzeln anzugeben, die ich in der DB verwenden will. Eine ID lese ich immer aus, aber definiere sie mir NICHT als ID im DataSet/DataTable.

Das ist in der Tat mühselig, außer man verwendet einen angepassten O/R Mapper, den ich mir einmalig entorfen habe. So werden die Spalten nach einer XML Konfigurationsdatei ausgelesen. Dabei habe ich auch solch eine Bezeichnung eingeführt, wie Internal und External, um zu unterscheiden, was später mal in der GUI zu sehen ist (external) und welche nur für den internen Gebrauch zuständig sind (hier z.B. ID's).

Aber das ist reine Geschmackssache. Ich würde auch strengstens darauf achten, dass ID's wirklich nur von der DB vergeben werden. Z.B. so wie svenson vorgeschlagen hat.

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

153 Beiträge seit 2006
vor 17 Jahren

Original von svenson
Wenn du einen Datensatz im DataSet einfügst dann bekommt dieser Datensatz eine temporäre AutoIncrement-ID. Der Trick ist, dass temporäre IDs und Server-IDs nicht im gleichen Bereich laufen. Überlicherweise erreicht man das, indem man die temporären IDs mit -1 beginnen läßt und einen negativen Schrittwert einstellt, also -1, -2, etc.!

Danke, werd ich ausprobieren!

Trotzdem immer noch lästig aufwändig das Ganze.....

Stimmt.

3.728 Beiträge seit 2005
vor 17 Jahren
GUIDs

GUIDs braucht man immer dann, wenn man einen gültigen Schlüssel erstellen muss, ohne in diesem Moment mit dem Server verbunden zu sein.

Um den Sinn zu erklären, muss ich etwas ausholen:

Keine dauerhafte Datenbankverbindung haben zu müssen ist für verteilte (möglicherweise über das Internet) Anwendungen eigentlich Pflicht. Außerdem vereinfacht es die Architektur und erhöht die Skalierbarkeit, da das Management der Verbindungen von ADO.NET per Connection Pooling automatisch geregelt wird. Es ist also auch ein Irrglaube, es wäre leistungsfähiger, eine Verbindung dauernd offen zu halten. Bei vielen gleichzeitigen Client-Anfragen ist eine Verbindung ein Flachenhals. Manuelles Handling der Verbindungen wäre das Rad neu erfunden (Und warscheinlich nicht so gut, wie das bestehende).

Wenn ich jetzt auf meinem Client einen neuen Datensatz in meine DataTable im Hauptspeicher schreibe, brauche ich dafür einen Schlüssel. Ich möchte keinen Round-Trip zum Datenbankserver haben, um einen gültigen Schlüssel zu bekommen. Der Serverzugriff selber wäre nicht mal so schlimm. Aber um den Schlüssel zu kriegen, müsste ich ein INSERT ausführen. Jetzt hat der Benutzer aber noch nicht alle Pflichtfelder eingegeben. Oh, Schade! Keine Pflichtfelder, kein INSERT. Natürlich kann ich auch warten, bis er alles eingegeben hat. Solange muss ich auf dem Client Extrawürste für mysteriöse Dummyschlüssel braten (z.B. welche die ins negative gehen). Oder ich muss immer abfangen, wenn der Schlüssel in meiner DataTable DBNull ist. Oder ich muss ungespeicherte Daten ganz anders verwalten. Selbst wenn der INSERT klappt und die Datenbank einen neuen tollen Schlüssel erstellt, habe ich ein Problem: Was ist wenn der Benutzer abbricht? Dann muss der hässliche Datensatz mit dem neuen Schlüssel ganz flux wieder verschwinden, denn er dürfte ja gar nicht da sein. Jetzt sagen bestimmt alle: Transaktionen!. Die müssen aber eine Verbindung offen halten und verursachen Sperren (Locks) auf der Datenbank (Das ist für den Datenbank Server auch Ressourcen Intensiv). Je nach Isolationsstufe der Transaktion wird möglicherweise die komplette Tabelle gesperrt. Alle anderen Clients müssen dann warten, bis diese Transaktion fertig ist. Wenn der Benutzer jetzt in die Mittagspause geht, ohne auf OK zu klicken, bekommen die anderen erstmal eine Sanduhr und irgendwann gibts nen Timeout.

Mit einem GUID als Primärschlüssel gibts das alles nicht. Die paar Byte mehr Platz sind kein Argument, da jeder Home-PC schon 200 GB Festplattenspeicher hat. Fazit:*In der Client Anwendung ist weniger Code erforderlich *Die Anwendung skaliert besser, weil Transaktionen kurz und knackig bleiben *Die Anwendung skaliert außerdem besser, weil geklotzt wird und nicht gekleckert (Der Client schiebt alles in einem Block, in einer Transaktion zum Server und nicht in kleinen Fitzelchen um Schlüssel zu holen etc.) *Die Anwendung ist automatisch "Offline-Fähig" (z.B. für den Außendienst)

Es gibt wirklich nur zwei wirkliche Nachteile, die gegen GUIDs sprechen:*GUIDs können nicht als Sortierung zwecks Reihenfolge verwendet werden *GUIDs sind selecht zu merken und z.B. beim Debuggen im Query Analyzer umständlich eizugeben.

S
8.746 Beiträge seit 2005
vor 17 Jahren

Die Frage ist, was es überhaupt bei der Architektur von ADO.NET bringt, neue Datensätze einzeln in die DB zu schreiben und die AutoIDs zurückzuholen. Tut man das nicht, hat man trotzdem ein konsistentes DataSets (Einsatz von Relationen vorrausgesetzt) aus dem alle Anfragen bedient werden können. Wer nicht den Fehler macht, Unique Identifier zu fachlichen Feldern (niemals fachliche Felder zu IDs machen, selbst WENN sie eindeutig sind!) zu machen hat eigentlich keine Not. Damit ist man dann auch "offlinefähig".

Letztlich muss man hin und wieder sowieso das gesamte DataSet neu laden um Aktualisierungen anderer Clients mitzubekommen.

Man muss sich immer wieder klar machen: ADO.NET arbeitet im Speicher und der muss zu festgelegten Zeitpunkten aktualisiert werden (und zwar vollständig). Dies nach jeder Änderung zu tun, ist bei den Anwendungsfällen, für die ADO.NET gemacht worden ist, nicht unbedingt ein "Best Practice".

_
227 Beiträge seit 2006
vor 17 Jahren

Wie sieht es denn mit der Eindeutigkeit von GUIDs aus?

153 Beiträge seit 2006
vor 17 Jahren

Siehe Wikipedia:

A Globally Unique Identifier or GUID is a pseudo-random number used in software applications. While each generated GUID is not guaranteed to be unique, the total number of unique keys ( 2128 or 3.4028×1038 ) is so large that the possibility of the same number being generated twice is very small.

S
8.746 Beiträge seit 2005
vor 17 Jahren

Spannend wäre mal die Frage, wieviel eine GUID im Gegensatz zu einer unique ID mit clustered index an Performance verliert und wieviel an zusätzlichem Speicherplatz der Kram kostet.

4.506 Beiträge seit 2004
vor 17 Jahren

Hallo zusammen,

A Globally Unique Identifier or GUID is a pseudo-random number used in software applications. While each generated GUID is not guaranteed to be unique, the total number of unique keys ( 2128 or 3.4028×1038 ) is so large that the possibility of the same number being generated twice is very small.

nichtsdestotrotz ist mir nur EIN Fall bekannt, dass bei Microsoft jetzt seit der Entstehung einen doppelten GUID produziert bekommen hat. Wenn man jetzt bedenkt, dass Microsoft wahrscheinlich diejenigen sind, die GUIDs noch am Häufigsten einsetzen, und vor allem in einer unbeschreiblichen Menge, dass man wirklich davon ausgehen kann, dass GUIDs im Normalbetrieb eindeutig sind.

Offen bleiben wirklich Svensons Fragen, die aber meiner Meinung nach keiner Antwort bedürfen, da es fast unbestritten ist, dass GUIDs langsamer sind, und auch mehr Speicherplatz verbraten, wieviel ist zumindest mir dann egal... (aber zum Verifizieren nicht schlecht)

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”