Access
 sql >> Datenbank >  >> RDS >> Access

Wie kommuniziert Access mit ODBC-Datenquellen? Teil 2

AKTUALISIERUNG: Weitere Erläuterungen zur Bedeutung von SQLExecute hinzugefügt und wie Access die vorbereiteten Abfragen verarbeitet. Danke Bob!

Was macht Access, wenn wir Datensätze in einer ODBC-verknüpften Tabelle durchsuchen und betrachten?

Im zweiten Teil unserer Serie zur ODBC-Ablaufverfolgung konzentrieren wir uns auf die Auswirkungen der Recordset-Typen innerhalb einer ODBC-verknüpften Tabelle. Im letzten Artikel haben wir gelernt, wie man den ODBC-SQL-Trace einschaltet, und wir können jetzt die Ausgabe sehen. Wenn Sie ein wenig damit gespielt haben, ist Ihnen vielleicht aufgefallen, dass Ihre Access-Abfrage und die von Access generierten ODBC-SQL-Anweisungen nicht sehr ähnlich aussehen. Wir werden auch einen eingehenden Blick darauf werfen, wie die Typen das Verhalten von SELECT-Abfragen beeinflussen, und wir werden uns auch mit verschiedenen Variationen von Recordsets wie Snapshots und Dynasets befassen.

Wenn Sie mitmachen möchten, können Sie die hier bereitgestellte Beispieldatenbank verwenden.

Wirkung von Recordset-Typen in einer SELECT-Abfrage

Die Recordset-Typen haben einen großen Einfluss darauf, wie Access mit den ODBC-Datenquellen kommuniziert. Sie haben vielleicht bemerkt, dass Sie in einer Formularentwurfsansicht oder in einer Abfrageentwurfsansicht den Datensatztyp festlegen können. Standardmäßig ist es auf Dynaset eingestellt .

In VBA haben wir einige weitere Optionen, aber darüber machen wir uns jetzt keine Gedanken. Beginnen wir damit, zu verstehen, was genau Dynaset ist und Snapshot bedeutet zuerst. Wir beginnen mit dem weniger häufig verwendeten Typ Snapshot zuerst.

Snapshot-Datensätze

Snapshot ist ganz einfach. Im Grunde bedeutet dies, dass wir zum Zeitpunkt der Ausführung der Abfrage eine Momentaufnahme des Ergebnisses erstellen. Normalerweise bedeutet dies auch, dass Access das Ergebnis nicht aktualisieren kann. Sehen wir uns jedoch an, wie Access die Quelle mit einem Snapshot-basierten Recordset abfragt. Wir können eine neue Access-Abfrage wie folgt erstellen:

Die SQL, wie wir sie in der SQL-Ansicht der Access-Abfrage sehen können, ist:

SELECT Cities.*
FROM Cities;
Wir führen die Abfrage aus und sehen uns dann die sqlout.txt an Datei. Hier ist die Ausgabe, zur besseren Lesbarkeit formatiert:

SQLExecDirect:
SELECT
   "CityID"
  ,"CityName"
  ,"StateProvinceID"
  ,"Location"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
FROM "Application"."Cities"
Es gab nur wenige Unterschiede zwischen dem, was wir in die Abfrage von Access geschrieben haben, und dem, was Access an ODBC gesendet hat, was wir analysieren werden.

  1. Access qualifizierte die Tabelle mit dem Schemanamen. Offensichtlich funktioniert das im Access SQL-Dialekt nicht auf die gleiche Weise, aber für den ODBC-SQL-Dialekt ist es hilfreich sicherzustellen, dass wir aus der richtigen Tabelle auswählen. Das wird durch den SourceTableName geregelt Eigentum.
  2. Access erweiterte den Inhalt von Cities.* in eine aufgezählte Liste aller Spalten, die Access bereits anhand der Fields kennt Sammlung der zugrunde liegenden TableDef Objekt.
  3. Zugriff verwendet den " um die Bezeichner in Anführungszeichen zu setzen, was der ODBC-SQL-Dialekt erwartet. Obwohl sowohl Access SQL als auch Transact-SQL Klammern verwenden, um einen Bezeichner in Anführungszeichen zu setzen, ist dies keine zulässige Syntax im ODBC-SQL-Dialekt.

Obwohl wir also nur eine einfache Snapshot-Abfrage durchgeführt haben, bei der alle Spalten für eine Tabelle ausgewählt wurden, können Sie sehen, dass Access viele Transformationen an der SQL durchführt, zwischen dem, was Sie in die Access-Abfrageentwurfsansicht oder SQL-Ansicht eingeben, und dem, was Access tatsächlich an die Daten ausgibt Quelle. In diesem Fall ist es jedoch hauptsächlich syntaktisch, sodass es keinen wirklichen Unterschied in der SQL-Anweisung zwischen der ursprünglichen Access-Abfrage und der ODBC-SQL-Anweisung gibt.

Die Ablaufverfolgung fügte außerdem SQLExecDirect hinzu am Anfang der SQL-Anweisung. Wir werden darauf zurückkommen, sobald wir uns einige andere Beispiele angesehen haben.

Recordsets vom Typ Dynaset

Wir verwenden dieselbe Abfrage, ändern aber die Eigenschaft wieder auf den Standardwert Dynaset .
Führen Sie es erneut aus und wir werden sehen, was wir aus der sqlout.txt erhalten . Auch hier ist es für die Lesbarkeit formatiert:

SQLExecDirect:
SELECT
  "Application"."Cities"."CityID"
FROM "Application"."Cities"

SQLPrepare:
SELECT
   "CityID"
  ,"CityName"
  ,"StateProvinceID"
  ,"Location"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
FROM "Application"."Cities"
WHERE "CityID" = ?

SQLExecute: (GOTO BOOKMARK)

SQLPrepare:
SELECT
   "CityID"
  ,"CityName"
  ,"StateProvinceID"
  ,"Location"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
FROM "Application"."Cities"
WHERE "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?
   OR "CityID" = ?

SQLExecute: (MULTI-ROW FETCH)

SQLExecute: (MULTI-ROW FETCH)
Wow, es passiert viel! Dies ist definitiv gesprächiger als das Recordset vom Snapshot-Typ. Gehen wir sie einzeln durch.

Der erste wählt nur die CityID aus Säule. Das ist zufällig der Primärschlüssel der Tabelle, aber was noch wichtiger ist, das ist der Index, den Access auf seiner Seite verwendet. Das wird wichtig, wenn wir später Ansichten studieren. Access verwendet diese Abfrage, um die Schlüssel abzurufen, und verwendet sie, um später andere Abfragen auszufüllen, wie wir sehen werden.

Die zweite Anweisung ist näher an der ursprünglichen Snapshot-Abfrage, außer dass wir jetzt ein neues WHERE haben -Klausel, die nach CityID filtert Säule. Daraus können wir erkennen, dass es sich um einen einzeiligen Abruf handelt. Wir können die Schlüssel verwenden, die wir aus der ersten Abfrage erhalten haben, und die restlichen Spalten in dieser Abfrage sammeln. Immer wenn diese vorbereitete Anweisung ausgeführt wird, sehen Sie ein SQLExecute: (GOTO BOOKMARK) .

Aber das wäre ineffizient, wenn wir das für alle Zeilen machen müssten … Und da kommt die nächste Abfrage ins Spiel. Die 3. Anweisung ist ähnlich wie die 2., hat aber 10 Prädikate. Diese vorbereitete Abfrage wird mit jedem SQLExecute: (MULTI_ROW FETCH) ausgeführt . Das bedeutet also, dass Access beim Laden eines Formulars oder eines Datenblatts oder sogar beim Öffnen eines Datensatzes im VBA-Code entweder die einzeilige Version oder die mehrzeilige Version verwendet und die Parameter mit den Schlüsseln ausfüllt, die es von Anfang an erhalten hat Abfrage.

Abrufen und Neusynchronisieren im Hintergrund

Ist Ihnen übrigens schon einmal aufgefallen, dass Sie beim Öffnen eines Formulars oder Datenblatts das „X von Y“ in der Navigationsleiste nicht sehen?

Das liegt daran, dass Access nicht wissen kann, wie viele es sind, bis die Erfassung der Ergebnisse der ersten Abfrage abgeschlossen ist. Aus diesem Grund stellen Sie möglicherweise fest, dass es sehr schnell geht, eine Abfrage zu öffnen, die große Datenmengen zurückgibt. Sie zeigen nur ein kleines Fenster des gesamten Datensatzes in der Vorschau an, während Access die Zeilen im Hintergrund abruft. Wenn Sie auf die Schaltfläche „Go To Last“ klicken, stellen Sie möglicherweise fest, dass Access eingefroren wird. Sie müssten warten, bis alle Schlüssel in der ersten Abfrage abgerufen wurden, bevor wir das „X von Y“ in der Navigationsleiste sehen können.

Daher können Sie erkennen, wie Access bei uns den Eindruck erwecken kann, selbst große Datensätze schnell öffnen zu können ein Recordset vom Typ Dynaset, und das ist normalerweise eine gute Erfahrung für den Benutzer.

Schließlich müssen wir anmerken, dass wir 3 verschiedene Arten von Ausführungen haben, SQLExecDirect , SQLPrepare und SQLExecute . Sie können sehen, dass wir bei ersterem keine Parameter haben. Die Abfrage ist einfach so wie sie ist. Soll eine Abfrage jedoch parametrisiert werden, muss diese zunächst über SQLPrepare vorbereitet werden und dann später mit SQLExecute ausgeführt werden mit Werten für bereitgestellte Parameter. Wir können nicht sehen, welche Werte tatsächlich an SQLExecute übergeben wurden Anweisung, obwohl wir aus dem, was wir in Access sehen, schließen können. Sie können nur wissen, ob eine einzelne Zeile abgerufen wurde (mithilfe von SQLExecute: (GOTO BOOKMARK)). oder mehrere Zeilen (mit SQLExecute: (MULTI-ROW FETCH)). ). Access verwendet die mehrzeilige Version, um Hintergrundabrufe durchzuführen und das Recordset inkrementell zu füllen, aber verwendet die einzeilige Version, um nur eine Zeile zu füllen. Dies kann bei einer einzelnen Formularansicht der Fall sein, im Gegensatz zu einer Endlosformular- oder Datenblattansicht, oder Sie verwenden es zum erneuten Synchronisieren nach einer Aktualisierung.

Navigieren

Bei einem ausreichend großen Datensatz kann Access möglicherweise nicht alle Datensätze vollständig abrufen. Wie bereits erwähnt, werden dem Benutzer die Daten so schnell wie möglich präsentiert. Wenn der Benutzer vorwärts durch das Recordset navigiert, ruft Access normalerweise immer mehr Datensätze ab, um den Puffer vor dem Benutzer zu halten.

Aber angenommen, der Benutzer springt in die 100. Zeile, indem er zur Navigationssteuerung geht und dort 100 eingibt?

In diesem Fall sendet Access die folgenden Abfragen …

SQLExecute: (MULTI-ROW FETCH)

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (MULTI-ROW FETCH)

SQLExecute: (MULTI-ROW FETCH)
Beachten Sie, wie Access die bereits vorbereiteten Anweisungen verwendet, die zum Zeitpunkt des Öffnens des Recordsets erstellt wurden. Da es bereits die Schlüssel aus der ersten Abfrage hat, kann es wissen, welches die „100.“ Zeile ist. Um ein konkreteres Beispiel zu verwenden. Angenommen, wir hätten CityID beginnend bei 1, 3, 4, 5…99, 100, 101, 102 ohne Eintrag für CityID = 2 . In der ersten Abfrage die CityID 101 wäre in der 100. Reihe. Wenn der Benutzer zu 100 springt, sucht Access daher in der ersten Abfrage in der 100. Zeile und stellt fest, dass es sich um CityID handelt 101, nimmt dann diesen Wert und speist ihn in SQLExecute: (GOTO BOOKMARK) ein um sofort zu diesem Datensatz zu navigieren. Es betrachtet dann die nächsten 10 Datensätze und verwendet diese nachfolgenden CityID um den Puffer mit mehreren SQLExecute: (MULTI-ROW FETCH) zu füllen . Möglicherweise ist Ihnen aufgefallen, dass vor dem Abruf einer einzelnen Zeile ein Abruf mehrerer Zeilen erfolgt. Access ruft tatsächlich die 101. bis 110. Zeile beim Abruf mehrerer Zeilen ab und ruft den 100. Datensatz beim nächsten Einzelzeilenabruf ab.

Sobald Access die Daten für die Zeilen bei 100 erhalten hat, bringt es den Benutzer dorthin und beginnt dann, den Puffer um diese 100. Zeile zu füllen. Dadurch kann der Benutzer die 100. Zeile anzeigen, ohne warten zu müssen, bis alle 11. bis 99. Datensätze geladen sind. Der Benutzer hat auch eine scheinbar schnelle Browsing-Erfahrung, wenn der Benutzer von der neuen Position aus auf Zurück oder Weiter klickt, da Access es bereits im Hintergrund geladen hat, bevor der Benutzer danach gefragt hat. Das trägt dazu bei, die Illusion zu vermitteln, selbst über ein langsames Netzwerk hinweg schnell zu sein.

Aber selbst wenn der Benutzer das Formular geöffnet und im Leerlauf gelassen hat, würde Access weiterhin sowohl den Hintergrundabruf durchführen als auch den Puffer aktualisieren, um zu vermeiden, dass dem Benutzer veraltete Daten angezeigt werden. Dies wird durch die ODBC-Einstellungen im Dialogfeld "Optionen" im Abschnitt "Erweitert" auf der Registerkarte "Client-Einstellungen" geregelt:

Der Standardwert für das ODBC-Aktualisierungsintervall beträgt 1500 Sekunden, kann aber geändert werden. Es kann auch über VBA geändert werden.

Schlussfolgerungen:Chunky oder Chatty

Sie sollten jetzt sehen, dass der Hauptgrund, warum Recordsets vom Typ Dynaset aktualisierbar sind, Recordsets vom Snapshot-Typ jedoch nicht, darin besteht, dass Access eine Zeile im Recordset durch die neueste Version derselben vom Server ersetzen kann, da es weiß, wie man a auswählt einreihig. Aus diesem Grund muss Access zwei ODBC-Abfragen verwalten; einer zum Abrufen der Schlüssel und der andere zum Abrufen des tatsächlichen Inhalts der Zeilen für einen bestimmten Schlüssel. Diese Informationen waren bei einem Recordset vom Snapshot-Typ nicht vorhanden. Wir haben gerade einen großen Datenklumpen erhalten.

Wir haben uns 2 Haupttypen von Recordsets angesehen, obwohl es noch mehr gibt. Andere sind jedoch nur Varianten der beiden Typen, die wir behandelt haben. Aber vorerst reicht es aus, sich daran zu erinnern, dass die Verwendung von Snapshots in unserer Netzwerkkommunikation unübersichtlich ist. Auf der anderen Seite bedeutet die Verwendung von Dynaset, dass wir gesprächig sein werden. Beide haben ihre Höhen und Tiefen.

Zum Beispiel benötigt Snapshot Recordset keine weitere Kommunikation mit dem Server, nachdem er die Daten abgerufen hat. Solange das Recordset geöffnet bleibt, kann Access frei im lokalen Cache navigieren. Der Zugang muss auch keine Sperren halten und damit andere Benutzer blockieren. Ein Snapshot-Datensatz lässt sich jedoch zwangsläufig langsamer öffnen, da alle Daten im Voraus erfasst werden müssen. Es kann für einen großen Recordset schlecht geeignet sein, selbst wenn Sie beabsichtigen, alle Daten zu lesen.

Angenommen, Sie erstellen einen großen Access-Bericht mit 100 Seiten, dann lohnt es sich normalerweise, ein Recordset vom Typ Dynaset zu verwenden. Es kann mit dem Rendern der Vorschau beginnen, sobald es genug hat, um die erste Seite zu rendern. Das ist besser, als Sie zu zwingen zu warten, bis es alle Daten abgerufen hat, bevor es mit dem Rendern der Vorschau beginnen kann. Obwohl ein Dynaset-Recordset Sperren annehmen kann, ist dies normalerweise nur für kurze Zeit der Fall. Es ist nur lang genug für Access, um seinen lokalen Cache neu zu synchronisieren.

Aber wenn wir darüber nachdenken, wie viele weitere Anfragen Access über das Netzwerk mit einem Recordset vom Typ Dynaset sendet, ist leicht zu erkennen, dass die Leistung von Access entsprechend leidet, wenn die Netzwerklatenz schlecht ist. Damit Access es Benutzern ermöglicht, Datenquellen auf generische Weise zu bearbeiten und zu aktualisieren, muss Access Schlüssel zum Auswählen und Ändern einer einzelnen Zeile verfolgen. Wir werden uns dies in den kommenden Artikeln ansehen. Im nächsten Artikel sehen wir uns an, wie sich das Sortieren und Gruppieren auf ein Recordset vom Typ Dynaset auswirkt und wie Access den Schlüssel bestimmt, der für ein Recordset vom Typ Dynaset verwendet werden soll.

Wenn Sie weitere Hilfe zu Microsoft Access benötigen, rufen Sie unsere Experten unter 773-809-5456 an oder senden Sie uns eine E-Mail an [email protected].