Locking-Problem in Oracle8.1.7

hi!

ich habe ein äußerst dringendes problem und komme weder mit der oracle-help-line, noch mit metalink oder technet weiter:

db-server: w2k
oracle: 8.1.7.4, standard edition
clients: citrix (w2k)
applikation: forms6i (patch4a)

  • auf eine tabelle wird äußerst oft von sehr vielen usern auf unterschiedliche datensätze zugegriffen
  • alle machen selects, inserts und - das problem - updates darauf; alles funktioniert wunderbar
  • bis plötzlich (ca. 1xtäglich) ein user alle anderen lockt, obwohl diese auf komplett andere datensätze zugreifen und dieser user auch nur „seinen“ satz gelockt hat; das commit 10 minuten später erledigt das ganze - nur daß dieser user natürlich nicht weiß, daß noch andere warten und diese ziemlich sauer sind

kennt vielleicht irgendwer irgendwelche oracle-probleme in dieser hinsicht?

gibt’s irgendwo scripts, aus deren ergebnis man mehr ablesen kann?

oder bin ich nur zu blind, um die lösung zu sehen?

danke für jede hilfe,
tomh

Hi,

  • bis plötzlich (ca. 1xtäglich) ein user alle anderen lockt,
    obwohl diese auf komplett andere datensätze zugreifen und
    dieser user auch nur „seinen“ satz gelockt hat; das commit 10
    minuten später erledigt das ganze - nur daß dieser user
    natürlich nicht weiß, daß noch andere warten und diese
    ziemlich sauer sind

Ich tippe auf einen gelockten Index - der Kollege hat entweder inserted oder in einer Spalte upgedated, die indiziert ist.

kennt vielleicht irgendwer irgendwelche oracle-probleme in
dieser hinsicht?

Das wäre eher Anwendungslogik. Evtl. könnte man ein Timeout einbauen?

gibt’s irgendwo scripts, aus deren ergebnis man mehr ablesen
kann?

DBA_LOCKS angesschaut?

Gruß

Sancho

hi und danke erstmal:

Ich tippe auf einen gelockten Index - der Kollege hat entweder
inserted oder in einer Spalte upgedated, die indiziert ist.

auch mein erster tip: leider nein, die column die geupdatet wird, besitzt lediglich einen not-null-constraint …

kennt vielleicht irgendwer irgendwelche oracle-probleme in
dieser hinsicht?

Das wäre eher Anwendungslogik. Evtl. könnte man ein Timeout
einbauen?

problem: diese tabelle wird von (übertriebenen) 8.324.122 masken angesprochen, jede macht immer nur ein bißchen was, und _meistens_ ist es das update auf ein unscheinbares wie oben beschriebenes column, das sonst niemanden interessiert, in einem satz, der sonst niemanden interessiert

gibt’s irgendwo scripts, aus deren ergebnis man mehr ablesen
kann?

DBA_LOCKS angesschaut?

ähem, alle v_$lock angeschaut und versucht zu analysieren, jedoch nicht recht schlauer geworden (was bedeuten die felder addr, kaddr, … ???)

danke erstmal,
tomh

Hi,

auch mein erster tip: leider nein, die column die geupdatet
wird, besitzt lediglich einen not-null-constraint …

Strange…

problem: diese tabelle wird von (übertriebenen) 8.324.122
masken angesprochen, jede macht immer nur ein bißchen was, und
_meistens_ ist es das update auf ein unscheinbares wie oben
beschriebenes column, das sonst niemanden interessiert, in
einem satz, der sonst niemanden interessiert

Noch stranger…

DBA_LOCKS angesschaut?

ähem, alle v_$lock angeschaut und versucht zu
analysieren, jedoch nicht recht schlauer geworden (was
bedeuten die felder addr, kaddr, … ???)

Im Rohzustand sind sie erst mal weniger brauchbar. Mit TOAD und den serverseitigen Objekten kannst du da besser reinschauen, ansonsten sowas:
http://www.tilsor.com.uy/servicios/soporte_tecnico/d…

Gruß

Sancho

Seass tom!

auch mein erster tip: leider nein, die column die geupdatet
wird, besitzt lediglich einen not-null-constraint …

Bist du dir sicher, dass im Update-Statement nur die eine Column drin steht?

(select sess.sid, sess.serial#, sess.username, sql.piece, sql.sql_text from v$sqltext sql, v$session sess where sql.address=sess.sql_address and sql.hash_value=sess.sql_hash_value order by sess.sid, sql.piece:wink:

Gibt’s foreign keys auf eine der/die Spalte, die im Update drinstehen/drinsteht?

problem: diese tabelle wird von (übertriebenen) 8.324.122
masken angesprochen, jede macht immer nur ein bißchen was, und
_meistens_ ist es das update auf ein unscheinbares wie oben
beschriebenes column, das sonst niemanden interessiert, in
einem satz, der sonst niemanden interessiert

Ich empfehle dringendst herauszufinden, worauf denn wirklich locks existieren.

gibt’s irgendwo scripts, aus deren ergebnis man mehr ablesen
kann?

Bittesehr, du willst es ja nicht anders… :wink:

 SELECT l.sid,
 s.username,
 s.osuser,
 l.type,
 decode( l.type,
 'MR', 'Media Recovery',
 'RT', 'Redo Thread',
 'UN', 'User Name',
 'TX', 'Transaction',
 'TM', 'DML',
 'UL', 'PL/SQL User Lock',
 'DX', 'Distributed Xaction',
 'CF', 'Control File',
 'IS', 'Instance State',
 'FS', 'File Set',
 'IR', 'Instance Recovery',
 'ST', 'Disk Space Transaction',
 'TS', 'Temp Segment',
 'IV', 'Library Cache Invalidation',
 'LS', 'Log Start or Switch',
 'RW', 'Row Wait',
 'SQ', 'Sequence Number',
 'TE', 'Extend Table',
 'TT', 'Temp Table',
 l.type),
 l.id1, o.name,
 null,
 null,
 null,
 decode( lmode,
 0, 'None',
 1, 'Null',
 2, 'Row-S (SS)',
 3, 'Row-X (SX)',
 4, 'Share',
 5, 'S/Row-X (SSX)',
 6, 'Exclusive',
 'Invalid'),
 decode( request,
 0, 'None',
 1, 'Null',
 2, 'Row-S (SS)',
 3, 'Row-X (SX)',
 4, 'Share',
 5, 'S/Row-X (SSX)',
 6, 'Exclusive',
 'Invalid'),
 l.ctime,
 decode( block,
 0, 'Not Blocking',
 1, 'Blocking',
 2, 'Global',
 to\_char(block)),
 c.sql\_text
 FROM v$lock l, v$session s, v$open\_cursor c, sys.obj$ o
 WHERE l.type IN ('TM', 'TX')
 AND l.sid = s.sid
 AND l.sid = c.sid (+)
 AND o.obj#(+) = ID1
union
 SELECT l.sid,
 s.username,
 s.osuser,
 l.type,
 decode( l.type,
 'MR', 'Media Recovery',
 'RT', 'Redo Thread',
 'UN', 'User Name',
 'TX', 'Transaction',
 'TM', 'DML',
 'UL', 'PL/SQL User Lock',
 'DX', 'Distributed Xaction',
 'CF', 'Control File',
 'IS', 'Instance State',
 'FS', 'File Set',
 'IR', 'Instance Recovery',
 'ST', 'Disk Space Transaction',
 'TS', 'Temp Segment',
 'IV', 'Library Cache Invalidation',
 'LS', 'Log Start or Switch',
 'RW', 'Row Wait',
 'SQ', 'Sequence Number',
 'TE', 'Extend Table',
 'TT', 'Temp Table',
 l.type),
 l.id1, NULL,
 null,
 null,
 a.name,
 decode( lmode,
 0, 'None',
 1, 'Null',
 2, 'Row-S (SS)',
 3, 'Row-X (SX)',
 4, 'Share',
 5, 'S/Row-X (SSX)',
 6, 'Exclusive',
 'Invalid'),
 decode( request,
 0, 'None',
 1, 'Null',
 2, 'Row-S (SS)',
 3, 'Row-X (SX)',
 4, 'Share',
 5, 'S/Row-X (SSX)',
 6, 'Exclusive',
 'Invalid'),
 l.ctime,
 decode( block,
 0, 'Not Blocking',
 1, 'Blocking',
 2, 'Global',
 to\_char(block)),
 null
 FROM v$lock l,
 sys.dbms\_lock\_allocated a,
 v$session s
 WHERE l.type = 'UL' AND l.id1 = a.lockid AND l.sid = s.sid;

DBA_LOCKS angesschaut?

Die wird eher nicht weiterhelfen…

ähem, alle v_$lock angeschaut und versucht zu
analysieren, jedoch nicht recht schlauer geworden (was
bedeuten die felder addr, kaddr, … ???)

Na du willst es aber genau wissen. http://www.google.com/search?hl=en&lr=&ie=UTF-8&q=ka…

danke erstmal,
tomh

Ich hoffe das hilft dir weiter. Sonst komm’ ich halt einmal kurz vorbei. Musst dich nur mit meinem Chef auf einen Stundensatz einigen *ggg*

Liebe Grüße
Martin

1 Like

schönen guten morgen, martin!

Bist du dir sicher, dass im Update-Statement nur die eine
Column drin steht?

kurze vorgeschichte: der entwicklungsleiter dieses projektes ist mit 1.6.04 (freiwillig) ausgeschieden, hat bereits ein paar wochen vorarbeit geleistet und ist schließlich auf dieses update gekommen - und ich knabbere seit dienstag an diesem problem und weiß absolut nimmer weiter (hab dieselben ergebnisse wie mein vorgänger rausbekommen)

(select sess.sid, sess.serial#, sess.username, sql.piece,
sql.sql_text from v$sqltext sql, v$session sess where
sql.address=sess.sql_address and
sql.hash_value=sess.sql_hash_value order by sess.sid,
sql.piece:wink:

Gibt’s foreign keys auf eine der/die Spalte, die im Update
drinstehen/drinsteht?

genau das ist es ja: nix, njet, null … das ist es ja, was unsere köpfe zum rauchen bringt …

Ich empfehle dringendst herauszufinden, worauf denn wirklich
locks existieren.

row locks in der table

Bittesehr, du willst es ja nicht anders… :wink:

JA! sowas wünsch ich mir (hab mittlerweile im metalink doch ein paar scriptchen gefunden)

jetzt muß ich _nur_ noch warten, daß der lock wieder auftaucht (wetten, jetzt taucht er tagelang nimmer auf!)

Na du willst es aber genau wissen.
http://www.google.com/search?hl=en&lr=&ie=UTF-8&q=ka…

mein ausbildner in den letzten 6 monaten war google … ich will nimmer googeln

Ich hoffe das hilft dir weiter. Sonst komm’ ich halt einmal
kurz vorbei. Musst dich nur mit meinem Chef auf einen
Stundensatz einigen *ggg*

hehehe - da werden sich unsere chefs aber nicht recht einigen können - meiner ist der meinung, wir können alles und brauchen keine hilfe … in keinen bereichen (voriges jahr hat er mich ernsthaft gefraft, ob ich mich mit klimaanlagen auskenne, da unsere im serverraum hin war …)

grüße und danke,
tomh

Hallo,

Du solltest Dir das ganze mal in der Management Console (unter 8.1.7 evtl noch DBA nochetwas) unter „Sessions“ ansehen. Da findest Du die SQL Statements, die die Benutzer gerade ausführen. Du brauchst nur bei denen mit der Uhr dran zu schauen.

Ansonsten hat Oracle immer einen Row-Level Lock. D.h. es werden immer nur die Zeilen gesperrt, die geändert werden. Lesen darf man immer, SELECT FOR UPDATE ist gesperrt und wartet. Es sollte also nicht sein, dass ein Lock auf einen Zeile ein Update auf einen andere Zeile beeinflußt.

Es sei denn, du betreibst die Datenbank mit SET TRANSACTION ISOLATION LEVEL SERIALIZABLE. Dann muss auch ein SELECT auf das COMMIT warten.

Insgesamt: so was sollte in einer Anwendung nicht vorkommen, dass ein Datensatz über längere Zeit hinweg gesperrt wird. Das Problem liegt also am Design der Anwendung.

Gruß

Peter

Hallo Peter!

Du solltest Dir das ganze mal in der Management Console (unter
8.1.7 evtl noch DBA nochetwas) unter „Sessions“ ansehen. Da
findest Du die SQL Statements, die die Benutzer gerade
ausführen. Du brauchst nur bei denen mit der Uhr dran zu
schauen.

Die Tools - so gut sie auch sein mögen - laufen bei mir unter Klickibunti (soll heissen: ich traue denen nicht). Ich mach immer noch lieber meine SELECT * FROM v$irgendwas. Ist aber natürlich Geschmackssache.

Ansonsten hat Oracle immer einen Row-Level Lock. D.h. es
werden immer nur die Zeilen gesperrt, die geändert werden.
Lesen darf man immer, SELECT FOR UPDATE ist gesperrt und
wartet. Es sollte also nicht sein, dass ein Lock auf einen
Zeile ein Update auf einen andere Zeile beeinflußt.

Das ist so nicht richtig. Ein Update auf eine Spalte, die zum Primary Key gehört muss zwangsläufig immer die gesamte Tabelle sperren. Noch lustiger wird’s beim Update auf eine Spalte, auf die ein Foreign Key existiert. Der sperrt nämlich fatalerweise die Fremdtabelle (was zu lustigen Lock-suchen führen kann, weil es halt gar so undurchsichtig ist, warum um Gottes Willen ein Update auf Tabelle A die gesamte Tabelle B sperrt).

Es sei denn, du betreibst die Datenbank mit SET TRANSACTION
ISOLATION LEVEL SERIALIZABLE. Dann muss auch ein SELECT auf
das COMMIT warten.

Tut das jemand?

Insgesamt: so was sollte in einer Anwendung nicht vorkommen,
dass ein Datensatz über längere Zeit hinweg gesperrt wird. Das
Problem liegt also am Design der Anwendung.

Das zu vermeiden ist nicht immer möglich, prinzipiell hast du aber natürlich recht.

Gruß

Peter

Auch einen schönen Gruß
Martin

Hallo Peter!

Du solltest Dir das ganze mal in der Management Console (unter
8.1.7 evtl noch DBA nochetwas) unter „Sessions“ ansehen. Da
findest Du die SQL Statements, die die Benutzer gerade
ausführen. Du brauchst nur bei denen mit der Uhr dran zu
schauen.

Die Tools - so gut sie auch sein mögen - laufen bei mir unter
Klickibunti (soll heissen: ich traue denen nicht). Ich mach
immer noch lieber meine SELECT * FROM v$irgendwas. Ist aber
natürlich Geschmackssache.

Versuchs mal. Ist gar nicht so schlecht. Kann zwar nie das gute alte SQl Skipt ersetzen, das man immer wieder durchlaufen lassen kann, ist aber für die Fehlersuche ist es echt gut. Und auch zum Optimieren. Ich zeige das immer gerne in der Vorlesung, weil man da einiges viel einfacher sieht.

Ansonsten hat Oracle immer einen Row-Level Lock. D.h. es
werden immer nur die Zeilen gesperrt, die geändert werden.
Lesen darf man immer, SELECT FOR UPDATE ist gesperrt und
wartet. Es sollte also nicht sein, dass ein Lock auf einen
Zeile ein Update auf einen andere Zeile beeinflußt.

Das ist so nicht richtig. Ein Update auf eine Spalte, die zum
Primary Key gehört muss zwangsläufig immer die gesamte Tabelle
sperren. Noch lustiger wird’s beim Update auf eine Spalte, auf
die ein Foreign Key existiert. Der sperrt nämlich fatalerweise
die Fremdtabelle (was zu lustigen Lock-suchen führen kann,
weil es halt gar so undurchsichtig ist, warum um Gottes Willen
ein Update auf Tabelle A die gesamte Tabelle B sperrt).

Dann solltest Du aber schleunigst alle Foreign Key Referenzen indizieren. Das löst dann möglicherweise dieses Problem. (Ich müsste da ein Skript haben, das die nicht indizierten FKs raussucht und anzeigt)
Ich hatte noch nie das Bedürfnis, einen PK zu ändern. Ein PK sollte die nötige Stabilität haben.

Es sei denn, du betreibst die Datenbank mit SET TRANSACTION
ISOLATION LEVEL SERIALIZABLE. Dann muss auch ein SELECT auf
das COMMIT warten.

Tut das jemand?

Nein.

Insgesamt: so was sollte in einer Anwendung nicht vorkommen,
dass ein Datensatz über längere Zeit hinweg gesperrt wird. Das
Problem liegt also am Design der Anwendung.

Das zu vermeiden ist nicht immer möglich, prinzipiell hast du
aber natürlich recht.

Ich hab das so gelöst, dass ich in diesem Fall ein optimistisches Verfahren benutze. Ich mache den Select for update erst, wenns ernst wird, vergleiche die Werte und lasse den Benutzer entscheiden, falls sich zwischen Aufruf und Speichern etwas geändert hat (Zeige ich an). Das ganze habe ich dann noch auf die geänderten Attribute beschränkt. Dadurch hat man die Transaktion auf Sekundenbruchteile verkürzt, ohne ein Lost Update zu riskieren.

Gruß

Peter

Auch einen schönen Gruß
Martin

Gruß

Peter

PS: wenn alles nicht hilft, schau mal bei askTom nach.

hi!

Du solltest Dir das ganze mal in der Management Console (unter 8.1.7 evtl noch DBA nochetwas) unter „Sessions“ ansehen. Da
findest Du die SQL Statements, die die Benutzer gerade
ausführen. Du brauchst nur bei denen mit der Uhr dran zu schauen.

wir benutzen den toad und haben bereits festgestellt, daß kein user einen anderen locken sollte :frowning: (wir wissen, wer mit welchen daten für den lock verantwortlich ist und wer mit welchen daten gesperrt wird)

Ansonsten hat Oracle immer einen Row-Level Lock. D.h. es
werden immer nur die Zeilen gesperrt, die geändert werden.
Lesen darf man immer, SELECT FOR UPDATE ist gesperrt und
wartet. Es sollte also nicht sein, dass ein Lock auf einen
Zeile ein Update auf einen andere Zeile beeinflußt.

Es sei denn, du betreibst die Datenbank mit SET TRANSACTION
ISOLATION LEVEL SERIALIZABLE. Dann muss auch ein SELECT auf
das COMMIT warten.

select hat keine probleme, es handelt sich grundsätzlich um updates

Insgesamt: so was sollte in einer Anwendung nicht vorkommen,
dass ein Datensatz über längere Zeit hinweg gesperrt wird. Das
Problem liegt also am Design der Anwendung.

hierbei handelt es sich um eine „gewachsene“ applikation - eigentlich sind es 6 applikationen (wobei 4 so eng miteinander verknüpft sind, daß sich diese ein schema teilen), die auf 2 instanzen arbeiten und untereinander die daten hin- und herschupfen; die besagte tabelle wird von allen applikationen benötigt und modifiziert; allerdings werden die datensätze durch die applikationen „durchgereicht“, sprich: sobald eine applikation einen datensatz für sich in anspruch nimmt, ist dieser aus datensicht für die anderen applikationen uninteressant

ich vergaß: diese tabelle wird auch noch repliziert, wobei es hier absolut keine probleme gibt

grüße,
tomh

ps: wie sollte es anders sein: das locking-problem trat seit freitag nimmer auf und da deswegen ein bißchen zeit bleibt, hab ich einen tar eröffnet …

Hi Tom!

Rein interessehalber: Bist du bei dem Problem schon weiter gekommen?

Liebe Grüße
Martin