OPDATERING: Tilføjet nogle flere præciseringer omkring betydningen af SQLExecute
og hvordan Access håndterer de forberedte forespørgsler. Tak, Bob!
Hvad laver Access, når vi gennemser og ser på poster i en ODBC-linket tabel?
I den anden del af vores ODBC-sporingsserie vil vores fokus vende sig mod den indvirkning, rekordsættyperne har i en ODBC-linket tabel. I den sidste artikel lærte vi, hvordan man slår ODBC SQL-sporing til, og vi kan nu se outputtet. Hvis du har leget lidt med det, har du måske bemærket, at din Access-forespørgsel og de ODBC SQL-sætninger, som Access genererer, ikke ligner meget. Vi vil også give et dybtgående kig på, hvordan typerne påvirker adfærden af SELECT-forespørgsler, og vi vil også se på forskellige variationer af rekordsæt såsom Snapshots og Dynasets.
Hvis du vil følge med, kan du bruge prøvedatabasen, som findes her.
Effekt af Recordset-typer i en SELECT-forespørgsel
Recordset-typerne har stor effekt på, hvordan Access kommunikerer med ODBC-datakilderne. Du har måske bemærket, at du i en formulardesignvisning eller i forespørgselsdesignvisning kan indstille postsættypen. Som standard er den indstillet til Dynaset
.
I VBA har vi få flere muligheder, men vi vil ikke bekymre os om det for nu. Lad os starte med at forstå, hvad der præcist er Dynaset
og Snapshot
betyder først. Vi starter med en mindre almindeligt brugt type, Snapshot
først.
Snapshot type rekordsæt
Snapshot
er ret simpelt. Det betyder grundlæggende, at vi tager et øjebliksbillede af resultatet på tidspunktet for forespørgslens udførelse. Normalt betyder det også, at Access ikke kan opdatere resultatet. Lad os dog se på, hvordan Access forespørger kilden med et snapshot-baseret recordset. Vi kan oprette en ny Access-forespørgsel som sådan:
SQL'en, som vi kan se i Access-forespørgslens SQL-visning er:
SELECT Cities.* FROM Cities;Vi kører forespørgslen og ser derefter på
sqlout.txt
fil. Her er outputtet, formateret til læsbarhed: SQLExecDirect: SELECT "CityID" ,"CityName" ,"StateProvinceID" ,"Location" ,"LatestRecordedPopulation" ,"LastEditedBy" ,"ValidFrom" ,"ValidTo" FROM "Application"."Cities"Der var få forskelle mellem det, vi skrev i Access’ forespørgsel, sammenlignet med det, som Access sendte til ODBC, som vi vil analysere.
- Adgang kvalificerede tabellen med skemanavnet. I Access SQL-dialekt fungerer det naturligvis ikke på samme måde, men for ODBC SQL-dialekt er det nyttigt at sikre, at vi vælger fra den rigtige tabel. Det er styret af
SourceTableName
ejendom. - Adgang udvidede indholdet af
Cities.*
ind i en opregnet liste over alle kolonner, som Access allerede kender til baseret påFields
samling af den underliggendeTableDef
objekt. - Adgang brugte
"
for at citere identifikatorerne, hvilket er hvad ODBC SQL dialekt forventer. Selvom både Access SQL og Transact-SQL bruger parenteser til at citere en identifikator, er det ikke en lovlig syntaks i ODBC SQL-dialekten.
Så selvom vi kun lavede en simpel snapshot-forespørgsel, der valgte alle kolonner til en tabel, kan du se, at Access udfører en masse transformation til SQL'en mellem det, du sætter i Access-forespørgselsdesignvisningen eller SQL-visningen i forhold til, hvad Access faktisk udsender til dataene kilde. I dette tilfælde er det dog for det meste syntaktisk, så der er ingen reel forskel i SQL-sætningen mellem den originale Access-forespørgsel og ODBC SQL-sætningen.
Sporet tilføjede også SQLExecDirect
ved starten af SQL-sætningen. Vi vender tilbage til det, når vi har set på nogle få andre eksempler.
Dynaset type recordsets
Vi bruger den samme forespørgsel, men ændrer egenskaben tilbage til dens standard, Dynaset
.
Kør det igen, og vi vil se, hvad vi får fra sqlout.txt
. Igen er det formateret til læsbarhed:
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, der sker en masse ting! Dette er bestemt mere chatty end snapshot-typen recordset. Lad os gennemgå dem én efter én.
Den første vælger kun CityID
kolonne. Det er tilfældigvis den primære nøgle i tabellen, men endnu vigtigere, det er det indeks, som Access bruger på sin side. Det bliver vigtigt, når vi senere studerer synspunkter. Access bruger denne forespørgsel til at hente nøglerne og bruge den til at udfylde andre forespørgsler senere, som vi vil se.
Den anden sætning er tættere på den oprindelige snapshot-forespørgsel, bortset fra at vi nu har en ny WHERE
klausulfiltrering på CityID
kolonne. Ud fra det kan vi se, at det er en enkelt rækkes hentning. Vi kan bruge de nøgler, vi fik fra den første forespørgsel, og samle resten af kolonnerne i denne forespørgsel. Hver gang den forberedte sætning bliver udført, vil du se en SQLExecute: (GOTO BOOKMARK)
.
Men det ville være ineffektivt, hvis vi skulle gøre dette for alle rækker... Og det er her, den næste forespørgsel kommer ind. Den 3. sætning ligner den 2. men har 10 prædikater. Denne forberedte forespørgsel udføres med hver SQLExecute: (MULTI_ROW FETCH)
. Så hvad dette betyder er, at når vi indlæser en formular eller et dataark eller endda åbner et recordset i VBA-kode, vil Access bruge enten versionen med én række eller flere rækker og udfylde parametrene ved hjælp af de nøgler, den fik fra den første forespørgsel.
Baggrundshentning og gensynkronisering
I øvrigt, har du nogensinde lagt mærke til, hvordan du, når du åbner en formular eller et dataark, ikke kan se "X'et af Y" i navigationslinjen?
Det skyldes, at Access ikke kan vide, hvor mange der er, før den er færdig med at indsamle resultaterne fra den første forespørgsel. Derfor kan du ofte opleve, at det er meget hurtigt at åbne en forespørgsel, der returnerer store mængder data. Du får kun vist et lille vindue af hele postsættet, mens Access henter rækkerne i baggrunden. Hvis du klikker på knappen "Gå til sidst", vil du muligvis opdage, at den fryser Access. Du skal vente, indtil den er færdig med at hente alle nøglerne i den første forespørgsel, før vi kan se "X af Y" i navigationslinjen.
Således kan du forstå, hvordan Access kan give illusionen af at være hurtig til at åbne selv et stort postsæt, når vi bruger et rekordsæt af dynaset-typen, og det er normalt en god oplevelse for brugeren.
Til sidst skal vi bemærke, at vi har 3 forskellige typer henrettelser, SQLExecDirect
, SQLPrepare
og SQLExecute
. Du kan se, at med førstnævnte har vi ingen parametre. Forespørgslen er simpelthen som den er. Men hvis en forespørgsel skal parametreres, skal den først forberedes via SQLPrepare
og derefter senere udført med SQLExecute
med værdier for parametre angivet. Vi kan ikke se, hvilke værdier der rent faktisk blev sendt til SQLExecute
erklæring, selvom vi kan udlede af, hvad vi ser i Access. Du kan kun vide, om den hentede en enkelt række (ved hjælp af SQLExecute: (GOTO BOOKMARK)
eller flere rækker (ved hjælp af SQLExecute: (MULTI-ROW FETCH)
). Access vil bruge versionen med flere rækker til at hente baggrunden og udfylde postsættet trinvist, men brug versionen med en række til kun at udfylde én række. Det kan være tilfældet på en enkelt formularvisning i modsætning til kontinuerlig formular- eller dataarkvisning eller brug den til resynkronisering efter en opdatering.
Naviger rundt
Med et stort nok rekordsæt vil Access muligvis ikke blive færdig med at hente alle posterne. Som tidligere nævnt præsenteres brugeren for dataene så hurtigt som muligt. Normalt, når brugeren navigerer frem gennem postsættet, vil Access blive ved med at hente flere og flere poster for at holde bufferen foran brugeren.
Men antag, at brugeren hopper til 100. række ved at gå til navigationskontrol og indtaste 100 der?
I så fald vil Access indsende følgende forespørgsler...
SQLExecute: (MULTI-ROW FETCH) SQLExecute: (GOTO BOOKMARK) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH)Bemærk, hvordan Access bruger de allerede forberedte sætninger, den oprettede på tidspunktet for åbning af postsættet. Fordi den allerede har nøglerne fra den første forespørgsel, er den i stand til at vide, hvilken der er den "100." række. For at bruge et mere konkret eksempel. Antag, at vi havde
CityID
starter ved 1, 3, 4, 5…99, 100, 101, 102 uden registrering for CityID = 2
. I den første forespørgsel, CityID
101 ville være i 100. række. Derfor, når brugeren hopper til 100, slår Access den 100. række op i den første forespørgsel, og se, at det er CityID
101, tager derefter denne værdi og fører den ind i SQLExecute: (GOTO BOOKMARK)
for straks at navigere til denne post. Den ser derefter på de næste 10 poster og bruger de efterfølgende CityID
for at fylde bufferen med flere SQLExecute: (MULTI-ROW FETCH)
. Du har måske bemærket, at der er en hentning af flere rækker før en enkelt rækkehentning. Access henter faktisk den 101.-110. række i hentningen af flere rækker og henter den 100. post i den næste hentning af enkelt række. Når Access har fået dataene for rækkerne på 100. Det tager brugeren dertil, og begynd derefter at fylde bufferen op omkring den 100. række. Det gør det muligt for brugeren at se den 100. række uden at skulle vente på at indlæse alle de 11.-99. Brugeren har tilsyneladende også hurtig browsing-oplevelse, når brugeren klikker på forrige eller næste fra den nye position, fordi Access allerede har indlæst det i baggrunden, før brugeren bad om det. Det hjælper med at give illusionen af at være hurtig selv over et langsomt netværk.
Men selvom brugeren lod formularen være åben og inaktiv, ville Access fortsætte med at udføre både baggrundshentning og opdatere bufferen for at undgå at vise brugerens forældede data. Det er styret af ODBC-indstillingerne i Options-dialogen under sektionen Avanceret på fanen Klientindstilling:
Standarden for ODBC-opdateringsintervallet er 1500 sekunder, men kan ændres. Det kan også ændres via VBA.
Konklusioner:Chunky eller Chatty
Du skal nu se, at hovedårsagen til, at rekordsæt af dynaset-typen kan opdateres, men rekordsæt af snapshot-typen ikke er, fordi Access er i stand til at erstatte en række i postsættet med den nyeste version af det samme fra serveren, da den ved, hvordan man vælger en enkelt række. Af den grund skal Access administrere 2 ODBC-forespørgsler; en for at hente nøglerne og en anden for at hente det faktiske indhold af rækker for en given nøgle. Disse oplysninger var ikke til stede i et rekordsæt af snapshot-typen. Vi har lige fået en stor klat data.
Vi så på 2 hovedtyper af rekordsæt, selvom der er flere. Andre er dog blot varianter af de 2 typer, vi dækkede. Men indtil videre er det tilstrækkeligt at huske, at det at bruge snapshot er at være chunky i vores netværkskommunikation. På den anden side betyder det at bruge dynaset, at vi bliver snakkesalige. Begge har deres op- og nedture.
For eksempel behøver snapshot recordset ikke yderligere kommunikation med serveren, når det først har hentet dataene. Så længe rekordsættet forbliver åbent, kan Access frit navigere rundt i dets lokale cache. Access behøver heller ikke at holde nogen låse og dermed blokere andre brugere. Et snapshot-optagelsessæt er dog nødvendigvis langsommere at åbne, da det skal indsamle alle data på forhånd. Det kan passe dårligt til et stort rekordsæt, selvom du har til hensigt at læse alle data.
Antag, at du opretter en stor Access-rapport, der er på 100 sider, er det normalt umagen værd at bruge rekordsæt af dynaset-typen. Den kan begynde at gengive forhåndsvisningen, så snart den har nok til at gengive den første side. Det er bedre end at tvinge dig til at vente, indtil den har hentet alle data, før den kan begynde at gengive forhåndsvisningen. Selvom et dynaset recordset kan tage låse, er det normalt for kort tid. Den er kun lang nok til, at Access kan resynkronisere sin lokale cache.
Men når vi tænker på, hvor mange flere anmodninger Access sender over netværket med et rekordsæt af dynaset-typen, er det let at se, at hvis netværksforsinkelsen er dårlig, vil Access' ydeevne lide tilsvarende. For at Access kan tillade brugere at redigere og opdatere datakilder på en generisk måde kræver det, at Access holder styr på nøgler til at vælge og ændre en enkelt række. Det vil vi se på i de kommende artikler. I den næste artikel vil vi se på, hvordan sortering og grupper påvirker et rekordsæt af dynaset-typen, samt hvordan Access bestemmer, hvilken nøgle der skal bruges til et rekordsæt af dynaset.
For mere hjælp med Microsoft Access, ring til vores eksperter på 773-809-5456 eller e-mail os på [email protected].