bfuerchau hat geschrieben: So 30. Jul 2023, 14:16
Meine aufrufenden Transaktionen sind grundsätzlich ReadCommited. Da via ODBC-Treiber oder NetProvider immer nit RecVersion.
Wenn ich nach dem Execute mit IBExpert (der läuft auch noch) reinsehe, ist der Index aktiv und die Selekitivity passt.
Danach ja, aber dann ist die TX des execute blocks bereits committet und IBE benutzt eine neue TX. Dann natürlich.
Aber es geht um die Sichtbarkeit
innerhalb einer Transaktion und
innerhalb einer stored routine oder eines execute blocks bei ReadConsistency. Der execute block gibt Dir nicht die korrekte Satzzahl zurück, wenn bei ReadCommitted das sub-level ReadConsistency = 1 konfiguriert ist, durch den Schalter ReadConsistency = 1 in firebird.conf. Dann wird Dein sub-level record_version ignoriert. Und eine stored routine oder ein execute block sieht bei ReadCommitted dann nur noch die eigenen Änderungen, aber nicht mehr die anderer Transaktionen, selbst wenn die
nach seinem Start committet wurden, und
bevor er die Änderungen abfragt, alles noch in der eigenen Transaktion. Das ist grundlegend anders als bisher. Bisher (ReadConsistency = 0, egal ob record_version oder no record_version) hat eine stored routine oder ein execute block, der in einer ReadCommited TX ausgeführt wurde, zwischenzeitlich commitete Änderungen anderer Transaktionen innerhalb seines bodies gesehen. Das ist ja genau der Zweck und die Definition von ReadCommitted, maximale Sichtbarkeit und Nebenläufigkeit von Datenänderungen, ohne dafür die Konsistenz zu opfern wie etwa bei Dirty Read (was es bei Firebird nicht gibt).
Ich habe Dein Beispiel eben noch mal getestet, ziemlich vereinfacht, und das zeigt es ganz klar. Vorbereitung eine Testtabelle tbl mit einer Spalte und zwei Datensätzen, das langt:
Code: Alles auswählen
insert into tbl values (1);
insert into tbl values (2);
Dann der execute block:
Code: Alles auswählen
execute block returns (xCount integer) as
begin
in autonomous transaction do
execute statement 'create index TBL_X2 on TBL (NUM)';
-- in autonomous transaction do
select round(coalesce(1 / nullif(rdb$statistics, 0), 0), 0)
from rdb$indices
where rdb$index_name = 'TBL_X2'
into :xCount;
suspend;
end;
Da kriegst Du <null> als xcount, weil die Änderung der rdb$indices durch die autonome Transaktion für den execute block nicht sichtbar ist, obwohl sie committet ist.
Dann lösch den gerade erzeugten Index tbl_x2:
und mach den Gegentest, indem Du im execute block die auskommentierte Zeile "-- in autonomous transaction do" aktivierst. Nur dann liefert der execute block das korrekte Ergebnis, nämlich 2.
Durch den Schalter ReadConsistency = 1 verhalten sich stored routines und execute blocks bei ReadCommitted intern, in ihrem body, wie bei Isolation Level Snapshot! Sie sehen nur commits, die vor ihrem Start committet waren, aber keine mehr seitdem.
Ich bin gerade mit Vlad da dran, weil das ganz grundlegende weitreichende Konsequenzen hat. Das ist mir leider erst vor kurzem aufgefallen, im Zusammenhang mit Firebird 5, vorher hatte ich ReadConsistency auf 0, bei Firebird 4, nach dem Motto, erstmal defensiv alle Schalter auf legacy, und dann nach und nach umstellen. Das ReadCommitted-Sublevel ReadConsistency gibt es schon einige Jahre, und wurde vor Jahren auch ausgiebig diskutiert, anscheinend nicht genug. Der Test oben betrifft Versionen ab Firebird 4. Betroffen sind alle, die PSQL-Code einsetzen, der ReadCommitted-Sichtbarkeit auch
innerhalb des PSQL-Codes voraussetzt. Also in stored procedures, stored functions, trigger, execute blocks.
Grüße, Volker