Statement/Transaction/Connection ID einer SQL Abfrage über den Client ermitteln - Für benutzergesteuerten SQL Abbruch

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

Antworten
Helios
Beiträge: 9
Registriert: So 28. Feb 2021, 11:02

Hallo zusammen,
ich nutze Firebird in Kombination mit Lazarus.
Um langlaufende SQL Abfragen sauber abbrechen zu können, z.B. über

Code: Alles auswählen

DELETE FROM MON$STATEMENTS WHERE MON$STATEMENT_ID = statement_id AND MON$TRANSACTION_ID = transaction_id AND MON$ATTACHMENT_ID = connection_id
benötige ich die SQL Statement ID, Connection (Attachment) ID und die Transaction ID.
Weiss jemand ob und wie ich die über den Client, sprich über die Lazarus Komponenten TIBConnection/TQuery (oder anders?) diese ermitteln kann?
Danke für jeden Hinweis.
Gruß
Helios

PS: Die Tabellen sind indiziert, aber der Benutzer hat die Möglichkeit alle Daten der Datenbank (per Design!) abzufragen, das kann u.U. zu einem Langläufer (Speicherüberlauf und den Abbruch der Abfrage) führen. Dem soll der Benutzer in diesem "Spezialfall" mit einem benutzergesteuerten Abbruch zuvor kommen.
Benutzeravatar
martin.koeditz
Beiträge: 292
Registriert: Sa 31. Mär 2018, 14:35

Hallo Helios,

wenn es um die eigene Verbindung geht, könntest du schonmal auf den Parameter CURRENT_CONNECTION zugreifen.

Code: Alles auswählen

DELETE FROM MON$STATEMENTS 
WHERE MON$STATEMENT_ID = statement_id AND MON$TRANSACTION_ID = transaction_id AND MON$ATTACHMENT_ID = CURRENT_CONNECTION
Das wird vermutlich nur marginal helfen. Ich kenne Lazarus an dieser Stelle zu wenig, aber spricht etwas dagegen, die notwendigen Daten per SQL abzufragen? Zum Beispiel alle aktiven Statements außerhalb der eigenen Verbindung:

Code: Alles auswählen

SELECT
  ATT.MON$USER,
  ATT.MON$REMOTE_ADDRESS,
  STMT.MON$SQL_TEXT,
  STMT.MON$TIMESTAMP
FROM MON$ATTACHMENTS ATT
JOIN MON$STATEMENTS STMT ON ATT.MON$ATTACHMENT_ID = STMT.MON$ATTACHMENT_ID
WHERE ATT.MON$ATTACHMENT_ID <> CURRENT_CONNECTION
AND STMT.MON$STATE = 1
Gruß
Martin
Martin Köditz
it & synergy GmbH
Helios
Beiträge: 9
Registriert: So 28. Feb 2021, 11:02

Hallo Martin,
ja es geht um die eigene Session.
CURRENT_CONNECTION hatte ich noch gar nicht gekannt und mit Deinem Tipp habe ich auch noch CURRENT_TRANSACTION gefunden.
Leider klappt ein

Code: Alles auswählen

DELETE FROM MON$STATEMENTS 
WHERE MON$TRANSACTION_ID = CURRENT_TRANSACTION AND MON$ATTACHMENT_ID = CURRENT_CONNECTION

nicht so wie ich es gedacht hatte (aus der gleichen Session heraus).
Von einer zweiten Applikation funktioniert der

Code: Alles auswählen

DELETE FROM MON$STATEMENTS 
WHERE MON$TRANSACTION_ID = CURRENT_TRANSACTION AND MON$ATTACHMENT_ID = CURRENT_CONNECTION AND MON$STATEMENT_ID = statement_id
wenn ich sie direkt aus der Tabelle MON$STATEMENTS übernehme. Bei einer Embedded Firebird Umgebung hilft mir das aber leider nicht.
Hast Du da noch eine Idee?
Ich habe über das Lazarus Forum noch ein " fb_cancel_operation" als Tipp aus der Firebird API
https://github.com/FirebirdSQL/firebird ... _operation
bekommen. Hast Du das schon mal verwendet? Da finde ich kein Beispiel für.
Danke für Deine Rückmeldung und Gruß
Helios
Benutzeravatar
martin.koeditz
Beiträge: 292
Registriert: Sa 31. Mär 2018, 14:35

Grundätzlich reicht die Angabe von MON$STATEMENT_ID, da diese in MON$STATEMENTS eindeutig ist.

Wenn deine Anweisung explizit erzeugt wird, also in einer eigenen Transaktion heraus, wird die Anweisung eben dieser Transaktion entfernt und nicht die gewünschte.

Code: Alles auswählen

DELETE FROM MON$STATEMENTS 
WHERE MON$TRANSACTION_ID = CURRENT_TRANSACTION AND MON$ATTACHMENT_ID = CURRENT_CONNECTION
Der obige Code entfernt alle Anweisungen, die in der aktuellen (vermutlich gerade geöffneten) Transaktion laufen. Das ist auch die Anweisung selbst.

Also wirst du die korrekte Statement-ID benötigen.

Code: Alles auswählen

DELETE FROM MON$STATEMENTS 
WHERE MON$STATEMENT_ID = XYZ
Gruß
Martin
Martin Köditz
it & synergy GmbH
bfuerchau
Beiträge: 278
Registriert: Mo 7. Mai 2018, 18:09

Du benötigst aber auf jeden Fall eine 2. Verbindung, da du ja die laufende Transaktion abbrechen willst.
Innerhalb einer Anwendung kannst du beliebig viele Connections auch zu embedded DB's herstellen:
http://www.firebirdfaq.org/faq284/

Ich mache das ähnlich auch mit .net/C++/VB6. Vor dem Start einer Transaktion frage ich 1malig die current_connection ab und merke mir diese. Dann kann ich mit dieser gelesenen ID die benötigten Aktionen über eine 2. Verbindung ausführen.

Ich verwende dieses Verfahren i.Ü. auch für parallele Abfragen.
Wenn ich mehrere unabhängige Daten benötige, kann ich dies gleichzeitig über mehrere Connections in diversen Threads abfragen und zentral auf das Ende aller Abfragen warten.
Da sind ungeahnte Performanceschübe möglich.
Bei der FB2.5 ist da allerdings der Klassikserver (also nicht embedded, Prozess je Connection) erforderlich, ab FB3 macht das der Server dann selber, je Verbindung einen Thread aufzumachen.

Warum nimmst du überhaupt einen embedded Server? Meine Erfahrungen mit FBServer-Installation und Zugriff via TCP-localhost sind absolut positiv. Zumal ich dann parallel zur Anwendung mal mit iSQL oder IBExpert in der Datanbank nachsehen kann ohne die App zu beendn. Zusätzlich kann dann auch mit BI-Tools wie Power-BI (oder meine Lösung) Zusatznutrzen generieren.
Helios
Beiträge: 9
Registriert: So 28. Feb 2021, 11:02

Hallo bfuerchau
hallo Martin,

mit der 2. Connection (zum Abbrechen via. DELETE) und dem Zwischenspeichern der 1. Connection zum Absetzen des "Langlauf SQL-Statements" funktioniert es wunderbar (zumindest bisher habe ich keine Nebenwirkungen entdeckt) :) . Danke für den Tipp, dass auch Embedded mehrere Connections aus einer Applikation heraus möglich sind. Da war ich bisher von ausgegangen, dass das gar nicht geht. Wieder was gelernt und das Abbrechen funktioniert jetzt prima ohne Nebenwirkungen auf andere nebenläufige SQL-Statements die auch im State = 2 sind.

Noch schnell die Antwort auf Deine Frage bfuerchau: Die Embeded Lösung ist für mich ein "Notnagel" falls es auf den Clients nicht möglich sein sollte einen Dienst zusätzlich zu installieren (das wird die IT in meiner Firma hochwahrscheinlich nicht akzeptieren :( und auch die Client Installation von Firebird ist dann wesentlich einfacher).

Nochmal Danke und sorry für meine späte Antwort, ich brauchte etwas Zeit die Vorschläge von euch richtig umzusetzen und zu testen.

Schönes Wochenende und Gruß
Helios
vr2
Beiträge: 106
Registriert: Fr 13. Apr 2018, 00:13

Hallo Helios,

eine zweite Connection zum Abbrechen eines Statements ist der offizielle Weg, da wirst Du keine Nebenwirkungen sehen.

bzgl "Dienst-Installation wird die IT meiner Firma nicht akzeptieren" Also wenn Deine Firma eine Datenbankanwendung einsetzt, aber die IT nicht einsieht, dass der zugehörige Datenbankserver als Systemkomponente behandelt und daher permanent ansprechbar sein sollte, dann stimmt was nicht. Das ist überall der Normalfall bei Datenbankservern. Starten die ihre Webserver auch vom USB-Stick? Und außerdem: Im Gegensatz zu so asozialen Datenbankservern wie MS-SQL-Server, die sich erstmal großzügig x GB RAM reservieren, egal, ob was bei ihnen passiert oder nicht, frisst ein Firebird-Server überhaupt kein Brot, egal ob Dienst oder nicht. Wenn das die Befürchtung Deiner IT-Admins ist, sollten sie sich schlau machen, wie der Footprint eines Firebird-Servers aussieht. Schlanker geht nicht. Es kann natürlich sein, dass die Admins sich mit Firebird nicht auskennen und daher auch die Administration nicht übernehmen wollen, oder keinen Zoo haben wollen, berechtigter Einwand. Dem lässt sich entgegnen, dass Firebird-Server nahezu wartungsfrei sind. Da muss man miteinander abstimmen, wer was übernimmt, und erstmal schaut, wieviel Aufwand überhaupt entsteht.

Aus Adminperspektive ist es außerdem besser, wenn man weiß, welche Server auf einem System laufen. Und aus Entwicklerperspektive ist der Embedded-Modus ein Sonderfall mit Einschränkungen.

Grüße, Volker
Helios
Beiträge: 9
Registriert: So 28. Feb 2021, 11:02

Hallo Volker,
alles gut :D Ist eine große IT und da kann nicht jeder machen was er will ohne das entsprechend Abzustimmen und Installationsjobs bauen zu lassen usw. Das dauert seine Zeit.
Ich bastle hier ja nur an einer "kleinen" Offline Lösung für spezielle Kollegen mit speziellen Bedarf.
Die große Oracle Lösung die es dazu auch noch gibt, kann mein kleines Projekt nicht ersetzen und soll es auch nicht.
Für mich ist das der erste Eintieg mit Firebird (nachdem ich mal flüchtig mit InterBase mit einer Delphi 2.0 Server Edition Kontakt hatte (anno 1995;-)).
Ich werde immer mehr ein Fan von der Firebird Datenbank weil sie eben so schön schlank ist, Transaktionen und Trigger/Prozedurales SQL bietet, auch mit größeren Datenmengen klar kommt (bin jetzt bei ca. 6GB), Open Source ist und sich auch wunderbar mit Lazarus/Free Pascal verwenden läst. Vielleicht überwiegen nach dem Prototypenstadium die Gründe einen Server auf jedem Client aufzusetzen aber schauen wir mal. Nix muss aber alles kann, je nachdem was sich dann im Gesamtkontext anbietet.
Nochmal danke für Deine /Eure Unterstützung und Gruß
Arne
bfuerchau
Beiträge: 278
Registriert: Mo 7. Mai 2018, 18:09

Zur Not startet man den Firebird-Prozess eben als Anwendung. Dies geht auch per Aufgabenplanung als unbaufsichtigte Komponente.
Antworten