sql >> Base de Datos >  >> RDS >> Database

SQL avanzado:APLICACIÓN CRUZADA y APLICACIÓN EXTERNA

En este artículo, veremos el operador "APLICAR" y sus variaciones:APLICACIÓN CRUZADA y APLICACIÓN EXTERNA junto con ejemplos de cómo se pueden usar.

En particular, aprenderemos:

  • la diferencia entre CROSS APPLY y la cláusula JOIN
  • cómo unir la salida de consultas SQL con funciones evaluadas en tablas
  • cómo identificar problemas de rendimiento consultando vistas de administración dinámica y funciones de administración dinámica.

Qué es la Cláusula APPLY

Microsoft introdujo el operador APPLY en SQL Server 2005. El operador APPLY es similar a la cláusula JOIN de T-SQL, ya que también le permite unir dos tablas; por ejemplo, puede unir una tabla externa con una interna. El operador APPLY es una buena opción cuando, por un lado, tenemos una expresión evaluada en una tabla que queremos evaluar para cada fila de la tabla que tenemos en el otro lado. Por lo tanto, la tabla del lado derecho se procesa para cada fila de la tabla del lado izquierdo. La tabla del lado izquierdo se evalúa primero y luego la tabla del lado derecho se evalúa contra cada fila de la tabla del lado izquierdo para generar el conjunto de resultados final. El conjunto de resultados final incluye todas las columnas de ambas tablas.

El operador APPLY tiene dos variaciones:

  • APLICACIÓN CRUZADA
  • APLICACIÓN EXTERIOR

APLICACIÓN CRUZADA

CROSS APPLY es similar a INNER JOIN, pero también se puede usar para unir funciones evaluadas por tablas con tablas SQL. El resultado final de CROSS APPLY consta de registros que coinciden entre el resultado de una función evaluada en una tabla y una tabla SQL.

APLICACIÓN EXTERIOR

OUTER APPLY se parece a LEFT JOIN, pero tiene la capacidad de unir funciones evaluadas por tablas con tablas SQL. La salida final de OUTER APPLY contiene todos los registros de la tabla del lado izquierdo o de la función con valores de tabla, incluso si no coinciden con los registros de la tabla del lado derecho o de la función con valores de tabla.

Ahora, déjame explicarte ambas variaciones con ejemplos.

Ejemplos de uso

Preparación de la configuración de demostración

Para preparar una configuración de demostración, deberá crear tablas denominadas "Empleados" y "Departamento" en una base de datos que llamaremos "DemoDatabase". Para hacer eso, ejecute el siguiente código:

USE DEMODATABASE 
GO 

CREATE TABLE [DBO].[EMPLOYEES] 
  ( 
     [EMPLOYEENAME] [VARCHAR](MAX) NULL, 
     [BIRTHDATE]    [DATETIME] NULL, 
     [JOBTITLE]     [VARCHAR](150) NULL, 
     [EMAILID]      [VARCHAR](100) NULL, 
     [PHONENUMBER]  [VARCHAR](20) NULL, 
     [HIREDATE]     [DATETIME] NULL, 
     [DEPARTMENTID] [INT] NULL 
  ) 

GO 

CREATE TABLE [DBO].[DEPARTMENT] 
  ( 
     [DEPARTMENTID]   INT IDENTITY (1, 1), 
     [DEPARTMENTNAME] [VARCHAR](MAX) NULL 
  ) 
GO

A continuación, inserte algunos datos ficticios en ambas tablas. El siguiente script insertará datos en el "Empleado s ” tabla:

[expandir título =”CONSULTA COMPLETA “]

INSERT [DBO].[EMPLOYEES] 
       ([EMPLOYEENAME], 
        [BIRTHDATE], 
        [JOBTITLE], 
        [EMAILID], 
        [PHONENUMBER], 
        [HIREDATE], 
        [DEPARTMENTID]) 
VALUES (N'KEN J SÁNCHEZ', 
        CAST(N'1969-01-29T00:00:00.000' AS DATETIME), 
        N'CHIEF EXECUTIVE OFFICER', 
        N'[email protected]', 
        N'697-555-0142', 
        CAST(N'2009-01-14T00:00:00.000' AS DATETIME), 
        1), 
       (N'TERRI LEE DUFFY', 
        CAST(N'1971-08-01T00:00:00.000' AS DATETIME), 
        N'VICE PRESIDENT OF ENGINEERING', 
        N'[email protected]', 
        N'819-555-0175', 
        CAST(N'2008-01-31T00:00:00.000' AS DATETIME), 
        NULL), 
       (N'ROBERTO  TAMBURELLO', 
        CAST(N'1974-11-12T00:00:00.000' AS DATETIME), 
        N'ENGINEERING MANAGER', 
        N'[email protected]', 
        N'212-555-0187', 
        CAST(N'2007-11-11T00:00:00.000' AS DATETIME), 
        NULL), 
       (N'ROB  WALTERS', 
        CAST(N'1974-12-23T00:00:00.000' AS DATETIME), 
        N'SENIOR TOOL DESIGNER', 
        N'[email protected]', 
        N'612-555-0100', 
        CAST(N'2007-12-05T00:00:00.000' AS DATETIME), 
        NULL), 
       (N'GAIL A ERICKSON', 
        CAST(N'1952-09-27T00:00:00.000' AS DATETIME), 
        N'DESIGN ENGINEER', 
        N'[email protected]', 
        N'849-555-0139', 
        CAST(N'2008-01-06T00:00:00.000' AS DATETIME), 
        NULL), 
       (N'JOSSEF H GOLDBERG', 
        CAST(N'1959-03-11T00:00:00.000' AS DATETIME), 
        N'DESIGN ENGINEER', 
        N'[email protected]', 
        N'122-555-0189', 
        CAST(N'2008-01-24T00:00:00.000' AS DATETIME), 
        NULL), 
       (N'DYLAN A MILLER', 
        CAST(N'1987-02-24T00:00:00.000' AS DATETIME), 
        N'RESEARCH AND DEVELOPMENT MANAGER', 
        N'[email protected]', 
        N'181-555-0156', 
        CAST(N'2009-02-08T00:00:00.000' AS DATETIME), 
        3), 
       (N'DIANE L MARGHEIM', 
        CAST(N'1986-06-05T00:00:00.000' AS DATETIME), 
        N'RESEARCH AND DEVELOPMENT ENGINEER', 
        N'[email protected]', 
        N'815-555-0138', 
        CAST(N'2008-12-29T00:00:00.000' AS DATETIME), 
        3), 
       (N'GIGI N MATTHEW', 
        CAST(N'1979-01-21T00:00:00.000' AS DATETIME), 
        N'RESEARCH AND DEVELOPMENT ENGINEER', 
        N'[email protected]', 
        N'185-555-0186', 
        CAST(N'2009-01-16T00:00:00.000' AS DATETIME), 
        3), 
       (N'MICHAEL  RAHEEM', 
        CAST(N'1984-11-30T00:00:00.000' AS DATETIME), 
        N'RESEARCH AND DEVELOPMENT MANAGER', 
        N'[email protected]', 
        N'330-555-2568', 
        CAST(N'2009-05-03T00:00:00.000' AS DATETIME), 
        3)

[/expandir]

Para añadir datos a nuestro “Departamento ”, ejecute el siguiente script:

INSERT [DBO].[DEPARTMENT] 
       ([DEPARTMENTID], 
        [DEPARTMENTNAME]) 
VALUES (1, 
        N'IT'), 
       (2, 
        N'TECHNICAL'), 
       (3, 
        N'RESEARCH AND DEVELOPMENT')

Ahora, para verificar los datos, ejecuta el código que puedes ver a continuación:

SELECT [EMPLOYEENAME], 
       [BIRTHDATE], 
       [JOBTITLE], 
       [EMAILID], 
       [PHONENUMBER], 
       [HIREDATE], 
       [DEPARTMENTID] 
FROM   [EMPLOYEES] 

GO

SELECT [DEPARTMENTID], 
       [DEPARTMENTNAME] 
FROM   [DEPARTMENT] 
GO

Aquí está el resultado deseado:

Crear y probar una función evaluada en tablas

Como ya mencioné, “APLICACIÓN CRUZADA ” y “APLICACIÓN EXTERNA ” se utilizan para unir tablas SQL con funciones evaluadas por tablas. Para demostrarlo, creemos una función evaluada en una tabla llamada “getEmployeeData .” Esta función utilizará un valor de DepartmentID columna como parámetro de entrada y devolver todos los empleados del departamento correspondiente.

Para crear la función, ejecute el siguiente script:

CREATE FUNCTION Getemployeesbydepartment (@DEPARTMENTID INT) 
RETURNS @EMPLOYEES TABLE ( 
  EMPLOYEENAME   VARCHAR (MAX), 
  BIRTHDATE      DATETIME, 
  JOBTITLE       VARCHAR(150), 
  EMAILID        VARCHAR(100), 
  PHONENUMBER    VARCHAR(20), 
  HIREDATE       DATETIME, 
  DEPARTMENTID VARCHAR(500)) 
AS 
  BEGIN 
      INSERT INTO @EMPLOYEES 
      SELECT A.EMPLOYEENAME, 
             A.BIRTHDATE, 
             A.JOBTITLE, 
             A.EMAILID, 
             A.PHONENUMBER, 
             A.HIREDATE, 
             A.DEPARTMENTID 
      FROM   [EMPLOYEES] A 
      WHERE  A.DEPARTMENTID = @DEPARTMENTID 

      RETURN 
  END

Ahora, para probar la función, pasaremos “1 ” como “ID de departamento ” al “Obtener empleados por departamento " función. Para ello, ejecute el script proporcionado a continuación:

USE DEMODATABASE
GO
SELECT EMPLOYEENAME,
       BIRTHDATE,
       JOBTITLE,
       EMAILID,
       PHONENUMBER,
       HIREDATE,
       DEPARTMENTID
FROM   GETEMPLOYEESBYDEPARTMENT (1)

La salida debe ser la siguiente:

Unirse a una tabla con una función evaluada por tabla usando CROSS APPLY

Ahora, intentemos unir la tabla Empleados con el "Obtener empleados por departamento ” función evaluada por tabla usando CROSS APPLY . Como mencioné, el APLICACIÓN CRUZADA El operador es similar a la cláusula Join. Rellenará todos los registros del "Empleado ” tabla para la que hay filas coincidentes en la salida de “Getemployeesbydepartment ”.

Ejecute el siguiente script:

SELECT A.[EMPLOYEENAME], 
       A.[BIRTHDATE], 
       A.[JOBTITLE], 
       A.[EMAILID], 
       A.[PHONENUMBER], 
       A.[HIREDATE], 
       B.[DEPARTMENTNAME] 
FROM   DEPARTMENT B 
       CROSS APPLY GETEMPLOYEESBYDEPARTMENT(B.DEPARTMENTID) A

La salida debe ser la siguiente:

Unir una tabla con una función evaluada por tabla usando OUTER APPLY

Ahora, intentemos unir la tabla Empleados con el "Obtener empleados por departamento ” función evaluada por tabla usando APLICACIÓN EXTERNA . Como mencioné antes, la APLICACIÓN EXTERNA El operador se asemeja a la “UNIÓN EXTERNA ” cláusula. Rellena todos los registros del "Empleado ” y la salida de la tabla “Getemployeesbydepartment ” función.

Ejecute el siguiente script:

SELECT A.[EMPLOYEENAME], 
       A.[BIRTHDATE], 
       A.[JOBTITLE], 
       A.[EMAILID], 
       A.[PHONENUMBER], 
       A.[HIREDATE], 
       B.[DEPARTMENTNAME] 
FROM   DEPARTMENT B 
       OUTER APPLY GETEMPLOYEESBYDEPARTMENT(B.DEPARTMENTID) A

Este es el resultado que debería ver como resultado:

Identificación de problemas de rendimiento mediante el uso de vistas y funciones de administración dinámica

Déjame mostrarte un ejemplo diferente. Aquí, veremos cómo obtener un plan de consulta y el texto de consulta correspondiente mediante el uso de funciones de administración dinámica y vistas de administración dinámica.

Para fines de demostración, he creado una tabla llamada "SmokeTestResults ” en la “Base de datos de demostración”. Contiene los resultados de una prueba de humo de aplicación. Imaginemos que, por error, un desarrollador ejecuta una consulta SQL para completar los datos de "SmokeTestResults ” sin agregar un filtro, lo que reduce significativamente el rendimiento de la base de datos.

Como DBA, necesitamos identificar la consulta con muchos recursos. Para ello, utilizaremos el “sys.dm_exec_requests ” y la vista “sys.dm_exec_sql_text ” función.

Sys.dm_exec_requests ” es una vista de administración dinámica que proporciona los siguientes detalles importantes que podemos usar para identificar la consulta que consume recursos:

  1. ID de sesión
  2. Tiempo de CPU
  3. Tipo de espera
  4. ID de la base de datos
  5. Lecturas (físicas)
  6. Escribe (físico)
  7. Lecturas lógicas
  8. Manejador SQL
  9. Manejador del plan
  10. Estado de la consulta
  11. Comando
  12. ID de transacción

sys.dm_exec_sql_text ” es una función de gestión dinámica que acepta un controlador SQL como parámetro de entrada y proporciona los siguientes detalles:

  1. ID de la base de datos
  2. ID de objeto
  3. Está encriptado
  4. Texto de consulta SQL

Ahora, ejecutemos la siguiente consulta para generar algo de estrés en la base de datos ASAP. Ejecute la siguiente consulta:

USE ASAP 
GO 

SELECT TSID, 
       USERID, 
       EXECUTIONID, 
       EX_RESULTFILE, 
       EX_TESTDATAFILE, 
       EX_ZIPFILE, 
       EX_STARTTIME, 
       EX_ENDTIME, 
       EX_REMARKS 
FROM  [ASAP].[DBO].[SMOKETESTRESULTS]

SQL Server asigna un ID de sesión "66" e inicia la ejecución de la consulta. Ver la siguiente imagen:

Ahora, para solucionar el problema, necesitamos el ID de la base de datos, Lecturas lógicas, SQL Consulta, Comando, ID de sesión, Tipo de espera y identificador SQL . Como mencioné, podemos obtener ID de base de datos, lecturas lógicas, comando, ID de sesión, tipo de espera y identificador SQL de "sys.dm_exec_requests". Para obtener la Consulta SQL , debemos usar “sys.dm_exec_sql_text. ” Es una función de administración dinámica, por lo que deberá unirse a “sys.dm_exec_requests ” con “sys.dm_exec_sql_text ” usando APLICACIÓN CRUZADA.

En la ventana Nuevo editor de consultas, ejecute la siguiente consulta:

SELECT B.TEXT, 
       A.WAIT_TYPE, 
       A.LAST_WAIT_TYPE, 
       A.COMMAND, 
       A.SESSION_ID, 
       CPU_TIME, 
       A.BLOCKING_SESSION_ID, 
       A.LOGICAL_READS 
FROM   SYS.DM_EXEC_REQUESTS A 
       CROSS APPLY SYS.DM_EXEC_SQL_TEXT(A.SQL_HANDLE) B

Debería producir el siguiente resultado:

Como puede ver en la captura de pantalla anterior, la consulta devolvió toda la información necesaria para identificar el problema de rendimiento.

Ahora, además del texto de la consulta, queremos obtener el plan de ejecución que se utilizó para ejecutar la consulta en cuestión. Para hacer esto, usaremos el “sys.dm_exec_query_plan” función.

sys.dm_exec_query_plan ” es una función de gestión dinámica que acepta un manejador de plan como parámetro de entrada y proporciona los siguientes detalles:

  1. ID de la base de datos
  2. ID de objeto
  3. Está encriptado
  4. Plan de consultas SQL en formato XML

Para completar el plan de ejecución de consultas, debemos usar CROSS APPLY para unir "sys.dm_exec_requests ” y “sys.dm_exec_query_plan.

Abra la ventana del editor New Query y ejecute la siguiente consulta:

SELECT B.TEXT, 
       A.WAIT_TYPE, 
       A.LAST_WAIT_TYPE, 
       A.COMMAND, 
       A.SESSION_ID, 
       CPU_TIME, 
       A.BLOCKING_SESSION_ID, 
       A.LOGICAL_READS, 
       C.QUERY_PLAN 
FROM   SYS.DM_EXEC_REQUESTS A 
       CROSS APPLY SYS.DM_EXEC_SQL_TEXT(A.SQL_HANDLE) B 
       CROSS APPLY SYS.DM_EXEC_QUERY_PLAN (A.PLAN_HANDLE) C

La salida debe ser la siguiente:

Ahora, como puede ver, el plan de consulta se genera en formato XML por defecto. Para abrirlo como una representación gráfica, haga clic en la salida XML en el query_plan columna como se muestra en la imagen de arriba. Una vez que haga clic en la salida XML, el plan de ejecución se abrirá en una nueva ventana como se muestra en la siguiente imagen:

Obtener una lista de tablas con índices muy fragmentados mediante funciones y vistas de administración dinámica

Veamos un ejemplo más. Quiero obtener una lista de tablas con índices que tengan un 50 % o más de fragmentación en una base de datos determinada. Para recuperar estas tablas, necesitaremos usar el "sys.dm_db_index_physical_stats ” y la vista “sys.tables ” función.

Tablas del sistema ” es una vista de administración dinámica que completa una lista de tablas en la base de datos específica.

sys.dm_db_index_physical_stats ” es una función de gestión dinámica que acepta los siguientes parámetros de entrada:

  1. ID de la base de datos
  2. ID de objeto
  3. ID de índice
  4. Número de partición
  5. Modo

Devuelve información detallada sobre el estado físico del índice especificado.

Ahora, para completar la lista de índices fragmentados, debemos unirnos a “sys.dm_db_index_physical_stats ” y “sys.tablas ” usando APLICACIÓN CRUZADA. Ejecute la siguiente consulta:

SELECT TABLES.NAME, 
       INDEXSTATISTICS.ALLOC_UNIT_TYPE_DESC, 
       CONVERT(NUMERIC(10, 2), INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT) AS 
       PERCENTAGEFRAGMENTATION, 
       INDEXSTATISTICS.PAGE_COUNT 
FROM   SYS.TABLES AS TABLES 
       CROSS APPLY SYS.DM_DB_INDEX_PHYSICAL_STATS (DB_ID(), TABLES.OBJECT_ID, 
                   NULL, 
                   NULL, NULL) AS 
                                               INDEXSTATISTICS 
WHERE  INDEXSTATISTICS.DATABASE_ID = DB_ID() 
       AND AVG_FRAGMENTATION_IN_PERCENT >= 50 
ORDER  BY INDEXSTATISTICS.AVG_FRAGMENTATION_IN_PERCENT DESC

La consulta debe producir el siguiente resultado:

Resumen

En este artículo, cubrimos el operador APLICAR, sus variaciones:APLICACIÓN CRUZADA y APLICACIÓN EXTERNA y cómo funcionan. También hemos visto cómo puede usarlos para identificar problemas de rendimiento de SQL utilizando vistas de administración dinámica y funciones de administración dinámica.