Announcement

Collapse
No announcement yet.

ganze DB-Tabelle gesperrt während Transaction !?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • ganze DB-Tabelle gesperrt während Transaction !?

    Hallo, folgendes Problem:

    DB: SQL-Server
    C++ und VB.NET

    Mit einer C++ Applikation werden in einer ziemlich "großen" Transaction Datensätze in eine Tabelle geschrieben.

    Mit einer anderen Applikation (VB.NET) sollen nun parallel Datensätze aus der selben Tabelle gelesen werden. Ein Aufruf wie (SELECT * FROM TABLE WHERE STATUS=20) liefert aber einen Timeout zurück, solange die C++-Apllikation die Transaktion nicht beendet hat.

    Die Frage:
    Gibt es eine Möglichkeit die Connection innerhalb der C++-Applikation so zu öffnen, das andere Applikationen dennoch auf die Datensätze der Tabelle zugreifen können (natürlich nur auf die Sätze, welche durch die C++-Applikation bereits committed wurden) - oder ist das mit SQL-Server generell nicht möglich?
    (Kleiner Hinweis noch, bei Oracle habe ich diese Probleme nicht!)

    Ich habe viel mit dem Mode und der IsolationLevel "gespielt", aber leider ohne Erfolg.

    Hier mein Connection-Code:
    pCon.CreateInstance(__uuidof(Connection));
    pCon->ConnectionTimeout = 30;
    pCon->Mode = adModeShareDenyNone;
    pCon->IsolationLevel = adXactIsolated;
    pCon->Open(s_conn, DBUser, DBPW, adOpenUnspecified);

    Die VB.NET-Applikation geht über das SqlConnection-Object

    Ich hoffe ich habe mich verständlich ausgedrückt und jemand weiß eine Lösung.

    Tnx.
    Olli

  • #2
    Welchen SQL-Server?

    Wenn Du den MS SQL-Server meinst, so ist das eine schwäche des Servers der AFAIK erst in der 2005er-Version gelößt wird. Er hat nämlich kein Multi-Version-Konzept realisiert. D.h. wird ein Datensatz in einer Transaktion geändert, so kann keine andere Anwendung diesen Datensatz lesen (wir gestoppt), außer sie gibt sich auch mit dem neuen Wert zufrieden, welcher noch nicht in der Transaktion abgeschlossen wurde

    Comment


    • #3
      Ja, ich meine den MS SQL-Server.

      Das mit dem Zugriff auf den gleichen Datensatz ist okay.
      Mein Problem ist aber, das die ganze Tabelle gesperrt ist.

      Heißt:
      BeginTrans -- insert into (..) -- Commit

      Während der Transaction ist "nicht einmal" ein Select count(*) auf diese Tabelle möglich.

      Ist es nicht möglich auf Datensätze der Tabelle zu zugreifen, die sich schon vor der Transaction darin befunden haben?

      Tnx.
      Oll

      Comment


      • #4
        Wenn du mit "Select count(*)" wird ja auch versucht die neu eingefügten Datensätze anzuzeigen.

        Wenn es nur um die Anzahl der Zeilen geht:

        SELECT rows FROM dbo.sysindexes WHERE (id IN (SELECT id FROM dbo.sysobjects WHERE (name = 'Table1')))

        Comment


        • #5
          leider geht es nicht nur um die Anzahl der Zeilen.

          Brauche eigentlich ein DataSet mit Select * from table where status=20.
          Damit sollten mir alle (vor der Transaction) vorhandenen Sätze mit dem angegebenen Status (DB-Feld) geliefert werden.

          tnx so far...

          Comment


          • #6
            An der C++ Applikation kannst du leider nichts einstellen. Ein Insert wird immer Locks setzen.

            Du kannst den lesenden Anwendungen nur sagen das sie vorhandene Locks ignorieren oder überlesen sollen. Das kann man mit Tablehints im SQL schalten. Such mal im SQL Onlinehandbuch unter 'Sperrhinweise auf Tabellenebene'.

            Da der SQL Server , wie Benhard schon anmerkte, keine Versionierung beherscht(Halte ich im übrigen eher für einen Vorteil als einen Nachteil, ist aber eine andere Geschichte) mußt du dich entscheiden ob du Dirty Reads zuläßt mit NOLOCK un d somit die durch die C++ Anwendung geschrieben Daten schon sehen willst. Oder ob du gesperrte Records einfach überlesen willst (READPAST) , diese würden also zum Beispiel bei einem Select Count einfach nicht mitgezählt.

            Gruß Ral

            Comment


            • #7
              Danke für die Hinweise ich werd's mal mit Ralf's Vorschlag probieren. Eine Verwendung von NOLOCK ist nicht gewünscht.

              tnx
              Oll

              Comment


              • #8
                Hallo nochmal,

                der Tipp von Ralf mit (READPAST) hat funktioniert - Super!

                Nun werde ich aber *unverschämt* ;-)

                Kann man so eine Option auch irgendwie einem Update-Statement mitgeben?
                Ich müsste nach dem Select und weiteren Schritten die selektierten Rows im Status-Feld aktualisieren, also ala UPDATE Table set Status=50 WHERE....

                Ginge das auch irgendwie?

                tnx
                Oll

                Comment


                • #9
                  > Oder ob du gesperrte Records einfach überlesen willst (READPAST) , diese würden also zum Beispiel bei einem Select Count einfach nicht mitgezählt.

                  Bei Nur-Insert's mag das ja noch passen, aber bei Updates halte ich die Option READPAST für ziemlich sinnlos. Und vor allem wie verträgt sich das mit dem ACID-Prinzip? Du bekommst ein Ergebnis welche zu keinem Zeitpunkt einen gültigen Zustand der Datenbank darstellt. Weder vor dem Start der Transaktion noch dem nach der Transaktion. Ich halte diese Option eher für einen Notnagel aufgrund des fehlenden Multi-Versions-Konzepts um Timeouts und Fehlermeldungen zu vermeiden

                  Comment


                  • #10
                    @Oliver
                    Das solle eigentlich so schon ohne Eingriff möglich sein.(Du versuchst doch nicht die gleichen Datensätze upzudaten die das C++ Programm gerade am Wickel hat oder?) Du solltest vielleicht im Enterprise Manager mal beobachten welche Art von Locks auf der Tabelle angelegt werden. Solange das C++ Programm nur Rowlocks nimmt solltest du deine eigenen Updates problemlos durchführen können.

                    @Bernd
                    Ob das sinnvoll ist oder nicht hängt natürlich vom Context ab in dem er den Hint einsetzt, denn wir beide nicht wirklich kennen. Wie immer gilt 'Man muß schon wissen was man tut'. Ich persönlich würde READPAST aber auch eher vermeiden.

                    Das eigentliche Problem wird wohl sein das in der C++ Anwendung die Transaktion viel zu lange offen gehalten wird (Ganz einfach weil das unter Oracle -auf den ersten Blick- kein Problem macht).
                    Vermutlich werden Daten gelesen, bearbeitet und währenddessen in die DB geschrieben. Wobei die ganze Zeit eine Transaktion offen gehalten wird. Dies sollte man eigentlich nicht tun, sondern ohne Transaktion(oder in einer eigenen) die Daten lesen und bearbeiten. Alle Datenbankänderungen währenddessen cachen und wenn man alles zusammen hat in einer kurzen Transaktion in einem Rutsch wegschreiben.

                    Ral

                    Comment


                    • #11
                      Dooh, irgendwie hab ich Probleme mit deinem Namen.
                      Bitte, Bitte verzeih er mir.*Winselnd auf die Knie fall*

                      Ich schnapp mir jetzt Notepad und schreib 1000 mal zur Strafe
                      'Ich werde Bernhard nur noch Bernhard nennen.'.

                      Gruß und Sorry
                      Ral

                      Comment


                      • #12
                        #(Du versuchst doch nicht die gleichen Datensätze upzudaten die das C++ Programm gerade am Wickel hat oder?)
                        Nein das versuche ich natürlich nicht.

                        #Das eigentliche Problem wird wohl sein das in der C++ Anwendung die Transaktion viel zu lange offen gehalten wird
                        Das sehe ich schon auch so, aber ist die "Vorgabe"
                        (Hintergrund: C++ holt Daten (als Stream) von einer Quelle ab, es ist ein Stream, der n Sätze enthält (jeder Satz ein Insert); nur wenn ALLE Daten korrekt übertragen sind (Stream zu Ende), dann die Inserts "Committen")

                        #Du solltest vielleicht im Enterprise Manager mal beobachten welche Art von Locks auf der Tabelle angelegt werden

                        sorry, aber wo sehe ich das detailiert bzw. wie ist nachfolgendes zu interpretieren?
                        Im EPM unter Sperren / ProcessID steht:
                        Sperrtyp: DB
                        Modus: S
                        Status: Grant
                        Besitzer: Sess
                        Index: Table1

                        unter Sperren / Objekte steht
                        Sperrtyp: DB
                        Modus: S
                        Status: Grant
                        Besitzer: Sess
                        Index: Table1

                        riesen Dank schonmal für die Hilfe

                        Comment


                        • #13
                          ..ein weiterer Test ergab zwei Sperren beim Insert-Statement:
                          Sperrtyp: TAB, Modus: IX und
                          Sperrtyp: RID, Modus: X

                          Wie könnte man beim Insert eine Sperre "nur" auf Zeilenebene erreichen?

                          Tnx und schönes Wochenende
                          Oll

                          Comment


                          • #14
                            Sperre TAB im Modus IX ist eine exclusive Tabellensperre und hört sich problematisch an. Versuch mal die Inserts in der C++Anwendung mit dem Tablehint ROWLOCK zu versehen(unter der Annahme das die Sperre von diesen Inserts stammt).

                            Ral

                            Comment


                            • #15
                              Hallo Ralf,

                              komisch, wenn ich ein insert into table1 with (rowlock) values(...) mache habe ich trotzdem einen Sperrtyp: PAG und Modus IX.

                              Ein Update auf eine vorhandene Row ist somit wieder nicht möglich.
                              Ich glaube ich sollte evtl. doch die Vorgabe "in Frage" stellen ;-)

                              tnx
                              Oll

                              Comment

                              Working...
                              X