(gelöst) (CC) gelöschter Datensatz wird gefunden.

5. Januar 2011 12:37

Hallo zusammen,

des Öfteren kommt es vor das Rechnungen über die Standard-Stapel Faktura (Report 297) gebucht werden. Leider werden zum Teil über 2000 Rechnungen gebucht.
Wenn nun das Lager in der Zwischenzeit einen dringenden Beleg druchbuchen möchte klappt das nicht 100%ig.
Ich hatte mir überlegt, dass ich, sobald ein Beleg gebucht wird ein Eintrag in eine Neue Tabelle erzeugt wird. Der Buchungsvorgang wird solange mit einem Sleep angehalten, bis es keine Datensätze vor diesem Beleg gibt.
Nun kommt es aber zu dem Problem, dass ich nach einer Buchung den Eintrag aus der Tabelle nicht löschen kann, da die Tabelle von einem anderen Benutzer gesperrt ist.
Ich dachte bisher immer, dass der SQL-Server nicht die ganze Tabelle sperrt, sondern nur den Datensatz in der Schreibtransaktion. Kann man das Sperrverhalten irgendwie beeinflussen? Oder kann ich auch ohne Commit diese eine Tabelle wieder freigeben?


Gruß

Christian
Zuletzt geändert von cdziewas am 5. Januar 2011 16:03, insgesamt 2-mal geändert.

Re: (CC) Table Lock aufheben?

5. Januar 2011 13:51

NAV ist wohl der Grund dafür, daß der SQL Server ziemlich schnell von Datensatzsperren auf Datensetsperren und dann auf Tabellensperren geht. In diesem Dokument http://www.sql-server.de/de/SQLNAVPorsche.pdf ist auf Seite vier ein Weg beschrieben, das zu umgehen. Aber ob das nun in deinem Fall hilfreich und der Weisheits letzter Schluß ist, wage ich zu bezweifeln.

Versuchst du denn mit dem zwischenzeitlich schlafenden Prozess den Datensatz zu löschen oder mit dem anderen?

Re: (CC) Table Lock aufheben?

5. Januar 2011 13:54

Danke für den Link. Ich schaue mir das Dokument mal an.
Ich versuche den Prozess mit einer anderen Anmeldung zu löschen.

Re: (CC) Table Lock aufheben?

5. Januar 2011 14:48

HattrickHorst hat geschrieben:NAV ist wohl der Grund dafür, daß der SQL Server ziemlich schnell von Datensatzsperren auf Datensetsperren und dann auf Tabellensperren geht. In diesem Dokument http://www.sql-server.de/de/SQLNAVPorsche.pdf ist auf Seite vier ein Weg beschrieben, das zu umgehen. Aber ob das nun in deinem Fall hilfreich und der Weisheits letzter Schluß ist, wage ich zu bezweifeln.


Man bedenke, dass das was Kollege D. dort schreibt über 8 Jahre alt ist und schon damals mit SQL 2000 nur bedingt funktioniert hat; heutzutage ist dass eher "Käse".
Blockade-Probleme in NAV mit SQL Server sind leider etwas komplexer; da muss man schon mehr "Hirnschmalz" hineinstecken, um A) den Ursachen auf den Grund zu gehen und B) saubere Lösungen zu entwickeln, die nicht zu Lasten der Datenintegrität gehen.

Wenn es hier also um Blockadeprobleme geht, dann gilt es zunächst exakt zu identifizieren was/wann/wo/wodurch/wie blockiert wird:
http://dynamicsuser.net/blogs/stryk/archive/2010/12/02/block-amp-deadlock-detection-updated-scripts.aspx (und verlinkte Artikel)

Dann erst kann man eine saubere Lösung andenken; z.B.
http://dynamicsuser.net/blogs/stryk/archive/2010/10/22/solving-blocking-issues-practical-examples.aspx
http://dynamicsuser.net/blogs/stryk/archive/2008/11/03/blocks-amp-deadlocks-in-nav-with-sql-server.aspx

Zu deinem Problem:
Der SQL Server sperrt auch nicht die gesamte Tabelle. SQL Server beginnt i.d.R. immer mit Rowlocking - auch wenn "Always Rowlock" nicht gesetzt wurde - kann aber ggf. die Sperren eskalieren (z.B. bei Stapelbuchungen). Durch "Always Rowlock" kann man diese Eskaltion unterbinden und somit ggf. Blockadeprobleme vermeiden (Details siehe mein BLOG).
I.d.R. werden also nur einzelne Zeilen/Datensätze gesperrt, z.B. ROW X. das kann zur folge haben, dass eine Speicherseite mit einem "Intended Lock" markiert wird, z.B. PAG IX. Dieses IX kann dann u.U. andere Prozesse blockieren; d.h. de facto ist eine Seitensperre das Problem.
Auch der NAV Code spielt eine große Rolle dabei, d.h. die SQL Cursor Steuerung, die Indizierung, NAV Setup, etc..

Wie gesagt, dass Thema ist vielschichtig ...

Re: (CC) Table Lock aufheben?

5. Januar 2011 15:13

Danke euch beiden für die Antwort. Das Locking ist nun kein Problem mehr. Ich habe gerade eben meinen Code umgestellt.
Mir ist nun aufgefallen, dass ich wegen dem IF Codeunit.RUN... im Report vorher eh ein Commit setzen muss.

Allerdings versteh ich gerade die Welt nicht mehr.
Wenn ich den Code unten ausführe bleibt der Report in einer Endlosschleife hängen, auch wenn ich in einer anderen Anmeldung den Eintrag in der Tabelle lösche. Im Debugger findet der Server immer noch den von mir gelöschten Datensatz.

Code:

IF SingleInsMgt.GetPostingUpdateBatch THEN BEGIN
  CurrDateTime :=  CURRENTDATETIME;
  PostingInfo.RESET;
  PostingInfo.INIT;
  PostingInfo."User ID" := USERID;
  PostingInfo."Posting Update Agr." := TRUE;
  PostingInfo.DocumentNo := "Sales Header"."No.";
  PostingInfo."DateTime PostingReq" := CurrDateTime;
  PostingInfo.INSERT;
  COMMIT;
 
   postnow := FALSE;
   REPEAT
      Testwindow.OPEN('#1##########');
      Testwindow.UPDATE(1,'WARTEN'); 
      SLEEP(1000);
      CLEAR(GenFunMgt);
      postnow := GenFunMgt.CheckIfPostable(CurrDateTime);
      Testwindow.CLOSE;
   UNTIL postnow;

END;


Filter in der Codeunit:

Code:
PostingInfoLoc.RESET;
PostingInfoLoc.SETCURRENTKEY("DateTime PostingReq");
PostingInfoLoc.SETFILTER("DateTime PostingReq",'<%1',PostingDateTime);
IF PostingInfoLoc.FINDFIRST THEN BEGIN
  EXIT(FALSE);
END ELSE BEGIN
  EXIT(TRUE);
END;

Re: (CC) Table Lock aufheben?

5. Januar 2011 15:30

stryk hat geschrieben:Man bedenke, dass das was Kollege D. dort schreibt über 8 Jahre alt ist und schon damals mit SQL 2000 nur bedingt funktioniert hat; heutzutage ist dass eher "Käse".

Oh! :oops: Gut zu wissen. Hatte das Dokument neulich erst entdeckt. Dann sollte er mal seine Homepage auf den neusten Stand bringen... :wink:

Re: (CC) Table Lock aufheben?

5. Januar 2011 15:41

cdziewas hat geschrieben:Wenn ich den Code unten ausführe bleibt der Report in einer Endlosschleife hängen, auch wenn ich in einer anderen Anmeldung den Eintrag in der Tabelle lösche. Im Debugger findet der Server immer noch den von mir gelöschten Datensatz.

Hast du es mal mit SELECTLATESTVERSION versucht?

Re: (CC) gelöschter Datensatz wird gefunden.

5. Januar 2011 16:02

Super besten Dank! So ein einfacher Befehl, der das Leben so viel einfacher macht. Irgendwie ist der mir bisher noch nicht untergekommen.
Mein Code sieht nun wie folgt aus, für die, die was Ähnliches vorhaben:

Code:

IF SingleInsMgt.GetPostingUpdateBatch THEN BEGIN
  CurrDateTime :=  CURRENTDATETIME;
  PostingInfo.RESET;
  PostingInfo.INIT;
  PostingInfo."User ID" := USERID;
  PostingInfo."Posting Update Agr." := TRUE;
  PostingInfo.DocumentNo := "Sales Header"."No.";
  PostingInfo."DateTime PostingReq" := CurrDateTime;
  PostingInfo.INSERT;
  COMMIT;
  SELECTLATESTVERSION;
   postnow := GenFunMgt.CheckIfPostable(CurrDateTime);
   IF NOT postnow THEN BEGIN
    REPEAT
       SELECTLATESTVERSION;
       Testwindow.OPEN('#1##########');
       Testwindow.UPDATE(1,'WARTEN'); 
       SLEEP(50);
       CLEAR(GenFunMgt);
       postnow := GenFunMgt.CheckIfPostable(CurrDateTime);
       Testwindow.CLOSE;
    UNTIL postnow;
   END;
END;

Re: (CC) Table Lock aufheben?

6. Januar 2011 00:09

cdziewas hat geschrieben:
Code:
PostingInfoLoc.RESET;
PostingInfoLoc.SETCURRENTKEY("DateTime PostingReq");
PostingInfoLoc.SETFILTER("DateTime PostingReq",'<%1',PostingDateTime);
IF PostingInfoLoc.FINDFIRST THEN BEGIN
  EXIT(FALSE);
END ELSE BEGIN
  EXIT(TRUE);
END;

Hi Christian,

kleiner Zusatz: wenn dieses Stück Code nichts anderes macht, als ein Boolean-Wert zurückzugeben, ob in der PostingInfoLoc ein Datensatz gemäß dem Filter existiert,
dann reicht auch ein
Code:
EXIT(NOT PostingInfoLoc.ISEMPTY)
aus anstatt
Code:
IF PostingInfoLoc.FINDFIRST THEN BEGIN
  EXIT(FALSE);
END ELSE BEGIN
  EXIT(TRUE);
END;
ist auch schneller und kürzer

Gruss von Deinem Ex-Kollegen

Re: (gelöst) (CC) gelöschter Datensatz wird gefunden.

6. Januar 2011 00:16

Muss mich gleich korrigieren, Du gibst TRUE zurück, wenn Nichts gefunden wird, also:
Code:
EXIT(PostingInfoLoc.ISEMPTY);

Re: (gelöst) (CC) gelöschter Datensatz wird gefunden.

6. Januar 2011 14:34

Super danke. Stimmt das ist wesentlich schneller, als ein FIND.

Gruß

Christian