sql >> Database >  >> RDS >> Access

Hoe praat Access met ODBC-gegevensbronnen? Deel 2

UPDATE: Wat meer verduidelijkingen toegevoegd rond de betekenis van SQLExecute en hoe Access de voorbereide query's afhandelt. Bedankt, Bob!

Wat doet Access wanneer we bladeren en records bekijken in een ODBC-gekoppelde tabel?

In het tweede deel van onze ODBC-traceerreeks zullen we ons concentreren op de impact die de recordsettypes hebben binnen een ODBC-gekoppelde tabel. In het laatste artikel hebben we geleerd hoe we ODBC SQL-tracering kunnen inschakelen en we kunnen nu de uitvoer zien. Als je er een beetje mee gespeeld hebt, is het je misschien opgevallen dat je Access-query en de ODBC SQL-statements die Access genereert niet erg op elkaar lijken. We zullen ook diepgaand bekijken hoe de typen het gedrag van SELECT-query's beïnvloeden, en we zullen ook verschillende variaties van recordsets onderzoeken, zoals Snapshots en Dynasets.

Als je het wilt volgen, kun je de voorbeelddatabase gebruiken die hier wordt aangeboden.

Effect van Recordset-types in een SELECT-query

De typen recordsets hebben een groot effect op hoe Access zal communiceren met de ODBC-gegevensbronnen. Het is u wellicht opgevallen dat u in een ontwerpweergave voor formulieren of in een ontwerpweergave voor query's het type recordset kunt instellen. Standaard is deze ingesteld op Dynaset .

In VBA hebben we weinig meer opties, maar daar maken we ons voorlopig geen zorgen over. Laten we beginnen met te begrijpen wat precies Dynaset en Snapshot betekent eerst. We beginnen met het minder vaak gebruikte type, Snapshot eerst.

Recordsets van het type momentopname

Snapshot is vrij eenvoudig. Het betekent in feite dat we een momentopname maken van het resultaat op het moment dat de query wordt uitgevoerd. Normaal gesproken betekent dit ook dat Access het resultaat niet kan bijwerken. Laten we echter eens kijken hoe Access de bron opvraagt ​​met een op momentopnamen gebaseerde recordset. We kunnen een nieuwe Access-query als volgt maken:

De SQL zoals we kunnen zien in de SQL-weergave van Access-query is:

SELECT Cities.*
FROM Cities;
We voeren de query uit en kijken dan naar de sqlout.txt het dossier. Dit is de uitvoer, geformatteerd voor leesbaarheid:

SQLExecDirect:
SELECT
   "CityID"
  ,"CityName"
  ,"StateProvinceID"
  ,"Location"
  ,"LatestRecordedPopulation"
  ,"LastEditedBy"
  ,"ValidFrom"
  ,"ValidTo"
FROM "Application"."Cities"
Er waren weinig verschillen tussen wat we schreven in de Access-query in vergelijking met wat Access naar ODBC stuurde, wat we zullen analyseren.

  1. Access kwalificeerde de tabel met de schemanaam. Vanzelfsprekend werkt dat in Access SQL-dialect niet op dezelfde manier, maar voor ODBC SQL-dialect is het handig om ervoor te zorgen dat we uit de juiste tabel selecteren. Dat wordt bepaald door de SourceTableName eigendom.
  2. Toegang heeft de inhoud van Cities.* . uitgebreid in een opgesomde lijst van alle kolommen die Access al kent op basis van de Fields verzameling van de onderliggende TableDef voorwerp.
  3. Toegang gebruikte de " om de identifiers te citeren, wat het ODBC SQL-dialect verwacht. Hoewel zowel Access SQL als Transact-SQL haakjes gebruiken om een ​​id aan te halen, is dat geen juridische syntaxis in het ODBC SQL-dialect.

Dus ook al hebben we alleen een eenvoudige snapshot-query uitgevoerd door alle kolommen voor een tabel te selecteren, u kunt zien dat Access veel transformatie naar de SQL uitvoert tussen wat u in de Access-queryontwerpweergave of SQL-weergave plaatst versus wat Access daadwerkelijk naar de gegevens verzendt bron. In dit geval is het echter meestal syntactisch, dus er is geen echt verschil in de SQL-instructie tussen de oorspronkelijke Access-query en de ODBC SQL-instructie.

De tracering heeft ook SQLExecDirect . toegevoegd aan het begin van de SQL-instructie. We komen daarop terug als we een paar andere voorbeelden hebben bekeken.

Dynaset-type recordsets

We gebruiken dezelfde zoekopdracht, maar veranderen de eigenschap terug naar de standaard, Dynaset .
Voer het opnieuw uit en we zullen zien wat we krijgen van de sqlout.txt . Nogmaals, het is geformatteerd voor leesbaarheid:

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)
Wauw, er gebeurt veel! Dit is zeker meer spraakzaam dan de snapshot-type recordset. Laten we ze een voor een doornemen.

De eerste selecteert alleen de CityID kolom. Dat is toevallig de primaire sleutel van de tabel, maar wat nog belangrijker is, dat is de index die Access aan zijn kant gebruikt. Dat wordt belangrijk als we later standpunten bestuderen. Access gebruikt deze query om de sleutels op te halen en gebruikt die om later andere query's in te vullen, zoals we zullen zien.

De tweede instructie komt dichter bij de oorspronkelijke snapshot-query, behalve dat we nu een nieuwe WHERE hebben clausule filteren op de CityID kolom. Daaruit kunnen we zien dat het een ophaalactie met één rij is. We kunnen de sleutels gebruiken die we van de eerste query hebben gekregen en de rest van de kolommen in deze query verzamelen. Telkens wanneer die voorbereide instructie wordt uitgevoerd, ziet u een SQLExecute: (GOTO BOOKMARK) .

Maar dat zou inefficiënt zijn als we dit voor alle rijen zouden moeten doen... En daar komt de volgende vraag om de hoek kijken. De 3e instructie is vergelijkbaar met de 2e maar heeft 10 predikaten. Deze voorbereide query wordt uitgevoerd met elke SQLExecute: (MULTI_ROW FETCH) . Dit betekent dus dat wanneer we een formulier of een gegevensblad laden of zelfs een recordset openen in VBA-code, Access de versie met één rij of met meerdere rijen gebruikt en de parameters invult met de sleutels die het van de eerste kreeg vraag.

Achtergrond ophalen en opnieuw synchroniseren

Is het je trouwens ooit opgevallen dat wanneer je een formulier of een datasheet opent, je de "X van Y" niet te zien krijgt in de navigatiebalk?

Dat komt omdat Access niet kan weten hoeveel er zijn totdat het klaar is met het verzamelen van de resultaten van de eerste query. Daarom zult u vaak merken dat het erg snel is om een ​​zoekopdracht te openen die een grote hoeveelheid gegevens retourneert. U bekijkt slechts een klein venster van de volledige recordset terwijl Access de rijen op de achtergrond ophaalt. Als u op de knop "Ga naar laatste" klikt, kan het zijn dat Access vastloopt. Je zou moeten wachten tot het klaar is met het ophalen van alle sleutels in de eerste query voordat we de "X van Y" in de navigatiebalk kunnen zien.

Dus u kunt begrijpen hoe Access de illusie kan wekken dat zelfs een grote recordset snel kan worden geopend wanneer we een recordset van het type dynaset en dat is meestal een goede ervaring voor de gebruiker.

Ten slotte moeten we opmerken dat we 3 verschillende soorten uitvoeringen hebben, SQLExecDirect , SQLPrepare en SQLExecute . Je kunt zien dat we bij de eerste geen parameters hebben. De vraag is gewoon zoals het is. Als een query echter moet worden geparametriseerd, moet deze eerst worden voorbereid via SQLPrepare en later uitgevoerd met SQLExecute met waarden voor opgegeven parameters. We kunnen niet zien welke waarden daadwerkelijk zijn doorgegeven aan de SQLExecute verklaring hoewel we kunnen afleiden uit wat we zien in Access. U kunt alleen weten of het een enkele rij heeft opgehaald (met behulp van SQLExecute: (GOTO BOOKMARK) of meerdere rijen (met behulp van SQLExecute: (MULTI-ROW FETCH) ). Access gebruikt de versie met meerdere rijen om de achtergrond op te halen en de recordset stapsgewijs te vullen, maar gebruikt de versie met één rij om slechts één rij te vullen. Dat kan het geval zijn in een enkele formulierweergave in plaats van een doorlopende formulier- of gegevensbladweergave of gebruiken voor hersynchronisatie na een update.

Navigeren

Met een recordset die groot genoeg is, kan Access mogelijk nooit alle records ophalen. Zoals eerder opgemerkt, krijgt de gebruiker de gegevens zo snel mogelijk te zien. Normaal gesproken zal Access, wanneer de gebruiker vooruit door de recordset navigeert, steeds meer records ophalen om de buffer voor de gebruiker te houden.

Maar stel dat de gebruiker naar de 100e rij springt door naar de navigatiebediening te gaan en daar 100 in te voeren?

In dat geval zal Access de volgende vragen indienen...

SQLExecute: (MULTI-ROW FETCH)

SQLExecute: (GOTO BOOKMARK)

SQLExecute: (MULTI-ROW FETCH)

SQLExecute: (MULTI-ROW FETCH)
Merk op hoe Access de reeds voorbereide instructies gebruikt die het heeft gemaakt bij het openen van de recordset. Omdat het de sleutels van de eerste query al heeft, kan het weten welke de "100e" rij is. Om een ​​meer concreet voorbeeld te gebruiken. Stel dat we CityID . hadden beginnend bij 1, 3, 4, 5…99, 100, 101, 102 zonder record voor de CityID = 2 . In de eerste zoekopdracht, de CityID 101 zou op de 100e rij staan. Daarom, wanneer de gebruiker naar 100 springt, zoekt Access de 100e rij op in de eerste zoekopdracht, kijk of het CityID is 101, neemt dan die waarde en voert die in de SQLExecute: (GOTO BOOKMARK) om onmiddellijk naar dat record te navigeren. Het kijkt dan naar de volgende 10 records en gebruikt die daaropvolgende CityID om de buffer te vullen met meerdere SQLExecute: (MULTI-ROW FETCH) . Het is u misschien opgevallen dat er een ophaalactie met meerdere rijen is voordat een enkele rij wordt opgehaald. Access haalt in feite de 101e-110e rijen in de meerdere rijen op en haalt het 100e record op in de volgende enkele rij.

Zodra Access de gegevens voor de rijen op de 100e heeft ontvangen, moet de gebruiker daarheen gaan en begint de buffer rond die 100e rij te vullen. Hierdoor kan de gebruiker de 100e rij bekijken zonder te hoeven wachten om alle 11e-99e records te laden. De gebruiker heeft blijkbaar ook een snelle browse-ervaring wanneer de gebruiker op vorige of volgende klikt vanaf de nieuwe positie, omdat Access het al op de achtergrond heeft geladen voordat de gebruiker erom vroeg. Dat helpt om de illusie te wekken snel te zijn, zelfs via een traag netwerk.

Maar zelfs als de gebruiker het formulier open en inactief laat, blijft Access zowel op de achtergrond ophalen als de buffer vernieuwen om te voorkomen dat de gebruiker verouderde gegevens toont. Dat wordt bepaald door de ODBC-instellingen in het dialoogvenster Opties, onder het gedeelte Geavanceerd op het tabblad Clientinstellingen:

De standaard voor ODBC-verversingsinterval is 1500 seconden, maar kan worden gewijzigd. Het kan ook worden gewijzigd via VBA.

Conclusies:grof of spraakzaam

U zou nu moeten inzien dat de belangrijkste reden waarom recordsets van het dynaset-type kunnen worden bijgewerkt, maar niet-snapshot-recordsets, is dat Access een rij in de recordset kan vervangen door de nieuwste versie van dezelfde van de server, omdat het weet hoe een enkele rij. Om die reden moet Access 2 ODBC-query's beheren; een om de sleutels op te halen en een andere om de werkelijke inhoud van rijen voor een bepaalde sleutel op te halen. Die informatie was niet aanwezig bij een recordset van het type snapshot. We hebben zojuist een grote hoeveelheid gegevens ontvangen.

We hebben gekeken naar 2 belangrijke soorten recordsets, hoewel er meer zijn. Andere zijn echter slechts varianten van de 2 typen die we hebben behandeld. Maar voor nu is het voldoende om te onthouden dat het gebruik van snapshot te grof is in onze netwerkcommunicatie. Aan de andere kant betekent het gebruik van dynaset dat we spraakzaam zullen zijn. Beide hebben hun ups en downs.

Een snapshot-recordset heeft bijvoorbeeld geen verdere communicatie met de server nodig nadat deze de gegevens heeft opgehaald. Zolang de recordset open blijft, kan Access vrij door de lokale cache navigeren. Toegang hoeft ook geen sloten te behouden en dus andere gebruikers te blokkeren. Een snapshot-recordset is echter noodzakelijkerwijs langzamer te openen, omdat alle gegevens vooraf moeten worden verzameld. Het kan slecht passen bij een grote recordset, zelfs als je van plan bent om alle gegevens te lezen.

Stel dat u een groot Access-rapport van 100 pagina's maakt, dan is het meestal de moeite waard om een ​​recordset van het type dynaset te gebruiken. Het kan beginnen met het weergeven van het voorbeeld zodra het genoeg heeft om de eerste pagina weer te geven. Dat is beter dan u te dwingen te wachten tot het alle gegevens heeft opgehaald voordat het kan beginnen met het weergeven van het voorbeeld. Hoewel een dynaset-recordset sloten kan bevatten, is dit meestal voor korte tijd. Het is alleen lang genoeg voor Access om zijn lokale cache opnieuw te synchroniseren.

Maar als we bedenken hoeveel verzoeken Access via het netwerk indient met een recordset van het type dynaset, is het gemakkelijk te zien dat als de netwerklatentie slecht is, de prestaties van Access dienovereenkomstig zullen afnemen. Om gebruikers in staat te stellen gegevensbronnen op een generieke manier te bewerken en bij te werken, moet Access sleutels bijhouden voor het selecteren en wijzigen van een enkele rij. We zullen hier in de komende artikelen naar kijken. In het volgende artikel zullen we bekijken hoe sorteren en groeperen een dynaset-type recordset beïnvloedt en hoe Access de sleutel bepaalt die moet worden gebruikt voor een dynaset-type recordset.

Voor meer hulp bij Microsoft Access kunt u onze experts bellen op 773-809-5456 of een e-mail sturen naar [email protected].


  1. Ik moet kolomnamen doorgeven met behulp van variabele in select-instructie in Store Procedure, maar ik kan geen dynamische query gebruiken

  2. Kan 'alleen-lezen' database niet verkleinen | Transactielogboek verkleinen bij gebruik van AlwaysOn-beschikbaarheidsgroep

  3. WAMP/MySQL-fouten niet in de juiste taal

  4. Hoe alleen tijd op te slaan; geen datum en tijd?