Effetto dei join in un recordset
Nel nostro sesto e ultimo articolo della serie di analisi ODBC, daremo un'occhiata a come Access gestirà i join nelle query di Access. Nell'articolo precedente, hai visto come vengono gestiti i filtri da Access. A seconda dell'espressione, Access può scegliere di parametrizzarla o essere costretto a valutarla autonomamente scaricando tutti i dati di input e quindi eseguendo le valutazioni in locale. In questo articolo ci concentreremo sui join. Quando ci pensi, i join sono in realtà un tipo speciale di filtro. Pertanto, in teoria, Access dovrebbe essere il più remoto possibile anche con i join. In genere potresti vedere i join scritti nel seguente pseudo-SQL:
FROM a INNER JOIN b ON a.ID = b.IDTuttavia, può essere considerato equivalente alla seguente sintassi:
FROM a, b WHERE a.ID = b.IDCiò dimostra che anche se possiamo usare il più leggibile e familiare
JOIN..ON
, Access è libero di trattarlo come un WHERE
che è utile nelle situazioni in cui Access non può eseguire completamente la query in remoto. Ma ecco il problema... quando Access decide di remotare i join? Proviamo una semplice query di unione: SELECT c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceName FROM Cities AS c INNER JOIN StateProvinces AS s ON c.StateProvinceID = s.StateProvinceID;Se tracciamo quella query, vedremo il seguente output:
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 ha deciso di non eseguire il join in remoto, anche se la query di Access originale è perfettamente in grado di essere eseguita su SQL Server. Invece, ha ottenuto gli ID da ogni tabella in un theta-join, quindi ha impostato 2 catene separate di query come se avessimo aperto 2 recordset di tipo dynaset. Le due diverse query preparate vengono quindi alimentate con le chiavi per le rispettive tabelle dalla prima query. Com'era prevedibile, possono essere molte chiacchiere da passare sulla rete.
Se modifichiamo la stessa query di Access in modo che sia un tipo snapshot anziché il tipo dynaset predefinito, otteniamo:
SQLExecDirect: SELECT "c"."CityID" ,"c"."CityName" ,"c"."StateProvinceID" ,"s"."StateProvinceName" FROM "Application"."Cities" "c", "Application"."StateProvinces" "s" WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" )Quindi Access esegue in remoto i join correttamente nel caso di query di tipo snapshot. Perché Access non lo ha fatto con la query di tipo dynaset originale? L'indizio è nello screenshot seguente in cui tentiamo di modificare entrambi colonne delle tabelle nello screenshot seguente:
Tale query consente l'aggiornamento a entrambe le colonne. Ciò non è effettivamente esprimibile in SQL, ma tale azione è legale da eseguire per l'utente. Pertanto, per eseguire tale aggiornamento, Access invierà il seguente SQL ODBC:
SQLExecDirect: UPDATE "Application"."StateProvinces" SET "StateProvinceName"=? WHERE "StateProvinceID" = ? AND "StateProvinceName" = ? SQLExecDirect: UPDATE "Application"."Cities" SET "CityName"=? WHERE "CityID" = ? AND "CityName" = ? AND "StateProvinceID" = ?Ciò non sarebbe possibile se Access non disponesse delle informazioni necessarie per aggiornare ciascuna tabella, il che spiega perché Access ha scelto di non eseguire il join in remoto durante la risoluzione della query di tipo dynaset originale. La lezione qui è che se non è necessario che una query sia aggiornabile e i dati risultanti sono sufficientemente piccoli, potrebbe essere meglio convertire la query in un tipo di snapshot. Nel caso in cui sia necessario formulare un'origine record complessa, di solito otterrai prestazioni molto migliori utilizzando una vista SQL come base rispetto ai join sul lato Access.
Per dimostrarlo, creeremo una vista SQL e la collegheremo ad 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;Quindi modifichiamo la query di accesso come segue:
SELECT c.CityID ,c.StateProvinceID ,c.CityName ,c.StateProvinceName FROM vwCitiesAndStates AS c;Se poi ripetiamo l'aggiornamento che abbiamo provato in origine, dovremmo vedere il seguente SQL ODBC tracciato:
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" = ?Ciò dimostra che, utilizzando le viste SQL per "remotare" i join, Access funzionerà solo con una singola origine, anziché con 2 tabelle e in remoto l'aggiornamento della vista completamente in SQL Server. Un effetto collaterale è che questo aggiornamento ora fallirà con il messaggio di errore:
Non dovrebbe sorprendere dato che stavamo facendo un UPDATE
su un'unica fonte mentre nell'esempio originale Access ne emetteva segretamente due separato UPDATE
dichiarazioni su ogni singola tabella. Si spera che ciò aiuti a sostenere che dovresti evitare di fare join in Access query/recordsources/rowsources, specialmente quando devono essere aggiornabili. In caso contrario, utilizza snapshot ove possibile.
Una breve nota sui join eterogenei
È necessario commentare i join tra due tabelle collegate provenienti da due diverse origini dati ODBC. Tali join sono "eterogenei" perché Access deve gestire i join localmente poiché si presume che ciascuna origine dati non si conosca. Indipendentemente dal fatto che si specifichi un recordset di tipo dynaset o snapshot, Access deve recuperare il set completo di chiavi da ogni origine dati e risolvere i join inviando query con parametri separate a ciascuna origine dati. Se l'aggiornamento è consentito, Access formulerà un UPDATE
separato interrogare ogni origine dati che deve essere aggiornata. È anche importante notare che un join tra due tabelle collegate che proviene da due database diversi è ancora considerato da Access come eterogeneo. Ciò è ancora vero anche se i due database si trovano sullo stesso server e non hai problemi a eseguire query tra database. In questo scenario, una vista SQL può aiutare a ridurre le chiacchiere aggiuntive nascondendo i join incrociati del database da Access in modo simile a quello che abbiamo già visto in questo articolo.
Differenza della sintassi del join esterno
Finché i join esterni non influiscono sull'aggiornabilità della query di Access, Access la gestirà in modo simile a come ha gestito la versione di inner join. Se modifichiamo la stessa query che usavamo per essere un join sinistro, l'SQL ODBC tracciato genererà la query di popolazione chiave in questo modo:
SQLExecDirect: SELECT "c"."CityID" ,"s"."StateProvinceID" FROM {oj "Application"."Cities" "c" LEFT OUTER JOIN "Application"."StateProvinces" "s" ON ("c"."StateProvinceID" = "s"."StateProvinceID" ) }La sintassi è molto diversa da quella che ci si potrebbe aspettare in altri dialetti SQL. Questo perché la grammatica SQL ODBC richiede che tutti i join esterni siano racchiusi in un
{oj ...}
espressione. Per maggiori dettagli su tale sintassi, consultare la documentazione. Per il nostro scopo, possiamo semplicemente ignorare il {oj
e il }
di chiusura come rumore. Conclusioni
Abbiamo visto che i join vengono trattati come se fossero una sorta di filtro e Access tenterà di remotare i join dove è consentito. Un'area particolare a cui prestare molta attenzione è il fatto che per impostazione predefinita utilizziamo recordset di tipo dynaset e Access non farà ipotesi sul fatto che vogliamo consentire la modifica delle colonne così e così nel recordset e fa di tutto per renderlo possibile per noi per aggiornare a due tabelle che in realtà non è facilmente esprimibile in SQL standard. Di conseguenza, Access farà molto più lavoro per supportare l'aggiornamento per una query che contiene join che possono influire negativamente sulle prestazioni.
Possiamo aiutare a evitare la penalità utilizzando le viste SQL al posto dei join espressi in una query di Access. Il compromesso è che siamo quindi soggetti alle regole di aggiornabilità di una vista SQL; potremmo non essere autorizzati ad aggiornare due tabelle contemporaneamente. Di solito, poiché un modulo di accesso ben progettato rappresenterà solo una singola tabella da aggiornare, non è una grande restrizione ed è una buona disciplina da seguire.
Con questo, la serie attuale è finita. Tuttavia, l'apprendimento che si spera scatenerà la serie non dovrebbe essere fatto. Spero sinceramente che tu abbia trovato utile la serie e non vedo l'ora di conoscere le nuove informazioni acquisite dall'utilizzo di strumenti per analizzare e risolvere i problemi di prestazioni con le applicazioni di Access che utilizzano origini dati ODBC. Sentiti libero di lasciare commenti o richiedere maggiori informazioni e grazie per aver letto insieme!
Per ulteriore assistenza con qualsiasi cosa relativa a Microsoft Access, chiama i nostri esperti al numero 773-809-5456 o inviaci un'e-mail a [email protected].