sql >> Database >  >> RDS >> Access

Hoe praat Access met ODBC-gegevensbronnen? Deel 6

Effect van samenvoegingen in een recordset

In ons zesde en laatste artikel van de ODBC-traceerreeks gaan we kijken hoe Access joins in Access-query's afhandelt. In het vorige artikel heb je gezien hoe filters worden afgehandeld door Access. Afhankelijk van de uitdrukking kan Access ervoor kiezen om het weg te parametriseren of kan het worden gedwongen om het zelf te evalueren door alle invoergegevens te downloaden en vervolgens de evaluaties lokaal uit te voeren. In dit artikel zullen we ons concentreren op joins. Als je erover nadenkt, zijn joins eigenlijk een speciaal soort filter. Daarom zou Access in theorie zoveel mogelijk remote moeten zijn, zelfs met joins. Meestal ziet u joins geschreven in de volgende pseudo-SQL:

FROM a INNER JOIN b ON a.ID = b.ID
Het kan echter worden beschouwd als gelijkwaardig aan de volgende syntaxis:

FROM a, b WHERE a.ID = b.ID
Dat illustreert dat, ook al gebruiken we misschien de meer leesbare en bekende JOIN..ON , Toegang is gratis om het te behandelen als een WHERE wat handig is in situaties waarin Access de query niet volledig kan verwijderen. Maar hier is het probleem ... wanneer besluit Access om de joins op afstand te houden? Laten we een eenvoudige join-query proberen:

SELECT 
   c.CityID
  ,c.StateProvinceID
  ,c.CityName
  ,s.StateProvinceName
FROM Cities AS c 
INNER JOIN StateProvinces AS s 
  ON c.StateProvinceID = s.StateProvinceID;
Als we die zoekopdracht traceren, zien we de volgende uitvoer:

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 heeft besloten om de join niet op afstand te doen, hoewel de oorspronkelijke Access-query perfect kan worden uitgevoerd op SQL Server. In plaats daarvan kreeg het de ID's van elke tabel in een theta-join en zette het vervolgens 2 afzonderlijke reeksen query's op alsof we 2 recordsets van het dynaset-type hadden geopend. De twee verschillende voorbereide query's krijgen vervolgens de sleutels voor de respectieve tabellen van de eerste query. Voorspelbaar, dat kan veel geklets zijn om over het netwerk te gaan.

Als we dezelfde Access-query wijzigen in een snapshot-type in plaats van het standaard dynaset-type, krijgen we:

SQLExecDirect: 
SELECT 
   "c"."CityID"
  ,"c"."CityName"
  ,"c"."StateProvinceID"
  ,"s"."StateProvinceName"  
FROM "Application"."Cities" "c",
     "Application"."StateProvinces" "s" 
WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" )
Dus Access doet de joins op afstand prima in het geval van een snapshot-type query. Waarom deed Access dat niet met de oorspronkelijke query van het dynaset-type? De aanwijzing staat in de volgende schermafbeelding waar we proberen beide te bewerken tabellen' kolommen in de volgende schermafbeelding:

Een dergelijke zoekopdracht maakt het mogelijk om naar beide kolommen te updaten. Dat is niet echt uit te drukken in SQL, maar een dergelijke actie is legaal voor de gebruiker om uit te voeren. Om die update uit te voeren, zou Access daarom de volgende ODBC-SQL indienen:

SQLExecDirect: 
UPDATE "Application"."StateProvinces" 
SET "StateProvinceName"=?  
WHERE "StateProvinceID" = ? 
  AND "StateProvinceName" = ?

SQLExecDirect: 
UPDATE "Application"."Cities" 
SET "CityName"=?  
WHERE "CityID" = ? 
  AND "CityName" = ? 
  AND "StateProvinceID" = ?
Dat zou niet mogelijk zijn als Access niet over de informatie zou beschikken die nodig is om elke tabel bij te werken, wat verklaart waarom Access ervoor heeft gekozen om de join niet op afstand te doen bij het oplossen van de oorspronkelijke query van het dynaset-type. De les hier is dat als je een query niet nodig hebt om te worden bijgewerkt en de resulterende gegevens klein genoeg zijn, het misschien beter is om de query om te zetten in een snapshot-type. In het geval dat u een complexe recordbron moet formuleren, krijgt u meestal veel betere prestaties met een SQL-view als basis dan wanneer u de joins aan de Access-kant doet.

Om dit te bewijzen, zullen we een SQL-view maken en deze koppelen aan 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;
Vervolgens passen we de Access-query als volgt aan:

SELECT 
   c.CityID
  ,c.StateProvinceID
  ,c.CityName
  ,c.StateProvinceName
FROM vwCitiesAndStates AS c;
Als we vervolgens de update herhalen die we oorspronkelijk hebben geprobeerd, zouden we de volgende getraceerde ODBC SQL moeten zien:

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" = ?
Dit toont aan dat het gebruik van SQL-views om de joins "op afstand" te plaatsen, Access alleen werkt met een enkele bron, in plaats van met 2 tabellen en de update van de view volledig naar SQL Server kan uitvoeren. Een neveneffect is dat deze update nu zal mislukken met de foutmelding:

Dat zou geen verrassing moeten zijn aangezien we een UPDATE aan het doen waren op een enkele bron, terwijl Access in het oorspronkelijke voorbeeld in feite in het geheim twee uitgaf aparte UPDATE verklaringen op elke afzonderlijke tafel. Hopelijk helpt dat om aan te tonen dat je moet voorkomen dat je joins doet in Access-query's/recordsources/rowsources, vooral wanneer ze moeten worden bijgewerkt. Als dat niet het geval is, gebruik dan waar mogelijk snapshot.

Een korte opmerking over heterogene joins

We moeten iets zeggen over joins tussen twee gekoppelde tabellen die afkomstig zijn uit twee verschillende ODBC-gegevensbronnen. Dergelijke joins zijn "heterogeen" omdat Access de joins lokaal moet afhandelen, aangezien wordt aangenomen dat beide gegevensbronnen elkaar niet kennen. Ongeacht of u een dynaset-type of snapshot-type recordsets opgeeft, Access moet de volledige set sleutels ophalen uit elke gegevensbron en de joins oplossen door afzonderlijke geparametriseerde query's naar elke gegevensbron te verzenden. Als bijwerken is toegestaan, formuleert Access een aparte UPDATE query naar elke gegevensbron die moet worden bijgewerkt. Het is ook belangrijk op te merken dat een join tussen twee gekoppelde tabellen die uit twee verschillende databases komt, elk door Access nog steeds als heterogeen wordt beschouwd. Dat is nog steeds waar, zelfs als de twee databases zich op dezelfde server bevinden en u geen probleem hebt om kruisdatabasequery's uit te voeren. In dit scenario kan een SQL-weergave helpen om de extra chatter te verminderen door de cross-database-joins van Access te verbergen, vergelijkbaar met wat we al in dit artikel hebben gezien.

Verschil in syntaxis van buitenste join

Zolang de outer joins de bijwerkbaarheid van de Access-query niet beïnvloeden, zal Access deze op dezelfde manier behandelen als de inner join-versie. Als we dezelfde query wijzigen die we gebruikten om een ​​left join te zijn, zal de getraceerde ODBC SQL de sleutelpopulatiequery als volgt uitvoeren:

SQLExecDirect: 
SELECT 
   "c"."CityID"
  ,"s"."StateProvinceID" 
FROM {oj 
	"Application"."Cities" "c" 
	LEFT OUTER JOIN "Application"."StateProvinces" "s" 
		ON ("c"."StateProvinceID" = "s"."StateProvinceID" ) 
}
De syntaxis ziet er heel anders uit dan je zou verwachten in andere SQL-dialecten. Dat komt omdat de ODBC SQL-grammatica vereist dat alle outer joins worden ingepakt in een {oj ...} uitdrukking. Raadpleeg de documentatie voor meer informatie over die syntaxis. Voor ons doel kunnen we de {oj . negeren en de afsluitende } als ruis.

Conclusies

We hebben gezien dat joins worden behandeld alsof ze een soort filter zijn en Access zal proberen de joins op afstand te houden waar dit is toegestaan. Een bijzonder aandachtspunt is het feit dat we standaard recordsets van het type dynaset gebruiken en dat Access geen aannames doet over de vraag of we het wijzigen van die en die kolommen in de recordset willen toestaan ​​en er alles aan doet om het voor ons mogelijk te maken om te updaten naar twee tabellen die eigenlijk niet gemakkelijk worden uitgedrukt in standaard SQL. Als gevolg hiervan zal Access veel meer werk doen om de updatebaarheid te ondersteunen voor een query die joins bevat die de prestaties negatief kunnen beïnvloeden.

We kunnen de boete helpen voorkomen door SQL-views te gebruiken in plaats van joins die in een Access-query worden uitgedrukt. De afweging is dat we dan onderworpen zijn aan de bijwerkbaarheidsregels van een SQL-view; het is mogelijk dat we niet twee tabellen tegelijk mogen bijwerken. Meestal omdat een goed ontworpen Access-formulier slechts één enkele tabel vertegenwoordigt om bij te werken, is dat niet echt een beperking en is het een goede discipline om te volgen.

Daarmee is de huidige serie klaar. Het leren dat de serie hopelijk vonkt, moet echter niet worden gedaan. Ik hoop oprecht dat je de serie nuttig vond en kijk uit naar nieuwe inzichten die je hebt verkregen door het gebruik van tools om prestatieproblemen met Access-applicaties te analyseren en aan te pakken met behulp van ODBC-gegevensbronnen. Voel je vrij om opmerkingen achter te laten of om meer informatie te vragen en bedankt voor het samen lezen!

Voor meer hulp bij alles wat met Microsoft Access te maken heeft, kunt u onze experts bellen op 773-809-5456 of een e-mail sturen naar [email protected].


  1. Query's met outer joins werken anders in Oracle 12c

  2. Een PostgreSQL-array toewijzen met Hibernate

  3. SELECT query retourneer 1 rij van elke groep

  4. 6 manieren om uw MariaDB-versie te controleren