Effekt af joinforbindelser i et recordset
I vores sjette og sidste artikel i ODBC-sporingsserien vil vi tage et kig på, hvordan Access vil håndtere joinforbindelser i Access-forespørgsler. I den forrige artikel så du, hvordan filtre håndteres af Access. Afhængigt af udtrykket kan Access vælge at parametrere det væk eller blive tvunget til selv at evaluere det ved at downloade alle inputdata og derefter udføre evalueringerne lokalt. I denne artikel vil vi fokusere på joinforbindelser. Når du tænker over det, er joins faktisk en speciel slags filter. Derfor burde Access i teorien fjerne så meget som muligt, selv med joinforbindelser. Du kan typisk se joins skrevet i følgende pseudo-SQL:
FRA en INDER JOIN b PÅ a.ID =b.IDDet kan dog betragtes som svarende til følgende syntaks:
FRA a, b HVOR a.ID =b.IDDet illustrerer, at selvom vi måske bruger det mere læsbare og velkendte
JOIN..ON
, Adgang er gratis at behandle det som en Hvor hvilket er nyttigt i situationer, hvor Access ikke kan fjerne forespørgslen fuldstændigt. Men her er spørgsmålet ... hvornår beslutter Access sig for at fjerne joinforbindelserne? Lad os prøve en simpel joinforespørgsel: VÆLG c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceNameFROM Cities AS c INNER JOIN StateProvinces AS s ON c.StateProvinceID =s.StateProvinceID;
Hvis vi sporer den forespørgsel, vil vi se følgende output: SQLExecDirect:VÆLG "c"."CityID" ,"s"."StateProvinceID" FRA "Application"."Cities" "c", "Application"."StateProvinces" "s" WHERE ("c"." StateProvinceID" ="s"."StateProvinceID" ) SQLPrepare:VÆLG "CityID" ,"CityName" ,"StateProvinceID" FRA "Application"."Cities" WHERE "CityID" =?SQLEExecute:(GOTO BOOKMARK)SQLPrepare:SELECTID "State SELECTID" " ,"StateProvinceName" FRA "Application"."StateProvinces" HVOR "StateProvinceID" =?SQLEExecute:(GOTO BOOKMARK)SQLPrepare:VÆLG "StateProvinceID" ,"StateProvinceName" FRA "ApplicationState"."StateProvinces" =ProvinceID" WHERE? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =? ELLER "StateProvinceID" =?SQLEExecute:(MULTI-ROW FETCH)SQLPrepare:VÆLG "CityID" ,"CityName" ,"StateProvinceID" FRA "Application"."Cities" WHERE "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =?SQLEeksecute:(MULTI-ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLExecute:(MULTI-ROW FETCH)SQLExecute:(MULTI-ROW FETCH) -ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLEexecute:(MULTI-ROW FETCH)SQLEexecute:(MULTI-ROW FETCH)
Access besluttede ikke at fjerne joinforbindelsen, selvom den originale Access-forespørgsel er perfekt i stand til at blive udført på SQL Server. I stedet fik den ID'erne fra hver tabel i en theta-join, og satte derefter 2 separate kæder af forespørgsler op, som om vi havde åbnet 2 rekordsæt af dynaset-typen. De to forskellige forberedte forespørgsler tilføres derefter nøglerne til de respektive tabeller fra den første forespørgsel. Forudsigeligt kan det være en masse snak at gå over netværket.
Hvis vi ændrer den samme Access-forespørgsel til at være en snapshot-type i stedet for standard-dynaset-typen, får vi:
SQLExecDirect:VÆLG "c"."CityID" ,"c"."Bynavn" ,"c"."StateProvinceID" ,"s"."StateProvinceName" FRA "Application"."Byer" "c", " Application"."StateProvinces" "s" WHERE ("c"."StateProvinceID" ="s"."StateProvinceID" )
Så Access fjerner joinforbindelserne fint i tilfælde af en forespørgsel af snapshot-typen. Hvorfor gjorde Access ikke det med den originale dynaset-type forespørgsel? Ledetråden er i det følgende skærmbillede, hvor vi forsøger at redigere begge tabellernes kolonner i følgende skærmbillede:
En sådan forespørgsel tillader opdatering til begge kolonner. Det kan faktisk ikke udtrykkes i SQL, men en sådan handling er lovlig for brugeren at udføre. Derfor, for at udføre denne opdatering, vil Access indsende følgende ODBC SQL:
SQLExecDirect:OPDATERING "Application"."StateProvinces" SET "StateProvinceName"=? HVOR "StateProvinceID" =? OG "StateProvinceName" =?SQLExecDirect:OPDATERING "Application"."Cities" SET "CityName"=? HVOR "CityID" =? OG "Bynavn" =? OG "StateProvinceID" =?
Det ville ikke være muligt, hvis Access ikke havde de nødvendige oplysninger til at opdatere hver tabel, hvilket forklarer, hvorfor Access valgte ikke at fjerne joinforbindelsen, da den oprindelige dynaset-type forespørgsel blev løst. Læren her er, at hvis du ikke har brug for en forespørgsel for at kunne opdateres, og de resulterende data er små nok, kan det være bedre at konvertere forespørgslen til en snapshot-type. I det tilfælde, hvor du har brug for at formulere en kompleks registreringskilde, vil du normalt få meget bedre ydeevne ved at bruge en SQL-visning som base end at lave joinforbindelser på Access-siden.
For at bevise dette vil vi oprette en SQL-visning og linke den til Access:
OPRET VISNING dbo.vwCitiesAndStates ASSELECT c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceNameFRA Application.Cities AS c INNER JOIN Application.StateProvinces AS s ON c.StateProvinceID =s.StateProvinceID;
Vi justerer derefter Access-forespørgslen som følger: VÆLG c.CityID ,c.StateProvinceID ,c.CityName ,c.StateProvinceNameFRA vwCitiesAndStates AS c;
Hvis vi derefter gentager den opdatering, vi prøvede oprindeligt, skulle vi se følgende sporede ODBC SQL: SQLExecDirect:VÆLG "c"."CityID" FRA "dbo"."vwCitiesAndStates" "c" SQLPrepare:VÆLG "CityID" ,"StateProvinceID" ,"CityName" ,"StateProvinceName" FRA "dbo"."vwCitiesAndStates" HVOR "CityID" =?SQLEExecute:(GOTO BOOKMARK)SQLPrepare:VÆLG "CityID" ,"StateProvinceID" ,"CityName" ,"StateProvinceName" FRA "dbo"."vwCitiesAndStates" HVOR "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =? ELLER "CityID" =?SQLEeksecute:(MULTI-ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLEeksecute:(MULTI-ROW FETCH)SQLExecute FETCH:(MULTI-ROW FETCH)RO BOOKMARK)SQLExecDirect:OPDATERING "dbo"."vwCitiesAndStates" SET "CityName"=?, "StateProvinceName"=? HVOR "CityID" =? OG "StateProvinceID" =? OG "Bynavn" =? OG "StateProvinceName" =?
Dette viser, at ved at bruge SQL-visninger til at "fjerne" joinforbindelserne, vil Access kun fungere med en enkelt kilde i stedet for med 2 tabeller og fjern opdateringen af visningen til SQL Server. En bivirkning er, at denne opdatering nu mislykkes med fejlmeddelelsen:
Det burde ikke komme som en overraskelse, da vi lavede en OPDATERING
på en enkelt kilde, hvorimod Access i det originale eksempel faktisk hemmeligt udstedte to separat OPDATERING
udsagn på hver enkelt tabel. Forhåbentlig hjælper det med at gøre det tilfældet, at du bør undgå at lave joins i Access-forespørgsler/recordsources/rowsources, især når de skal kunne opdateres. Hvis de ikke gør det, skal du bruge et øjebliksbillede, hvor det er muligt.
En hurtig bemærkning om heterogene sammenføjninger
Vi er nødt til at kommentere angående joinforbindelser mellem to sammenkædede tabeller, der kommer fra to forskellige ODBC-datakilder. Sådanne joinforbindelser er "heterogene", fordi Access skal håndtere joinforbindelserne lokalt, da hver datakilde antages at ikke kender til hinanden. Uanset om du angiver et recordsæt af dynaset- eller snapshot-type, skal Access hente det fulde sæt af nøgler fra hver datakilde og løse joinforbindelserne ved at sende separate parametriserede forespørgsler til hver datakilde. Hvis opdatering er tilladt, vil Access formulere en separat OPDATERING forespørgsel til hver datakilde, der skal opdateres. Det er også vigtigt at bemærke, at en joinforbindelse mellem to sammenkædede tabeller, der kommer fra to forskellige databaser, hver stadig betragtes af Access som heterogen. Det er stadig sandt, selvom de to databaser er på den samme server, og du ikke har noget problem med at lave krydsdatabaseforespørgsler. I dette scenarie kan en SQL-visning hjælpe med at skære ned på den ekstra chatter ved at skjule krydsdatabaseforbindelserne fra Access svarende til det, vi så allerede i denne artikel.
Syntaksforskel for ydre joinforbindelse
Så længe de ydre joinforbindelser ikke påvirker opdateringsevnen af Access-forespørgslen, vil Access håndtere det på samme måde som den håndterede den indre join-version. Hvis vi ændrer den samme forespørgsel, som vi plejede at være en venstre joinforbindelse, vil den sporede ODBC SQL udsende nøglepopulationsforespørgslen sådan:
SQLExecDirect:VÆLG "c"."CityID" ,"s"."StateProvinceID" FRA {oj "Application"."Cities" "c" VENSTRE YDRE JOIN "Application"."StateProvinces" "s" TIL (" c"."StateProvinceID" ="s"."StateProvinceID" ) }
Syntaksen ser ganske anderledes ud, end du kunne forvente i andre SQL-dialekter. Det skyldes, at ODBC SQL-grammatik kræver, at enhver ydre joinforbindelse er pakket ind i en {oj ...}
udtryk. Se dokumentationen for flere detaljer om den syntaks. Til vores formål kan vi bare se bort fra {oj
og den afsluttende }
som støj. Konklusioner
Vi så, at joins bliver behandlet som om de er en slags filter, og Access vil forsøge at fjerne joins, hvor det er tilladt. Et særligt område at være meget opmærksom på er det faktum, at vi som standard bruger dynaset type recordsets, og Access vil ikke gøre nogen antagelser om, hvorvidt vi vil tillade ændring af sådan og sådan kolonner i postsættet og går ud af det for at gøre det muligt for os at opdatere til to tabeller, som faktisk ikke er let at udtrykke i standard SQL. Som en konsekvens heraf vil Access gøre meget mere arbejde for at understøtte opdateringsmuligheder for en forespørgsel, der indeholder joinforbindelser, som kan påvirke ydeevnen negativt.
Vi kan hjælpe med at undgå straffen ved at bruge SQL-visninger i stedet for joinforbindelser udtrykt i en Access-forespørgsel. Afvejningen er, at vi så er underlagt reglerne for opdatering af en SQL-visning; Vi har muligvis ikke lov til at opdatere to tabeller på samme tid. Normalt fordi en veldesignet adgangsformular kun repræsenterer en enkelt tabel, der skal opdateres, er det ikke meget af en begrænsning og er en god disciplin at følge.
Dermed er den nuværende serie færdig. Den læring, som serien forhåbentlig afføder, bør dog ikke lade sig gøre. Jeg håber inderligt, at du fandt serien nyttig og ser frem til at høre om ny indsigt, du har fået ved at bruge værktøjer til at hjælpe med at analysere og løse ydeevneproblemer med Access-applikationer, der bruger ODBC-datakilder. Du er velkommen til at efterlade kommentarer eller anmode om mere information og tak fordi du læser sammen!
Ring til vores eksperter på 773-809-5456 eller e-mail os på [email protected] for at få yderligere hjælp til alt hvad der er relateret til Microsoft Access.