{"id":832,"date":"2007-12-05T19:17:20","date_gmt":"2007-12-05T18:17:20","guid":{"rendered":"http:\/\/www.glorf.it\/blog\/2007\/12\/05\/allgemein\/blockierungen-bei-updates-auf-unterschiedlichen-datensaetzen"},"modified":"2007-12-05T21:35:38","modified_gmt":"2007-12-05T20:35:38","slug":"blockierungen-bei-updates-auf-unterschiedlichen-datensaetzen","status":"publish","type":"post","link":"http:\/\/www.glorf.it\/blog\/2007\/12\/05\/allgemein\/blockierungen-bei-updates-auf-unterschiedlichen-datensaetzen","title":{"rendered":"Blockierungen bei Updates auf unterschiedlichen Datens&#228;tzen"},"content":{"rendered":"<p>Die <a href=\"http:\/\/www.glorf.it\/blog\/2007\/12\/04\/sql-talk\/updates-auf-unterschiedliche-datensaetze-klare-sache\">Frage<\/a> lautete:<\/p>\n<blockquote><p>Auf Verbindung 1 wird in einer etwas l&#228;ngeren Transaktion (ja, macht man nicht, aber nur mal angenommen..) der Datensatz mit ID &quot;0815\u2033 ge&#228;ndert.<\/p>\n<p>Auf Verbindung 2 wird jetzt ein UPDATE-Befehl auf den Datensatz mit der ID &quot;4711\u2033 abgesetzt (\u2026 WHERE ID = 4711).<\/p>\n<p>Geht der UPDATE auf der Verbindung 2 glatt durch oder wird er von Verbindung 1 blockiert?<\/p><\/blockquote>\n<p>Das kommt darauf an&#8230;.<\/p>\n<p><strong>Tabelle ohne Index<\/strong><\/p>\n<p>Gehen wir mal davon aus, die Tabelle ist ein Heap, also eine Tabelle ohne Clustered Index, au&#223;erdem sind gar keine Indexes darauf. Dann muss der SQL-Server wohl oder &#252;bel einen Table-Scan durchf&#252;hren um die betroffenen S&#228;tze zu finden. Dazu liest er jeden Satz durch. Auf den gerade untersuchten Satz wird eine Update-Sperre (U) gesetzt. Ist der Datensatz betroffen, dann wird sie ein eine Exklusiv-Sperre (X) umgewandelt, sonst sofort wieder freigegeben.<\/p>\n<p>Wegen des Table-Scan versucht Verbindung 2 auch den Satz mit ID 0815 zu lesen (er liest alle S&#228;tze der Tabelle). Der ist schon gesperrt, daher wird die <strong>Verbindung blockiert<\/strong>. Der zweite muss warten und versteht nicht warum&#8230; \ud83d\ude09<\/p>\n<p>Der SQL-Server-2005 verwendet hier &#252;brigens Satz-Sperren, w&#228;hrend der 2000er generell beim Table-Scan Seitensperren verwendete. In den anderen unten genannten F&#228;llen verhalten sich die Systeme gleich.<\/p>\n<p><strong>Tabelle mit Index<\/strong><\/p>\n<p>Hat die Tabelle einen Index auf dem Suchfeld (hier ID), dann sieht es anders aus. Sowohl bei einem Clustered-Index als auch einem normalen Index kann der SQL-Server den Datensatz direkt mittels Index-Seek anspringen. <\/p>\n<p>Daher tritt hier <strong>keine Blockierung<\/strong> auf.<\/p>\n<p><strong>Tabelle mit Index, Suche &#252;ber zwei Felder<\/strong><\/p>\n<p>Angenommen wir filtern nicht &#252;ber die ID, sondern &#252;ber zwei Felder, z.B. Kundennummer und laufende-Nummer (&#8230; WHERE KDNR=4711 AND LFDNR=10). Nur auf einem davon ist ein Index: Auf der Kundennummer liegt ein nicht-eindeutiger Index, pro Kundennummer kann es zig laufende Nummern geben.<\/p>\n<p>Dann macht der SQL-Server zwar einen Index-Seek auf alle S&#228;tze mit KDNR=4711, aber er muss f&#252;r alle potentiell betroffenen S&#228;tze nachsehen, welchen Wert LFDNR hat. Daher wird auch hier <strong>eine Blockierung auftreten<\/strong>, wenn zuf&#228;llig ein anderer Satz mit der gleichen Kundennummer schon exklusiv gesperrt ist.<\/p>\n<p><strong>Res&#252;mee<\/strong><\/p>\n<p>Ob es bei zwei UPDATEs auf unterschiedlichen Datens&#228;tzen zu einer Blockierung kommt oder nicht, h&#228;ngt ganz allein vom Zugriffsplan des &quot;Zweiten&quot; ab. Der Nutzen der richtigen Indexe kann gar nicht hoch genug bewertet werden.<\/p>\n<p>Und wie schon Cato sagte: Transaktionen m&#252;ssen immer so kurz wie m&#246;glich sein.<\/p>\n<p><strong>Ausschlussklauseln<\/strong><\/p>\n<ul>\n<li>Das Geschriebene gilt auch f&#252;r DELETEs.<\/li>\n<li>Man kann die Blockierung nicht wirklich umgehen. Man kann lediglich mittels READPAST angeben, dass gesperrte Datens&#228;tze &#252;bersprungen werden. Das macht aber wirklich nur dann Sinn, wenn es wirklich egal ist, ob alle vom UPDATE oder DELETE betroffenen Datens&#228;tze ge&#228;ndert werden.<\/li>\n<li>Wenn man den Isolation-Level &quot;SNAPSHOT&quot; verwendet, dann k&#246;nnte es anders sein, das habe ich nicht ausprobiert. <\/li>\n<li>Wenn man SERIALIZABLE verwendet, dann ist es &#228;hnlich nur schlimmer, weil dann jede Menge RangeS-U-Locks gesetzt werden. Aber wann macht man schon SERIALIZABLE bei UPDATEs oder DELETEs?<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Die Frage lautete: Auf Verbindung 1 wird in einer etwas l&#228;ngeren Transaktion (ja, macht man nicht, aber nur mal angenommen..) der Datensatz mit ID &quot;0815\u2033 ge&#228;ndert. Auf Verbindung 2 wird jetzt ein UPDATE-Befehl auf den Datensatz mit der ID &quot;4711\u2033 abgesetzt (\u2026 WHERE ID = 4711). Geht der UPDATE auf der Verbindung 2 glatt durch [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/832"}],"collection":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/comments?post=832"}],"version-history":[{"count":0,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/832\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/media?parent=832"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/categories?post=832"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/tags?post=832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}