Announcement

Collapse
No announcement yet.

MS SQL Server 7 update von Feldern dauert sehr lange

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

  • MS SQL Server 7 update von Feldern dauert sehr lange

    Hi, ...
    <br>diese Frage habe ich auch schon unter der Rubrik SQL Server gestellt aber ich hoffe das hier mehr gelesen wird.
    <br>ich habe neue Datensätze an die Tabelle tbl1 (Tabelle enthält viele Datensätze) angefügt. Wenn ich nun bei diesen neuen Datensätzen ein update mache in FeldX, so dauert die ausführung sehr lange. Mache ich das selbe update bei älteren Datensätzen und dem selben FeldX, so wird das update direkt ausgeführt. Wie kann so was passieren und was kann man dagegen machen?
    <br>
    <br>
    PS

  • #2
    Hallo,

    wie sieht der Primärschlüssel der Tabelle aus? Angenommen, alle neuen Datensätze werden bei einem fortlaufend hochgezählten Primärschlüsselwert immer an das logische "Ende" der Tabelle angefügt, so werden im Mehrbenutzerbetrieb alle Benutzer auf diese Datenbankseite (Page) zugreifen. In Abhängigkeit vom gewählten Isolation Level (SERIALIZABLE, REPEATABLE READ usw.) kann es nun passieren, dass sich mehrere Benutzer mit ihren ausgelösten Seiten- bzw. Index-Sperren in die Quere kommen, so dass alle Zugriffe auf die gemeinsam beanspruchte Seite nacheinander abgearbeitet werden.

    Bei einem Zugriff auf einen "alten" Datensatz, dessen Primärschlüsselwert auf eine Datenbankseite irgendwo in der "Mitte" verweist, hat der Anwender beim UPDATE alleinigen Zugriff, so dass es sehr unwahrscheinlich ist, dass es zu Kollisionen kommt.

    Microsoft rät daher in der Dokumenation des SQL Server 7, den Primärschlüssel so zu wählen, dass keine fortlaufenden Werte entstehen, sondern statt dessen auf einen CLUSTERED INDEX zurückzugreifen, der alle neu eingefügten Datensätze "breit streut"

    Comment


    • #3
      <br>Hi,...
      <br>
      <br>danke für die Antwort
      <br>ja es ist so, daß es sich hierbei um ein Primärschlüsselfeld vom Typ Integer mit einer Schrittweite von 1 (Autowert) handelt. Als die Daten erzeugt wurden, als das insert getätigt wurde, waren mehrere Benutzer an der Datenbank angemeldet. Jedoch bin ich nun der Einzige, der auf die Datenbank zugreift und trotz alledem dauert das Update noch so lange. Was mir noch aufgefallen ist:
      Bei einem update eines Datensatzes bekomme ich immer ein Time out im Frontend (eben weil es zu lange dauert). Also wurde das update bei genau diesem Datensatz auch nicht ausgeführt. Nun bin ich mal in die Trigger gegangen und habe mir via Print einige Infos ausgeben lassen und ulkiger Weise geht das update immer dann bei genau den selben Daten sätzen schnell, wenn eine Änderung in dem Trigger (neukompilierung) statt findet. Von dem CLUSTER INDEX möchte ich mich ersteinmal fernhalten, da die Datenbank ansonsten ganz gut läuft.
      Zu den Sperren:
      ich habe mir da zu mal einges durchgelesen und bin der Meinung, das wenn ich der Einzige bin, der z.B. über ein Select Statement auf bestimmte Datensätze zugreift, so sollte ich diese mir doch nicht selber sperren können oder? ... Moment!
      In dem Front End benutze ich eine ADO Connection um meine Select Anweisung aus zu führen (ein Grid wird mit Daten gefüllt) dann markiere ich einen Datensatz und drücke Löschen. Darauf hin wird eine neue ADO Connection geöffnet und eine update tbl gemacht (ein gelöscht Flag wird auf true gesetzt) nach dem Update wird die 2. Connection wieder geschlossen. Daran sollte es doch wohl nicht liegen (an den zwei Verbindungen, die sich wohlmöglich gegenseig sperren)oder, zu mal dieser Prozeß des Löschens bei anderen Datensätzen funktioniert.
      Angenommen es liegt nicht an dem obigen Löschprozeß wie kann man während die Datenbank in Benutzung ist solche Funktionsstörungen beseitigen? (Was mich natülich auch interessiert ist, wie so ein Fehler auftreten kann, wenn nur ein Client mit der DB arbeitet)
      <br>
      <br>MfG
      <br>P

      Comment


      • #4
        Hallo,

        was bedeutet "<i>...wenn eine Änderung in dem Trigger (neukompilierung) statt findet.</i>"? Wie sieht die im Trigger ausgelöste Aktion aus? Generell ist jede ADO-Verbindung für den SQL-Server ein "neuer Benutzer", so dass man sich durchaus mit mehreren parallelen Verbindungen selbst in die Quere kommen kann.

        Um dieses Problem einzugrenzen, würde ich folgendes machen: <br>
        a) der Client (Frontend) verwendet für alle ADO-Objekte ein gemeinsames Connection-Objekt. <br>
        b) der Client verzichtet auf den asynchronen Zugriffsmodus, bei dem Daten im Hintergrund geladen werden <br>
        c) der Client verzichtet auf eine Server-Cursor und greift nur auf einen Client-Cursor zurück (d.h. das RecordSet-Objekt arbeitet mit lokal zwischengepufferten Daten). <br>
        d) Was passiert, wenn vor dem Abschicken der "Lösch"-Anweisung die erste Datenmenge (Anzeige im DBGrid) geschlossen und hinterher wieder geöffnet wird?

        Alle Aktionen sollten über den <i>SQL Server 7 Profiler</i> nachkontrolliert werden, wobei es darum geht, welche SQL-Aktionen das Frontend tatsächlich in der jeweiligen Situation auslöst. Nur so lassen sich die "Nebenwirkungen" wie zum Beispiel beim Aufruf von Refresh drastisch vor Augen führen.

        &#10

        Comment


        • #5
          <br>Hi,...
          <br>
          <br>a und c getestet jedoch der selbe Fehler
          <br>
          <br>zu Trigger:
          <br>Änderungen in der Art, dass man ein Zeichen drückt, dieses wieder löscht und so dem System vorgaukelt man hätte eine Änderung gemacht. Ich denke das das vielleicht was mit dem Trigger zu tun hat (aufgrund des genannten Effektes)...
          <br>habe in dem Trigger alles auskommentiert bis auf den Code der Ref.Integrität. Noch immer dauert es zu lange und ich erhalte einen Time Out im Frontend (Wenn ich das update im Query Analyser laufen lasse, so dauert es zwar aber es wird letzten Endes doch ausgeführt). Was ich aber noch immer nicht verstehe ist, dass nach der Speicherung des Triggers einmalig ein update schnell funktioniert.
          <br>Den Profiler werde ich mir mal morgen zu Gemüte führen. In dem SQL Server ODBC Treiber habe ich keine Möglichkeit gefunden, den Time Out zu erhöhen kannn man das irgendwie machen ? Und was ich auch nicht verstehe: angenommen meine beiden connections würden sich gegenseitig sperren, wieso bekomme ich dann keine Fehlermeldung, dass der Datensatz gesperrt ist?
          <br>
          <br>MfG
          <br>P

          Comment


          • #6
            <br>Hi,...
            <br>
            <br>Anscheinend habe ich Fall D nicht richtig durchgeführt. Es funktioniert nämlich schon wenn man das Select des Grids vor dem Löschen kurz ändert und danach wieder zurück setzt. Gefällt mir zwar nicht besonders aber es hilft. Vieleicht finde ich bei Zeiten ja noch eine andere Lösung.
            <br>
            <br>Danke für die Hilfe
            <br>
            <br>MfG
            <br>P

            Comment


            • #7
              Hallo,

              was bedeutet "... das SELECT des Grid vor dem Löschen kurz ändert und danach wieder zurück setzt..."? Das sieht alles so aus, als ob im Hintergrund doch asynchrone Sachen ablaufen und eine Operation zu einem Zeitpunkt durchgeführt werden soll, zu dem die erste Operation (ADO-Recordset?) noch nicht abgeschlossen ist. Das Beste wird sein, alles im Profiler mitzuverfolgen

              Comment


              • #8
                Hi,...
                <BR>
                <BR>den Profiler habe ich mir mal kurz angesehen habe dort aber nichts genaues sehen können, da eine Sinnflut von Informationen auf mich nieder prasselte, als das Kommando ausgeführt wurde (sehr wahrscheinlich habe ich den Profiler nicht richtig genutzt). Das mit dem Select soll folgendes bedeuten:
                <BR>Select * From tbl where ID = 100; ist Basis des Grids
                <BR>nun wird im Programm code kurz die Daten Basis geändert
                <BR>Select * From tbl where ID = 0; (zeigt keine Daten an)
                <BR>update tbl (x) values(1) where id = 100;
                <BR>und nun wird die Datenbasis wieder hergestellt:
                <BR>Select * From tbl where ID = 100;
                <BR>
                <BR>(Die Select Statements sind vereinfacht dargestellt)
                <BR>
                <BR>Wenn die Operation noch nicht abgeschlossen wäre (angenommen es sei eine Front end Operation) dann könnte ich gar nicht im Code weiter machen. Des weiteren würde das ja bedeuten, dass wenn man mit dem update befehl lange genug wartet kein Fehler auftreten würde (das müßte ilch mal testen)
                <BR>
                <BR>MfG
                <BR>P

                Comment


                • #9
                  Hallo,

                  im asynchronen Modus spaltet ADO automatisch einen separaten Thread ab, um den primären Thread der eigenen Anwendung nicht zu blockieren. Aber das ist nicht der Grund - statt dessen wird die <b>zweite</b> TADOConnection-Instanz der "Übertäter" sein. Wenn <b>clUseServer</b> (Server-side Cursor) verwendet wird, setzt der SQL Server 7 bei bestimmten Konfigurations-Kombinationen einen <b>Update-Lock</b> ein und blockiert somit den aktuell angezeigten Datensatz (immer dann, wenn beim Zugriff über ADO für das Recordset einen Server-side-Cursor in Kombination mit dem pessimistischen Sperrverfahren anfordert wird, greift der SQL Server anstelle des Shared-Locks auf einen Update-Lock zu). Im Gegensatz zu einem echten X-Lock führt ein gesetzter Update-Lock nicht dazu, dass andere Transaktionen den Datensatz nicht mehr lesen können. Auch bei einem aktiven Update-Lock kann eine andere Transaktion über SELECT einen S-Lock auf den gleichen Datensatz setzen. Für das Updaten eines Feldes wird jedoch ein echter X-Lock benötigt, und hier sorgt das Update-Lock dafür, dass diese Anforderung bis zum Transaktionsende bzw. Timeout verschoben wird.

                  Um zu prüfen, ob dieser Sonderfall vorliegt, würde ich<br>
                  a) entweder nur eine einzige ADO-Connection aufbauen (gleicher Transaktions-Kontext) oder<br>
                  b) zu einem <b>clUseClient</b>-Cursor wechseln

                  Comment


                  • #10
                    <br>Hi,...
                    habe dem Grid (es soll ja nur Datenanzeigen) eine SQL Pass Throug Abfrage zu geteilt mit der Syntax Select ... From Table1 (NoLock) ...
                    <br>und es funktioniert (Vielen Dank für die Hilfestellungen). Ich denke mal bei einer Datenquelle, die nur Datenanzeigen soll kann man (NoLock) einsetzen oder nicht?
                    <br>
                    <br>MfG
                    <br>P

                    Comment


                    • #11
                      Hallo,

                      dieser Weg (LOLOCK) geht auch

                      Comment

                      Working...
                      X