sql >> Base de Datos >  >> RDS >> Access

¿Cómo se comunica Access con las fuentes de datos ODBC? parte 6

Efecto de las uniones en un conjunto de registros

En nuestro sexto y último artículo de la serie de seguimiento de ODBC, veremos cómo Access manejará las uniones en las consultas de Access. En el artículo anterior, vio cómo Access maneja los filtros. Dependiendo de la expresión, Access puede optar por parametrizarlo o puede verse obligado a evaluarlo por sí mismo descargando todos los datos de entrada y luego realizando las evaluaciones localmente. En este artículo, nos centraremos en las uniones. Cuando lo piensas, las uniones son en realidad un tipo especial de filtro. Por lo tanto, en teoría, Access debería ser lo más remoto posible, incluso con uniones. Por lo general, es posible que vea uniones escritas en el siguiente pseudo-SQL:

FROM a INNER JOIN b ON a.ID = b.ID
Sin embargo, puede considerarse equivalente a la siguiente sintaxis:

FROM a, b WHERE a.ID = b.ID
Eso ilustra que aunque podemos usar el JOIN..ON más legible y familiar , el acceso es gratuito para tratarlo como un WHERE lo cual es útil en situaciones en las que Access no puede realizar la consulta de forma remota. Pero aquí está el problema... ¿cuándo decide Access hacer remotas las uniones? Probemos una consulta de unión simple:

SELECT 
   c.CityID
  ,c.StateProvinceID
  ,c.CityName
  ,s.StateProvinceName
FROM Cities AS c 
INNER JOIN StateProvinces AS s 
  ON c.StateProvinceID = s.StateProvinceID;
Si rastreamos esa consulta, veremos el siguiente resultado:

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 decidió no realizar la unión de forma remota, a pesar de que la consulta de Access original es perfectamente capaz de ejecutarse en SQL Server. En su lugar, obtuvo los ID de cada tabla en un theta-join, luego configuró 2 cadenas separadas de consultas como si hubiéramos abierto 2 conjuntos de registros de tipo dynaset. Luego, las dos consultas preparadas diferentes reciben las claves para las tablas respectivas de la primera consulta. Como era de esperar, puede haber mucha charla en la red.

Si cambiamos la misma consulta de Access para que sea de tipo instantánea en lugar del tipo predeterminado de dynaset, obtenemos:

SQLExecDirect: 
SELECT 
   "c"."CityID"
  ,"c"."CityName"
  ,"c"."StateProvinceID"
  ,"s"."StateProvinceName"  
FROM "Application"."Cities" "c",
     "Application"."StateProvinces" "s" 
WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" )
Por lo tanto, Access hace las uniones remotas muy bien en el caso de una consulta de tipo instantánea. ¿Por qué Access no hizo eso con la consulta original de tipo dynaset? La pista está en la siguiente captura de pantalla donde intentamos editar ambos las columnas de las tablas en la siguiente captura de pantalla:

Dicha consulta permite actualizar ambas columnas. En realidad, eso no se puede expresar en SQL, pero dicha acción es legal para que la realice el usuario. Por lo tanto, para ejecutar esa actualización, Access enviaría el siguiente SQL ODBC:

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

SQLExecDirect: 
UPDATE "Application"."Cities" 
SET "CityName"=?  
WHERE "CityID" = ? 
  AND "CityName" = ? 
  AND "StateProvinceID" = ?
Eso no sería posible si Access no tuviera la información necesaria para actualizar cada tabla, lo que explica por qué Access eligió no realizar la unión de forma remota al resolver la consulta original de tipo dynaset. La lección aquí es que si no necesita que una consulta sea actualizable y los datos resultantes son lo suficientemente pequeños, podría ser mejor convertir la consulta en un tipo de instantánea. En el caso de que necesite formular un origen de registros complejo, normalmente obtendrá un rendimiento mucho mejor utilizando una vista SQL como base que haciendo las uniones en el lado de acceso.

Para probar esto, crearemos una vista SQL y la vincularemos a 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;
Luego ajustamos la consulta de Access de la siguiente manera:

SELECT 
   c.CityID
  ,c.StateProvinceID
  ,c.CityName
  ,c.StateProvinceName
FROM vwCitiesAndStates AS c;
Si luego repetimos la actualización que probamos originalmente, deberíamos ver el siguiente SQL ODBC 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" = ?
Esto demuestra que al usar vistas SQL para "remotar" las uniones, Access solo funcionará con una sola fuente, en lugar de con 2 tablas y la actualización remota en la vista completamente a SQL Server. Un efecto secundario es que esta actualización ahora fallará con el mensaje de error:

Eso no debería ser una sorpresa ya que estábamos haciendo una UPDATE en una sola fuente, mientras que en el ejemplo original, Access en realidad emitía secretamente dos separar UPDATE declaraciones en cada tabla individual. Con suerte, eso ayuda a demostrar que debe evitar hacer uniones en consultas de Access/recordsources/rowsources, especialmente cuando necesitan ser actualizables. Si no es así, use una instantánea cuando sea posible.

Una nota rápida sobre las uniones heterogéneas

Necesitamos comentar sobre las uniones entre dos tablas vinculadas que provienen de dos fuentes de datos ODBC diferentes. Tales uniones son "heterogéneas" porque Access debe manejar las uniones localmente ya que se supone que cada fuente de datos no se conoce entre sí. Independientemente de si especifica conjuntos de registros de tipo dynaset o de tipo instantánea, Access debe obtener el conjunto completo de claves de cada fuente de datos y resolver las uniones mediante el envío de consultas parametrizadas independientes a cada fuente de datos. Si se permite la actualización, Access formulará una UPDATE separada consulta a cada fuente de datos que necesita ser actualizada. También es importante tener en cuenta que Access aún considera heterogénea una unión entre dos tablas vinculadas que provienen de dos bases de datos diferentes. Eso sigue siendo cierto incluso si las dos bases de datos están en el mismo servidor y no tiene problemas para realizar consultas entre bases de datos. En este escenario, una vista de SQL puede ayudar a reducir la charla adicional al ocultar las uniones de bases de datos cruzadas de Access de manera similar a lo que ya vimos en este artículo.

Diferencia de sintaxis de combinación externa

Siempre que las uniones externas no afecten la capacidad de actualización de la consulta de Access, Access la manejará de manera similar a como manejó la versión de unión interna. Si modificamos la misma consulta que usamos para ser una combinación izquierda, el SQL ODBC rastreado generará la consulta de población clave de la siguiente manera:

SQLExecDirect: 
SELECT 
   "c"."CityID"
  ,"s"."StateProvinceID" 
FROM {oj 
	"Application"."Cities" "c" 
	LEFT OUTER JOIN "Application"."StateProvinces" "s" 
		ON ("c"."StateProvinceID" = "s"."StateProvinceID" ) 
}
La sintaxis se ve bastante diferente de lo que cabría esperar en otros dialectos de SQL. Esto se debe a que la gramática SQL de ODBC requiere que cualquier combinación externa esté envuelta en un {oj ...} expresión. Para obtener más detalles sobre esa sintaxis, consulte la documentación. Para nuestro propósito, podemos ignorar el {oj y el cierre } como ruido.

Conclusiones

Vimos que las uniones se tratan como si fueran una especie de filtro y Access intentará remotamente las uniones donde esté permitido. Un área particular a la que hay que prestar mucha atención es el hecho de que, de forma predeterminada, usamos conjuntos de registros de tipo dynaset y Access no supondrá si queremos permitir la modificación de tal o cual columna en el conjunto de registros y hace todo lo posible para que sea posible para nosotros. para actualizar a dos tablas que en realidad no se expresan fácilmente en SQL estándar. Como consecuencia, Access trabajará mucho más para admitir la capacidad de actualización de una consulta que contiene uniones que pueden afectar negativamente el rendimiento.

Podemos ayudar a evitar la penalización mediante el uso de vistas SQL en lugar de uniones expresadas en una consulta de Access. La compensación es que entonces estamos sujetos a las reglas de actualización de una vista SQL; es posible que no podamos actualizar dos tablas al mismo tiempo. Por lo general, debido a que un formulario de Access bien diseñado solo representará una sola tabla para actualizar, eso no es una gran restricción y es una buena disciplina a seguir.

Con eso, la serie actual está lista. Sin embargo, el aprendizaje que ojalá despierte la serie no debe hacerse. Espero sinceramente que haya encontrado útil la serie y espero escuchar los nuevos conocimientos que obtuvo al usar herramientas para ayudar a analizar y abordar los problemas de rendimiento con las aplicaciones de Access que usan fuentes de datos ODBC. ¡No dude en dejar comentarios o solicitar más información y gracias por leer juntos!

Para obtener más ayuda con cualquier cosa relacionada con Microsoft Access, llame a nuestros expertos al 773-809-5456 o envíenos un correo electrónico a [email protected].