Access
 sql >> Base de Dados >  >> RDS >> Access

Como o Access se comunica com fontes de dados ODBC? Parte 6

Efeito de junções em um conjunto de registros


Em nosso sexto e último artigo da série de rastreamento ODBC, vamos dar uma olhada em como o Access lidará com junções em consultas do Access. No artigo anterior, você viu como os filtros são tratados pelo Access. Dependendo da expressão, o Access pode optar por parametrizá-la fora ou pode ser forçado a avaliá-la por si mesmo baixando todos os dados de entrada e realizando as avaliações localmente. Neste artigo, vamos nos concentrar em junções. Quando você pensa sobre isso, as junções são na verdade um tipo especial de filtro. Portanto, em teoria, o Access deve ser remoto o máximo possível, mesmo com junções. Normalmente, você pode ver junções escritas no seguinte pseudo-SQL:
FROM a INNER JOIN b ON a.ID = b.ID
No entanto, pode ser considerado equivalente à seguinte sintaxe:
FROM a, b WHERE a.ID = b.ID
Isso ilustra que, embora possamos usar o JOIN..ON mais legível e familiar , o Access é livre para tratá-lo como um WHERE o que é útil em situações em que o Access não pode controlar totalmente a consulta. Mas aqui está o problema… quando o Access decide remotamente as junções? Vamos tentar uma consulta de junção simples:
SELECT 
   c.CityID
  ,c.StateProvinceID
  ,c.CityName
  ,s.StateProvinceName
FROM Cities AS c 
INNER JOIN StateProvinces AS s 
  ON c.StateProvinceID = s.StateProvinceID;
Se rastrearmos essa consulta, veremos a seguinte saída:
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)
O Access decidiu não fazer a junção remota, embora a consulta original do Access seja perfeitamente capaz de ser executada no SQL Server. Em vez disso, ele obteve os IDs de cada tabela em uma junção theta e, em seguida, configurou 2 cadeias de consultas separadas como se tivéssemos aberto 2 conjuntos de registros do tipo dynaset. As duas consultas preparadas diferentes são então alimentadas com as chaves das respectivas tabelas da primeira consulta. Previsivelmente, pode ser muita conversa para passar pela rede.

Se alterarmos a mesma consulta do Access para um tipo de instantâneo em vez do tipo de dynaset padrão, obteremos:
SQLExecDirect: 
SELECT 
   "c"."CityID"
  ,"c"."CityName"
  ,"c"."StateProvinceID"
  ,"s"."StateProvinceName"  
FROM "Application"."Cities" "c",
     "Application"."StateProvinces" "s" 
WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" )
Portanto, o Access faz as junções remotas muito bem no caso de consulta do tipo instantâneo. Por que o Access não fez isso com a consulta original do tipo dynaset? A pista está na captura de tela a seguir, onde tentamos editar ambos colunas das tabelas na captura de tela a seguir:



Essa consulta permite a atualização para ambas as colunas. Isso não é realmente exprimível no SQL, mas essa ação é legal para o usuário executar. Portanto, para executar essa atualização, o Access enviaria o seguinte ODBC SQL:
SQLExecDirect: 
UPDATE "Application"."StateProvinces" 
SET "StateProvinceName"=?  
WHERE "StateProvinceID" = ? 
  AND "StateProvinceName" = ?

SQLExecDirect: 
UPDATE "Application"."Cities" 
SET "CityName"=?  
WHERE "CityID" = ? 
  AND "CityName" = ? 
  AND "StateProvinceID" = ?
Isso não seria possível se o Access não tivesse as informações necessárias para atualizar cada tabela, o que explica por que o Access optou por não remoto a junção ao resolver a consulta do tipo dynaset original. A lição aqui é que, se você não precisar que uma consulta seja atualizável e os dados resultantes forem pequenos o suficiente, talvez seja melhor converter a consulta em um tipo de instantâneo. No caso de você precisar formular uma fonte de registro complexa, geralmente obterá um desempenho muito melhor usando uma exibição SQL como base do que fazendo as junções no lado do Access.

Para provar isso, vamos criar uma view SQL e vinculá-la ao 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;
Em seguida, ajustamos a consulta do Access da seguinte maneira:
SELECT 
   c.CityID
  ,c.StateProvinceID
  ,c.CityName
  ,c.StateProvinceName
FROM vwCitiesAndStates AS c;
Se repetirmos a atualização que tentamos originalmente, devemos ver o seguinte ODBC SQL rastreado:
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" = ?
Isso demonstra que usando visualizações SQL para “remota” as junções, o Access funcionará apenas com uma única fonte, em vez de com 2 tabelas e remoto a atualização na visualização totalmente para SQL Server. Um efeito colateral é que esta atualização agora falhará com a mensagem de erro:

Isso não deveria ser uma surpresa, pois estávamos fazendo um UPDATE em uma única fonte, enquanto no exemplo original, o Access estava secretamente emitindo dois separar UPDATE declarações em cada tabela individual. Espero que isso ajude a evitar fazer junções em consultas/recordsources/rowsources do Access, especialmente quando eles precisam ser atualizáveis. Se não o fizerem, use o instantâneo sempre que possível.

Uma nota rápida sobre junções heterogêneas


Precisamos comentar sobre as junções entre duas tabelas vinculadas que vêm de duas fontes de dados ODBC diferentes. Essas junções são “heterogêneas” porque o Access deve lidar com as junções localmente, pois supõe-se que cada fonte de dados não se conhece. Independentemente de você especificar um conjunto de registros do tipo dynaset ou instantâneo, o Access deve buscar o conjunto completo de chaves de cada fonte de dados e resolver as junções enviando consultas parametrizadas separadas para cada fonte de dados. Se a atualização for permitida, o Access formulará um UPDATE separado consulta para cada fonte de dados que precisa ser atualizada. Também é importante observar que uma junção entre duas tabelas vinculadas provenientes de dois bancos de dados diferentes ainda é considerada pelo Access como heterogênea. Isso ainda é verdade mesmo se os dois bancos de dados estiverem no mesmo servidor e você não tiver problemas em fazer consultas entre bancos de dados. Nesse cenário, uma exibição SQL pode ajudar a reduzir a conversa adicional ocultando as junções de banco de dados cruzadas do Access semelhante ao que já vimos neste artigo.

Diferença de sintaxe de junção externa


Contanto que as associações externas não afetem a capacidade de atualização da consulta do Access, o Access a tratará da mesma forma que lidou com a versão da associação interna. Se modificarmos a mesma consulta que costumávamos ser uma junção esquerda, o SQL ODBC rastreado produzirá a consulta de preenchimento de chaves da seguinte forma:
SQLExecDirect: 
SELECT 
   "c"."CityID"
  ,"s"."StateProvinceID" 
FROM {oj 
	"Application"."Cities" "c" 
	LEFT OUTER JOIN "Application"."StateProvinces" "s" 
		ON ("c"."StateProvinceID" = "s"."StateProvinceID" ) 
}
A sintaxe parece bem diferente do que você pode esperar em outros dialetos SQL. Isso ocorre porque a gramática ODBC SQL exige que qualquer junção externa seja encapsulada em um {oj ...} expressão. Para obter mais detalhes sobre essa sintaxe, consulte a documentação. Para nosso propósito, podemos simplesmente desconsiderar o {oj e o } de fechamento como ruído.

Conclusões


Vimos que as junções são tratadas como se fossem uma espécie de filtro e o Access tentará remotamente as junções onde for permitido. Uma área específica para prestar muita atenção é o fato de que, por padrão, usamos conjuntos de registros do tipo dynaset e o Access não fará suposições sobre se queremos permitir a modificação de colunas fulanas no conjunto de registros e se esforça para tornar isso possível para nós para atualizar para duas tabelas que na verdade não são facilmente expressas no SQL padrão. Como consequência, o Access fará muito mais trabalho para oferecer suporte à capacidade de atualização de uma consulta que contém junções que podem afetar negativamente o desempenho.

Podemos ajudar a evitar a penalidade usando visualizações SQL no lugar de junções expressas em uma consulta do Access. A desvantagem é que estamos sujeitos às regras de atualização de uma visão SQL; podemos não ter permissão para atualizar duas tabelas ao mesmo tempo. Normalmente, porque um formulário de acesso bem projetado representará apenas uma única tabela a ser atualizada, isso não é uma restrição e é uma boa disciplina a ser seguida.

Com isso, a série atual está feita. No entanto, o aprendizado que a série esperançosamente desperta não deve ser feito. Espero sinceramente que você tenha achado a série útil e ansioso para ouvir sobre os novos insights que você obteve ao usar ferramentas para ajudar a analisar e resolver problemas de desempenho com aplicativos do Access usando fontes de dados ODBC. Sinta-se à vontade para deixar comentários ou solicitar mais informações e obrigado por lerem juntos!

Para obter mais assistência com qualquer coisa relacionada ao Microsoft Access, ligue para nossos especialistas em 773-809-5456 ou envie um email para [email protected].