Účinek spojení v sadě záznamů
V našem šestém a posledním článku série trasování ODBC se podíváme na to, jak Access zpracuje spojení v dotazech Accessu. V předchozím článku jste viděli, jak Access zpracovává filtry. V závislosti na výrazu se může Access rozhodnout, že jej parametrizuje, nebo může být nucen jej vyhodnotit sám stažením všech vstupních dat a provedením vyhodnocení lokálně. V tomto článku se zaměříme na joiny. Když se nad tím zamyslíte, spojení jsou vlastně zvláštní druh filtru. Proto by se teoreticky měl Access oddálit co nejvíce i s připojeními. Obvykle můžete vidět spojení zapsaná v následujícím pseudo-SQL:
FROM a INNER JOIN b ON a.ID = b.IDLze jej však považovat za ekvivalentní následující syntaxi:
FROM a, b WHERE a.ID = b.IDTo ilustruje, že i když můžeme použít čitelnější a známější
JOIN..ON
, Přístup je zdarma a lze jej považovat za WHERE
což je užitečné v situacích, kdy Access nemůže plně vzdálený dotaz. Ale tady je háček… kdy se Access rozhodne vzdálená spojení? Zkusme jednoduchý spojovací dotaz: SELECT c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceName FROM Cities AS c INNER JOIN StateProvinces AS s ON c.StateProvinceID = s.StateProvinceID;Pokud tento dotaz vysledujeme, uvidíme následující výstup:
SQLExecDirect: SELECT "c"."CityID" ,"s"."StateProvinceID" FROM "Application"."Cities" "c", "Application"."StateProvinces" "s" WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" ) SQLPrepare: SELECT "CityID" ,"CityName" ,"StateProvinceID" FROM "Application"."Cities" WHERE "CityID" = ? SQLExecute: (GOTO BOOKMARK) SQLPrepare: SELECT "StateProvinceID" ,"StateProvinceName" FROM "Application"."StateProvinces" WHERE "StateProvinceID" = ? SQLExecute: (GOTO BOOKMARK) SQLPrepare: SELECT "StateProvinceID" ,"StateProvinceName" FROM "Application"."StateProvinces" WHERE "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? SQLExecute: (MULTI-ROW FETCH) SQLPrepare: SELECT "CityID" ,"CityName" ,"StateProvinceID" 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) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH)Access se rozhodl, že spojení nebude vzdálené, i když původní dotaz Accessu je dokonale možné spustit na serveru SQL Server. Místo toho získal ID z každé tabulky v theta-spojení a pak nastavil 2 samostatné řetězce dotazů, jako bychom otevřeli 2 sady záznamů typu dynaset. Do dvou různých připravených dotazů jsou pak vloženy klíče pro příslušné tabulky z prvního dotazu. Předvídatelně to může být hodně štěbetání po síti.
Pokud změníme stejný Access dotaz na typ snímku místo výchozího typu dynaset, dostaneme:
SQLExecDirect: SELECT "c"."CityID" ,"c"."CityName" ,"c"."StateProvinceID" ,"s"."StateProvinceName" FROM "Application"."Cities" "c", "Application"."StateProvinces" "s" WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" )V případě dotazu typu snímek tedy Access provede vzdálené spojení v pohodě. Proč to Access neudělal s původním dotazem typu dynaset? Nápověda je na následujícím snímku obrazovky, kde se pokoušíme upravit obě sloupce tabulek na následujícím snímku obrazovky:
Takový dotaz umožňuje aktualizaci na oba sloupce. To není ve skutečnosti vyjádřitelné v SQL, ale taková akce je pro uživatele legální. K provedení této aktualizace by tedy Access odeslal následující SQL ODBC:
SQLExecDirect: UPDATE "Application"."StateProvinces" SET "StateProvinceName"=? WHERE "StateProvinceID" = ? AND "StateProvinceName" = ? SQLExecDirect: UPDATE "Application"."Cities" SET "CityName"=? WHERE "CityID" = ? AND "CityName" = ? AND "StateProvinceID" = ?To by nebylo možné, pokud by Access neměl informace potřebné k aktualizaci každé tabulky, což vysvětluje, proč se Access při řešení původního dotazu typu dynaset rozhodl nevzdálit spojení. Z toho plyne ponaučení, že pokud nepotřebujete, aby byl dotaz aktualizovatelný, a výsledná data jsou dostatečně malá, může být lepší převést dotaz na typ snímku. V případě, kdy potřebujete formulovat komplexní zdroj záznamů, obvykle získáte mnohem lepší výkon s použitím pohledu SQL jako základu, než kdybyste dělali spojení na straně Accessu.
Abychom to dokázali, vytvoříme pohled SQL a propojíme jej s Access:
CREATE VIEW dbo.vwCitiesAndStates AS SELECT c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceName FROM Application.Cities AS c INNER JOIN Application.StateProvinces AS s ON c.StateProvinceID = s.StateProvinceID;Poté upravíme Access dotaz následovně:
SELECT c.CityID ,c.StateProvinceID ,c.CityName ,c.StateProvinceName FROM vwCitiesAndStates AS c;Pokud poté zopakujeme aktualizaci, kterou jsme původně zkusili, měli bychom vidět následující trasované ODBC SQL:
SQLExecDirect: SELECT "c"."CityID" FROM "dbo"."vwCitiesAndStates" "c" SQLPrepare: SELECT "CityID" ,"StateProvinceID" ,"CityName" ,"StateProvinceName" FROM "dbo"."vwCitiesAndStates" WHERE "CityID" = ? SQLExecute: (GOTO BOOKMARK) SQLPrepare: SELECT "CityID" ,"StateProvinceID" ,"CityName" ,"StateProvinceName" FROM "dbo"."vwCitiesAndStates" 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) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (GOTO BOOKMARK) SQLExecDirect: UPDATE "dbo"."vwCitiesAndStates" SET "CityName"=?, "StateProvinceName"=? WHERE "CityID" = ? AND "StateProvinceID" = ? AND "CityName" = ? AND "StateProvinceName" = ?To ukazuje, že pomocí zobrazení SQL pro „vzdálené“ spojení bude Access fungovat pouze s jedním zdrojem, nikoli se 2 tabulkami a bude plně vzdálenou aktualizaci na zobrazení SQL Serveru. Jedním z vedlejších efektů je, že tato aktualizace nyní selže s chybovou zprávou:
To by nemělo být překvapením, protože jsme prováděli UPDATE
na jediném zdroji, zatímco v původním příkladu Access ve skutečnosti tajně vydával dva samostatné UPDATE
výpisy na každé jednotlivé tabulce. Doufejme, že to pomůže objasnit, že byste se měli vyvarovat spojování v dotazech Access/recordsources/rowsources, zvláště když potřebují být aktualizovatelné. Pokud ne, použijte snímek tam, kde je to možné.
Rychlá poznámka týkající se heterogenních spojení
Potřebujeme komentář týkající se spojení mezi dvěma propojenými tabulkami, které pocházejí ze dvou různých zdrojů dat ODBC. Taková spojení jsou „heterogenní“, protože Access musí zpracovávat spojení lokálně, protože se předpokládá, že se každý zdroj dat o sobě navzájem neznají. Bez ohledu na to, zda zadáte sady záznamů typu dynaset nebo typu snímku, musí Access načíst úplnou sadu klíčů z každého zdroje dat a vyřešit spojení odesláním samostatných parametrizovaných dotazů do každého zdroje dat. Pokud je aktualizace povolena, Access vytvoří samostatnou UPDATE
dotaz na každý zdroj dat, který je třeba aktualizovat. Je také důležité poznamenat, že spojení mezi dvěma propojenými tabulkami, které pochází ze dvou různých databází, považuje Access stále za heterogenní. To stále platí, i když jsou dvě databáze na stejném serveru a nemáte problém s křížovými databázovými dotazy. V tomto scénáři může zobrazení SQL pomoci omezit další klábosení tím, že skryje křížová databázová spojení před Accessem, podobně jako jsme již viděli v tomto článku.
Rozdíl v syntaxi vnějšího spojení
Dokud vnější spojení neovlivní aktualizovatelnost dotazu Accessu, Access jej zpracuje podobně jako verzi vnitřního spojení. Pokud upravíme stejný dotaz, který jsme bývali levým spojením, trasovaný ODBC SQL vypíše dotaz na klíčové populace takto:
SQLExecDirect: SELECT "c"."CityID" ,"s"."StateProvinceID" FROM {oj "Application"."Cities" "c" LEFT OUTER JOIN "Application"."StateProvinces" "s" ON ("c"."StateProvinceID" = "s"."StateProvinceID" ) }Syntaxe vypadá zcela odlišně od toho, co byste mohli očekávat v jiných dialektech SQL. Je to proto, že gramatika ODBC SQL vyžaduje, aby všechna vnější spojení byla zabalena do
{oj ...}
výraz. Další podrobnosti o této syntaxi naleznete v dokumentaci. Pro náš účel můžeme jednoduše ignorovat {oj
a koncový }
jako hluk. Závěry
Viděli jsme, že s připojeními se zachází, jako by to byl druh filtru a Access se pokusí vzdálená připojení tam, kde je to povoleno. Jednou z konkrétních oblastí, kterým je třeba věnovat velkou pozornost, je skutečnost, že ve výchozím nastavení používáme sady záznamů typu dynaset a Access nebude dělat žádné předpoklady o tom, zda chceme povolit úpravy tak a tak sloupců v sadě záznamů, a jde z toho, aby nám to umožnil. aktualizovat na dvě tabulky, což ve skutečnosti není ve standardním SQL snadno vyjádřeno. V důsledku toho Access udělá mnohem více práce na podpoře aktualizovatelnosti pro dotaz, který obsahuje spojení, která mohou negativně ovlivnit výkon.
Můžeme pomoci vyhnout se penalizaci tím, že místo spojení vyjádřených v dotazu Access použijeme pohledy SQL. Kompromisem je, že pak podléháme pravidlům aktualizovatelnosti pohledu SQL; možná nám nebude dovoleno aktualizovat dvě tabulky současně. Obvykle proto, že dobře navržený přístupový formulář bude představovat pouze jednu tabulku k aktualizaci, není to příliš velké omezení a je dobré se řídit.
Tím je aktuální série hotová. Poučení, které série snad jiskří, by se však nemělo dělat. Upřímně doufám, že pro vás byla tato řada užitečná, a těším se na nové poznatky, které jste získali díky používání nástrojů, které vám pomohou analyzovat a řešit problémy s výkonem aplikací Access využívajících zdroje dat ODBC. Neváhejte zanechat komentáře nebo žádost o další informace a děkujeme za společné čtení!
Pro další pomoc s čímkoli souvisejícím s Microsoft Access zavolejte našim odborníkům na číslo 773-809-5456 nebo nám pošlete e-mail na adresu [email protected].