AutoIncrement - Gut oder Böse?

23. Dezember 2008 12:22

Hi Leute,

mir wurde als ich mit NAV angefangen habe immer gesagt das ich das AutoIncrement nicht verwenden sollte weil das irgendwie Probleme macht. Mitlerweile höre ich allerdings zuhauf das es total super funktioniert.
Weiss jemand von euch wie das nun ist? sollte man diese property verwenden oder lieber ne NOS dafuer nutzen?

23. Dezember 2008 15:19

[Beitrag aus dem Forum NAV Tipps & Tricks nach NAV 5.xx verschoben, da es eine Frage (und kein Tipp oder Trick) darstellt.]

Gruß, Natalie
MSDynamics.de-Team

Re: AutoIncrement - Gut oder Böse?

23. Dezember 2008 15:24

Ich kam noch nie in Versuchung, AutoIncrement zu verwenden und habe auch bisher nichts Schlechtes gehört, ABER die NAV-2009-Onlinehilfe zählt zahlreiche Einschränkungen auf:

Onlinehilfe NAV 2009 hat geschrieben:A table can only contain one auto-increment field. The numbers assigned to this field will not always be consecutive for the following reasons:

  • If you delete some records from a table, the numbers used for these records are not reused.
  • If several transactions are performed at the same time, they will each be assigned a different number. However, if one of these transactions is rolled back, the number that it was assigned is not reused.

If you add an auto-increment field to an existing table, the field automatically generates consecutive values and inserts them into the table. If you enable the AutoIncrement property for a field that already contains data, there must be no zero values in the field.

The AutoIncrement property is designed to always assign numbers automatically. If you want to insert a record, be sure that the value in this field is blank before you insert the record. This is even more critical when you are using the SQL Server Option.

The AutoIncrement property does not work with C/SIDE temporary tables.


Bei den vielen Dingen, die es dabei zu beachten gibt, wundert es mich nicht, dass manche von vorneherein versuchen, auf diese Eigenschaft zu verzichten.

Re: AutoIncrement - Gut oder Böse?

23. Dezember 2008 16:06

erstmal:
okay, das verschieben war an dieser Stelle wohl nötig^^ sorry war nich ganz bei mir.

Und zweitens:
das sagt die NAV 5.0 Hilfe auch. Aber deine Argumentation wird wohl der Grund sein warum einem das so beigebracht wird.

Re: AutoIncrement - Gut oder Böse?

11. Mai 2009 12:52

Hi,

ich hab hierzu nochmal eine Frage. Ich nutze diese Eigenschaft sehr gerne, weil sie bei mir wunderbar funktioniert. Autoinc find ich ziemlich wichtig. Dummerweise habe ich nun eine Tabelle, wo das Schlüselfeld nicht mehr Integer ist, sondern vom Typ "Code", weil es ja auch andere Tabellen verweisen muss. Leider finde ich aber nun, seitdem das Feld vom Typ "Code" ist, keine Property "Auto Increment" mehr. Die ist nun also weg. Kann mir jemand sagen, wie ich trotzdem AutoInc einbauen kann? Code beinhaltet doch auch nur Zahlen... (Die Felder, auf die ich verweise, sind auch alle vom Typ Code)

Nico

Re: AutoIncrement - Gut oder Böse?

11. Mai 2009 13:13

Also auch möchte mich erstmal deutlich FÜR AutoIncrement aussprechen! Gib nix besseres wenn man mal 'nen schnellen/simplen Primärschlüssel braucht. Der hier sonst übliche NAV Algorithmus muss nämlich stets ein LOCKTABLE beinhalten, und das kann wieder zu Sperren führen ...

Die AutoInc (IDENTITY in SQL) Anforderungen sind aber letztlich banal: immer manuell mit 0 initaialisieren, niemals Werte vorgeben, nur da einsetzten wo die Nummer (inhaltlich) unwichtig ist.

Das mit "Code" und "AutoIncrement": "Code" wir in SQL zu "varchar", aber IDENTITY funzt nur mit "Integer" (int) oder "BigInteger" (bigint). Was ich noch nicht ausprobiert habe: für "Code" Felder kann man in NAV den "SQLDataType" ändern. Vielleicht klapp ja "AutoInc" wenn man diesen Typ auf "int" oder "variant" umstellt?!

Gruß,
Jörg

Re: AutoIncrement - Gut oder Böse?

11. Mai 2009 14:43

Hi,

also wir haben damit, vor allem auf lange Sicht gesehen, schlechte Erfahrungen gemacht.
Bei uns war z.B. die Tabelle des NAS Schedulers mit einem AutoIncrement Integer Feld ausgestattet. Die Eintraege werden eine gewisse Zeit behalten, danach werden sie geloescht. Wiederkehrende Jobs werden rescheduled.

So schaukelt sich die Nummer immer weiter in die Hoehe, alte Nummern werden geloescht. Ab einem gewissen Zeitpunkt kennt sich Navision dann nicht mehr aus, und sucht sich fuer einen neuen Eintrag eine bereits existierende Nummer heraus. Erstellt man manuell einen Eintrag mit der naechsten richtigen Nummer, schafft es Navision dann wieder fuer eine gewisse Zeit, das Problem selbst kommt aber sicher wieder.

Von daher ist AutoIncrement fuer Tabellen, bei denen viel geschrieben und geloescht wird, fuer mich boese, zumindest bei V3.60 :wink:

Vielleicht ist das ab V5.xx besser?

Gruesse
feri

Re: AutoIncrement - Gut oder Böse?

11. Mai 2009 15:05

Mhh.. Das hört sich so an, als wenn AutoInc für deinen Scheduler vllt. nicht die richtige Wahl ist. Du sagst, wiederkehrende Jobs werden rescheduled... Bei AutoInc wird ja immer eine neue Nummer vergeben. Die alten tauchen nie wieder auf. Ich habe eine Tabelle, wo ich den Einträgen beim erstellen einfach nur irgendeine eindeutige Nummer verpassen will, und die darf auch wenn mal welche gelöscht werden nicht nochmal vergeben werden... Ich habs nun mit ner REPEAT-Schleife gemacht. Dummerweise fang ich unten an und wenn ich einen Datensatz nicht finde, dann nehm ich die Nummer. Das ist noch blöde. da muss es doch ne bessere Möglcihkeit geben. Kann doch nich so schwer sein, so ein komisches AutoInc da in ein Feld hineinzubekommen...

Vllt. könnte ich einfach zusätzlich immer ein autoinc-feld in die tablelle mit reinmachen und einfach bei jedem insert den wert in mein schlüsselfeld vom Typ Code kopieren mit CodeFeld := FORMAT(AutoInccFeld);

Was haltet ihr von sowas?

Re: AutoIncrement - Gut oder Böse?

11. Mai 2009 15:42

was haelst du von:
INCSTR (String)
Use this function to increase a positive number or decrease a negative number inside a string by one (1).


beim ONINSERT die letzte Nummer holen.

ich denke, dass das so gehen koennte!

Re: AutoIncrement - Gut oder Böse?

11. Mai 2009 15:45

Das klingt gut. Kannst du mir noch kurz sagen, wie ich auf ein Code-Feld die letzte Nummer hole?? (Man kann doch bei den Properties eines Code-Feldes angeben, Numeric. Das hab ich auf true. Also sind auch wirklich nur zahlen drin)

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 08:26

So, falls es noch jemanden interessiert, so hier hab ich es nun im Endeffekt gelöst:
Ich suche mit Find("+") den letzten Datensatz (der hat auch die größte Nummer). Finde ich keinen, Setze ich den neuen Wert auf 1, finde ich einen, erhöhe ich den Wert mit der coolen Methode INCSTR.


IF NOT "rec_Geb. Tour_Kopf".FIND('+') THEN BEGIN // AutoInc-Nr. selbst berechnen anhand der größten Nummer und setzen
rec_Tour_Kopf."Nr." := '1';
END ELSE BEGIN
rec_Tour_Kopf."Nr." := INCSTR( "rec_Geb. Tour_Kopf"."Nr.");
END;

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 09:06

...ich den Wert mit der coolen Methode INCSTR.

oh ja, die is sooooo cool 8-) :D


freut mich, dass du das Problem lösen konntest. Aber ich hoffe, das du in deinem Code selbst, eingerückt hast!


BTW es gibt hier im Forum die Funktion Code als Code zu markieren was dann so aussieht:
Code:
Cust.GET(theNo);

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 09:14

ok, ich probiers nochmal... :-)

So, falls es noch jemanden interessiert, so hier hab ich es nun im Endeffekt gelöst:
Ich suche mit Find("+") den letzten Datensatz (der hat auch die größte Nummer). Finde ich keinen, Setze ich den neuen Wert auf 1, finde ich einen, erhöhe ich den Wert mit der coolen Methode INCSTR.


Code:
IF NOT "rec_Geb. Tour_Kopf".FIND('+') THEN BEGIN // AutoInc-Nr. selbst berechnen anhand der größten Nummer und setzen
  rec_Tour_Kopf."Nr." := '1';
END ELSE BEGIN
  rec_Tour_Kopf."Nr." := INCSTR( "rec_Geb. Tour_Kopf"."Nr.");
END;


BTW: Ja, mein Code hier in Dynamics ist eingerückt... :-)

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 09:26

Hi!

Ich will nicht alles madig machen, aber dieser Code hat schon so seine Tücken ...
Code:
IF NOT "rec_Geb. Tour_Kopf".FIND('+') THEN BEGIN // AutoInc-Nr. selbst berechnen anhand der größten Nummer und setzen
rec_Tour_Kopf."Nr." := '1';
END ELSE BEGIN
rec_Tour_Kopf."Nr." := INCSTR( "rec_Geb. Tour_Kopf"."Nr.");
END;

FIND('+') lädt in diesem Fall ALLE Datensätze der Tabelle "rec_Geb. Tour_Kopf" in einen SQL Cursor, und das obwohl eigentlich nur der Letzte benötigt wird (das kann den Client ziemlich belasten - je nach Anzahl der DS). Ein alter NAV (Standard) Fehler der mittlerweile behoben wurde: in diesem Fall muss statt FIND('+') ein FINDLAST benutzt werden.
Das zweite Problem tritt auf, wenn zwei User gleichzeitig versuchen einen neuen DS anzulegen: Beide lesen u.U. die selbe letzte "Nr." und erhöhen diese um 1. Der erste User der den INSERT ausführt hat soz. "gewonnen", der zweite User wird einen PK-Fehler erhalten ("Der Datensatz bla bla existiert bereits."). Damit das nicht passiert, muss der Prozess serialisiert werden und darf nur noch DS aus abgeschlossenen lesen; dazu braucht's einen LOCKTABLE vorangestellt. Der wiederum kann aber zu Sperren/Blockaden führen.

Also, wenn AI nicht möglich ist, dann sollte der Algorithmus etwa so aussehen:
Code:
"rec_Geb. Tour_Kopf".LOCKTABLE;
IF "rec_Geb. Tour_Kopf".FINDLAST THEN
  rec_Tour_Kopf."Nr." := INCSTR( "rec_Geb. Tour_Kopf"."Nr.")
ELSE
  rec_Tour_Kopf."Nr." := '1';

Schöne Grüße,
Jörg

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 09:38

Ah, danke Jörg. Habe nun FindLast benutzt. Hört sich auch viel performanter an.

Mit dem Locktable.. damit hab ich leider noch wenig erfahrung. Muss ich die Tabelle irgendwann wieder entsperren? oder gilt das Lock nur für diese IF-Anweisung?

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 10:00

Also ein LOCKTABLE sperrt in NAV/SQL nicht wirklich eine Tabelle (auch wenn es sich hin und wieder so anfühlt). Bei einem LOCKTABLE passiert folgendes:

Die Transaktion wird serialisiert. D.h. der Prozess/User darf nur noch Daten lesen, die aus abgeschlossenen Transaktionen resultieren. Im NAV Standard dürfen nämlich Prozesse sog. "Dirty Reads" durchführen, d.h. also Daten von fremden Transaktionen lesen, obwohl diese noch offen sind. Durch "Dirty Reads" kann es zu dem Primmärschlüsselproblem" kommen, deshalb wird auch im NAV Standard bei allen wichtigen "Nummerierungen" - z.B. auch in "No. Series Management" - die Transaktionen serialisiert.
Ein LOCKTABLE gilt immer bis zum expliziten oder impliziten Commit; d.h. wenn im Code ein COMMIT gesetzt wird (explizit), oder wenn die Verarbeitung beendet wird (implizit).
Ein ERROR beendet die Transaction und damit auch den LOCKTABLE.
Nach einem LOCKTABLE werden auch sog. UPDATELOCKS gesetzt, die dann letztlich die im Zugriff befindlichen DS sperren.

D.h. aber auch, das ein LOCKTABLE nur dann benötigt wird, wenn tatsächlich die Möglichkeit besteht, dass mehrere User gleichzeitig den selben Prozess durchführen und es so zu Konflikten kommen kann. Ist sicher gestellt, dass eh nur EINER die Verarbeitung durchführt, dann kann man darauf auch verzichten ...

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 10:17

Mhh.. ok, und was genau heisst das nun? Kann ich vorsichtshalber schonmal LOCKTABLE hinschreiben und er machts dann, wenn er meint, dass es notwendig wäre? Welche Nachteile hätte ich durch einen LOCK? Und explizit entsperren muss ich ihn ja anscheinend nicht... Richtig? Wird automatisch entsperrt...

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 11:24

Na ja, wie so oft geht es hier um die unrühmliche Wahl zwischen Pest un Cholera ...

Mit LOCKTABLE wird sichergestellt, dass es nicht zu Primärschlüssel-Verletzungen kommt, kann dafür aber ggf. zu Blockadenführen (d.h. wenn ein anderer User ebenfalls zum selben Zeitpunkt einen neuen DS anlegen will).

Ich würde den LOCKTABLE mal setzten und beobachten, ob es tatsächlich zu Sperren kommt.

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 11:33

Dosihris hat geschrieben:Mhh.. Das hört sich so an, als wenn AutoInc für deinen Scheduler vllt. nicht die richtige Wahl ist.

Du sagst es. :mrgreen:

Dosihris hat geschrieben:Bei AutoInc wird ja immer eine neue Nummer vergeben. Die alten tauchen nie wieder auf.

So ist der Plan, leider faengt Navision an zu "spinnen" und kommt da etwas durcheinander.

Wir machen das an dieser Stelle jetzt einfach manuell, ist keine grosse Sache, nur die bis zur Fehlerbehebung verursachten Probleme waren laestig.

Gruesse
feri

Re: AutoIncrement - Gut oder Böse?

12. Mai 2009 12:16

@ Jörg:
Ok, danke, werd ich mal versuchen... Danke für die beiden Optimierungen meines Codes.


@ feri
Ihr habt es also auch manuell gemacht. Ich habe es nun im Endeffekt wie folgt gelöst. Wenn du magst, kannst du es ja mal kurz überfliegen und sagen, ob dir auch noch irgendwelche coolen Optimierungen einfallen. Wenn nicht, denke ich, haben wir in diesem Thread ja nun wirklich eindeutig und innig erläutert, wie man AutoInc selbst baut und welche Vor- und NAchteile die LockTable hat... :-)

Code:
  IF NOT "rec_Geb. Tour_Kopf".FINDLAST THEN BEGIN        // AutoInc-Nr. selbst berechnen anhand der größten Nummer und setzen
    rec_Tour_Kopf."Nr." := '1';
  END ELSE BEGIN
    rec_Tour_Kopf."Nr." := INCSTR( "rec_Geb. Tour_Kopf"."Nr.");
  END;

Re: AutoIncrement - Gut oder Böse?

19. August 2009 16:58

der locktable wird gelöst, sobald ein insert mit dem rec passiert, oder?
was ist mit anderen instanzen des recs?

was ist wenn zum finden des schlüssels eine andere instanz benutzt wird?
Code:
if A_instanz1.findlast then
  A_instanz2.nr := A_instanz1.nr + 1
else
  A_instanz2.nr := 1


müsste jetzt hier ein locktable auf A_instanz2 gesetzt werden, weil letztendlich mit diesem irgendwann der insert passiert?
ist so ein theoretisches konstrukt völlig unsinnig? in situationen wo zb zwischen der initialisierung von A_instanz2 (also dem rec für den insert) und dem eigentlich insert viel zeit vergeht (zb mit benutzereingabe) würde es ja doch wieder sinn machen den schlüssel erst direkt vor dem insert zu setzen und dann müsste ich eine zweite instanz zur schlüsselfindung nutzen, oder?

Re: AutoIncrement - Gut oder Böse?

20. August 2009 10:15

Also bei einem LOCKTABLE geschieht folgendes:

Zuerst wird der Befehl "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE" an den Server geschickt; d.h. die gesamte Transaktion wird serialisiert (statt UNCOMMITTED (= NAV Standard)). Ergo, diese Serialisierung - die nicht Objekt-bezogen ist - gilt bis zum Abschluss der Transaktion, also dem COMMIT.

Ist ein Prozess "serialisiert", so darf er nur noch Daten aus abgeschlossenen (committed) Transaktionen lesen; also keine "Dirty Reads" mehr; auch dürfen andere Prozesse keine Daten lesen die vom aktuellen Prozess gerade geändert werden.

"Books Online":
SERIALIZABLE
Gibt Folgendes an:
# Anweisungen können keine Daten lesen, die geändert wurden, für die jedoch noch kein Commit von anderen Transaktionen ausgeführt wurde.
# Andere Transaktionen können Daten, die von der aktuellen Transaktion gelesen werden, erst dann ändern, wenn die aktuelle Transaktion abgeschlossen ist.
# Andere Transaktionen können erst nach Abschluss der aktuellen Transaktion neue Zeilen mit Schlüsselwerten einfügen, die in den von Anweisungen in der aktuellen Transaktion gelesenen Schlüsselbereich fallen.


Weiter in NAV: Alle lesenden Befehle der Tabelle, die den LOCKTABLE ausgeführt hat, setzten einen UPDLOCK Hint ab - d.h. also ALLE Instanzen der Tabellen-Variable (das ist m.E. so schlecht gelöst und ein entsprechender Verbersserungsvorschlag ist schon an MS addressiert worden). UPDLOCK bewirkt, dass vormals gesetzte "Shared Locks" (S) in "Exclusive Locks" (X) umgewandelt werden (sollen). UPDLOCK (Aktualisierungssperren) gelten ebenfalls bis zum ABschluss der Transaktion (COMMIT).

Somit erhöht die Serialisierung das Risiko von Blockaden zu Gunsten der Datenkonsistenz. Oder anders gesagt: Beim LOCKTABLE in NAV geht es immer um "Blockaden versus Dirty Reads" ...