Aceleración de SQL

Cómo ajustar las llamadas de base de datos con Generación de perfiles de interacción de niveles

Mark Friedman

Muchas aplicaciones están diseñadas explícitamente para usar varios niveles, en los cuales el rendimiento de las llamadas dentro del nivel de acceso a datos es crucial para la capacidad de respuesta general de la aplicación. El uso de varios niveles aumenta la flexibilidad de la aplicación. El enfoque de N niveles también fomenta el aislamiento de componentes clave, lo que se puede usar para mejorar la confiabilidad y la escalabilidad. El uso de varios niveles promueve la escalabilidad, puesto que los componentes que se aíslan en distintos niveles pueden distribuirse más fácilmente entre los recursos informáticos disponibles.

La Generación de perfiles de interacción de niveles (TIP) está diseñada para ayudarle a comprender el rendimiento del nivel de datos en que reside la aplicación. TIP es una característica nueva de las herramientas para generación de perfiles de Visual Studio que mide e informa la duración de los retrasos en el nivel de datos que experimentan las aplicaciones de .NET Framework cuando se espera que se completen las llamadas sincrónicas a las bases de datos compatibles con ADO.NET. En el caso de las aplicaciones orientadas al tiempo de respuesta que realizan llamadas frecuentes a las bases de datos, TIP le ayuda a comprender cuáles son las solicitudes de datos que contribuyen más a los retrasos de la respuesta.

En este artículo, les presentaré TIP y demostraré sus capacidades de generación de informes. También analizaré la tecnología de instrumentación en la que se basa TIP y proporcionaré algunos procedimientos recomendados para usar TIP de manera eficaz para diagnosticar problemas de rendimiento relacionados con la actividad de la base de datos. Examinaremos el uso de TIP en una aplicación web de muestra de ASP.NET de dos niveles que contiene gran cantidad de datos y que obtiene acceso a datos desde Microsoft SQL Server mediante el uso de la tecnología LINQ to SQL. Finalmente, analizaré cómo se pueden aumentar los datos de rendimiento de TIP mediante el uso de herramientas estándar para el rendimiento del administrador de SQL para entender aún con mayor profundidad el rendimiento de un nivel de datos.

Introducción a TIP

TIP agrega dinámicamente código de instrumentación para medir la duración de las llamadas al nivel de datos de la aplicación durante la ejecución de una generación de perfiles. Las herramientas de generación de perfiles de Visual Studio están disponibles en Visual Studio 2010 Premium Edition y en Visual Studio 2010 Ultimate Edition.

Para comenzar una sesión de generación de perfiles, puede hacer clic en Iniciar Asistente de rendimiento en el menú Analizar, en Iniciar análisis de rendimiento del menú Depurar o usar el acceso directo del teclado Alt+F2. La primera página del Asistente de rendimiento le pide seleccionar un método para la generación de perfiles.

Es posible usar TIP con cualquier método de generación de perfiles (muestreo, instrumentación, memoria o simultaneidad), pero no está habilitada de manera predeterminada. Para habilitar TIP, deberá desmarcar la casilla de verificación "Iniciar generación de perfiles al terminar el asistente” en la página 3 del Asistente de rendimiento. (Como TIP todavía no está activada, todavía no se está listo para iniciar la aplicación y comenzar la generación de archivos). Para obtener mejores resultados, recomiendo seleccionar inicialmente el método de muestreo de generación de perfiles, en especial si lo que más le preocupa son los datos de interacción de nivel de datos. Esto se debe principalmente a que el muestreo tiene menos impacto en el rendimiento de la aplicación.

Para habilitar la recopilación de datos de TIP, obtenga acceso a la sesión de rendimiento del Asistente de rendimiento recién creada en la ventana Explorador de rendimiento y haga clic con el botón secundario para ver sus propiedades. En el cuadro de diálogo de propiedades, seleccione la ficha Interacciones de nivel y luego marque la casilla de verificación “Habilitar generación de perfiles de interacción de nivel”. Haga clic en el botón Aceptar para descartar el cuadro de diálogo. Ahora que TIP está habilitado, se está listo para comenzar a generar perfiles de la aplicación.

Para comenzar con la ejecución real de generación de perfiles, haga clic en el botón de la barra de herramientas Inicio con generación de perfiles en la ventana Explorador de rendimiento.

Para obtener las instrucciones completas sobre la activación de TIP en Visual Studio, vea la publicación del blog de Habib Heydarian “Tutorial: Uso del generador de perfiles de interacción de nivel en Visual Studio Team System 2010” en el sitio web https://blogs.msdn.com/b/habibh/archive/2009/06/30/walkthrough-using-the-tier-interaction-profiler-in-visual-studio-team-system-2010.aspx.

Cómo TIP mide el rendimiento

TIP inserta código en la aplicación durante la ejecución de una generación de perfiles que mide las llamadas al nivel de datos de ADO.NET que usa su aplicación. Cuando la generación de perfiles de interacción de nivel está activa, el generador de perfiles de Visual Studio inspecciona el Lenguaje Intermedio de Microsoft (MSIL) en su solución y busca referencias a funciones de ADO.NET. Antes de llamar al compilador JIT para generar el código nativo que ejecuta la aplicación, el generador de perfiles inserta instrucciones que agregan instrumentación a métodos clave de ADO.NET. Este código de instrumentación realiza seguimiento del tiempo que se usa durante cada llamada de ADO.NET.

Cuando la aplicación se ejecuta, TIP captura y registra datos de tiempo. Cuando se generan perfiles de la aplicación, esta instrumentación registra la duración de cualquier llamada de ADO.NET que se realiza y también captura una copia del texto de comando que se usa en la llamada de la base de datos. A medida que se ejecuta la aplicación, se recopilan datos de tiempo para todos los accesos a bases de datos realizados mediante el uso de métodos sincrónicos de las clases de ADO.NET, incluidas API de SQL, OLE DB, de Conectividad abierta de bases de datos (ODBC) y de SQL Server Compact (SQL CE). TIP también captura datos de tiempo si la aplicación usa LINQ to SQL o las API de Entity Framework para obtener acceso a bases de datos de SQL.

Los datos de tiempo se almacenan junto con cualquier otro dato recopilado durante la sesión de generación de perfiles en un archivo de generador de perfiles de Visual Studio (.vsp). Como una aplicación que hace una llamada a una base de datos externa realiza una llamada fuera de proceso, las instrucciones que TIP agrega para instrumentar la aplicación tienen muy poco impacto en el rendimiento de aplicación global.

Ajuste de rendimiento

Un patrón de diseño común implica dividir una aplicación web en un nivel de presentación, un nivel de lógica de negocios y un nivel de datos. El paradigma de diseño lleva a dividir la aplicación en partes componentes para fomentar la confiabilidad, la extensibilidad y la escalabilidad. La aplicación de varios niveles obtiene acceso a su nivel de datos mediante el uso de componentes de lógica de negocios que hacen referencia a entidades de datos de manera lógica, como filas y columnas en un conjunto de tablas relacionado. La manera en que una base de datos, como SQL Server, mantiene los datos físicos asociados con las tablas de base de datos es transparente con su aplicación por el diseño.

Para la confiabilidad y la escalabilidad, las aplicaciones web a gran escala a menudo configuran varias máquinas en grupos que son responsables de la lógica de procesamiento asociada con cada nivel de la aplicación. Varias máquinas que admiten varios niveles constituyen un desafío especial en el análisis de rendimiento, porque supervisar cualquier máquina individual proporciona una imagen incompleta de la aplicación.

Por ejemplo, usar un sistema de base de datos como SQL Server para administrar y mediar el acceso al almacén de datos de la aplicación crea un nivel de datos que se aísla de la lógica de aplicación. Los datos de aplicación hospedados en una base de datos como SQL Server se mantienen en un espacio de dirección de proceso independiente con su propio almacén de datos. La base de datos que contiene los datos de aplicación puede residir en la misma máquina física que la aplicación, pero hay más posibilidades de obtener acceso a ella desde una máquina distinta mediante el uso de protocolos de red.

SQL ordena que la aplicación se transmita a una base de datos externa y que se opere en función de si hay llamadas fuera de proceso. Los perfiles de muestreo ven que la aplicación está inactiva mientras espera que se completen estas llamadas fuera de proceso, pero no pueden indicar por qué la aplicación está en espera ni la duración de estos retrasos. Los perfiles instrumentados y de simultaneidad sí miden la duración de estos retrasos, pero no pueden indicar los comandos SQL que se emiten o por qué demoran tanto en completarse.

En las aplicaciones de varios niveles que se comunican con una base de datos externa, a menudo el componente de base de datos es uno de los factores que más contribuye al tiempo de respuesta de la aplicación global. Las herramientas para generación de perfiles de Visual Studio incluyen una variedad de métodos para la generación de perfiles, incluido el muestreo, la instrumentación, la asignación de memoria y la simultaneidad, pero ninguno de estos métodos podría ser de mucha ayuda para identificar problemas de rendimiento asociados con la obtención de acceso a una base de datos externa sin datos de TIP.

Los datos de TIP le permiten explorar en profundidad los retrasos relacionados con la base de datos y comprender por qué se producen. Junto con otras herramientas de rendimiento que puede suministrar el proveedor de la base de datos, también puede comenzar a entender lo que se puede hacer para mejorar el rendimiento de una aplicación que depende en gran medida del rendimiento de la base de datos.

Como TIP agrega instrumentación al código de la aplicación, es posible recopilar los datos de tiempo asociados con los comandos de la base de datos independientemente de la ubicación física de la instancia de base de datos a la que se obtiene acceso. Por ejemplo, es posible recopilar datos de tiempo para llamadas fuera de proceso a una instancia de SQL Server que reside físicamente en la misma máquina que la aplicación, lo que es un escenario típico en pruebas unitarias. Cuando la misma aplicación está lista para la integración o para cargar pruebas contra una instancia de SQL Server ubicada en una máquina física separada, TIP puede continuar recopilando datos de medida para esa configuración. De hecho, las medidas de TIP le permiten comparar el rendimiento de estas dos configuraciones distintas.

TIP le permite comparar y contrastar el impacto de las diversas opciones de ajuste y rendimiento de base de datos externas que están disponibles, incluida la configuración de la memoria caché, dispositivos de almacenamiento de datos físicos, particiones de base de datos, indización de base de datos y diseño de tabla de base de datos. Además, puede medir directamente el impacto que tiene en el rendimiento la ejecución de SQL Server en una máquina virtual.

Conceptos básicos sobre informes de TIP

Una vez que se completa una sesión de generación de perfiles con TIP activada, los datos de tiempo asociados con cualquier interacción de la aplicación con su nivel de datos de ADO.NET se resumen en la vista Interacciones de nivel. La figura 1 muestra un ejemplo del generador de perfiles cuando la recopilación de datos de TIP está activa y hay actividad de ADO.NET durante la ejecución de la generación de perfiles.

image: A Visual Studio Profiler Tier Interaction Report

Figura 1 Informe de interacción de nivel del generador de perfiles de Visual Studio

La primera mitad del informe es un resumen de los datos recopilados de la generación de perfiles. En el caso de las aplicaciones ASP.NET, la vista se organiza por dirección URL. El informe agrupa el tiempo de respuesta de lado servidor de las solicitudes GET de la aplicación web por dirección URL.

Debajo del nivel de aplicación, el informe muestra cada conexión con un nivel de base de datos (que en este ejemplo era la base de datos de muestra AdventureWorks). Mide e informa la parte del tiempo de procesamiento de lado servidor para las solicitudes de ASP.NET que se asocia con las llamadas de base de datos sincrónicas mediante ADO.NET. En este ejemplo aparecen tres líneas de resumen, y cada una de ellas tabula la actividad de base de datos asociada con tres páginas de ASP.NET distintas en el sitio web del que se generan perfiles. Para cada página de ASP.NET identificada durante la generación de perfiles, se informa el número de solicitudes de ASP.NET que se procesaron durante la ejecución de la generación de perfiles y los tiempos de respuesta de lado servidor para cada mensaje de respuesta que se generó.

Líneas de resumen adicionales muestran los datos de tiempo de respuesta para otras solicitudes GET, incluidas solicitudes para hojas de estilo, código Javascript e imágenes vinculadas en las páginas. Cualquier llamada de base de datos que el generador de perfiles no puede asociar con una solicitud de ASP.NET específica se agrupa bajo una categoría de Otras solicitudes.

Cuando genera perfiles de una aplicación de consola o escritorio de Windows que utiliza un nivel de datos, el informe organiza la actividad de ADO.NET bajo el nombre del proceso.

Bajo cada línea de resumen de página web hay una línea de resumen única que informa el número de solicitudes de base de datos sincrónica, organizadas por conexión de base de datos, realizadas durante el procesamiento de ASP.NET. En este ejemplo, puede ver que se manejaron seis solicitudes de ASP.NET a Customer­Query.aspx sobre una conexión de base de datos única. Estas seis solicitudes demoraron un total de 0,959 segundos en procesarse en el servidor, para obtener un tiempo de respuesta promedio de 160 milisegundos. Estas solicitudes emitieron 12 consultas SQL que demoraron aproximadamente 45 milisegundos en completarse. La espera de solicitudes de base de datos representó sólo alrededor del 5 por ciento del tiempo transcurrido asociado con la generación de los mensajes de respuesta para esta página web.

Si resalta una de las líneas de resumen de conexión de base de datos, la segunda mitad de la vista Interacciones de nivel desglosa los comandos específicos de SQL que emitió la aplicación. El texto de comando agrupa los comandos SQL emitidos y ordenados por tiempo transcurrido dentro del grupo de páginas.

En el ejemplo, un comando SQL se emitió tres veces, otro comando se emitió seis veces y una tercera consulta se emitió tres veces. En la vista detallada, el tiempo transcurrido de cada consulta específica que se acumula en una línea única del informe de resumen se informa por separado. Puede ver el tiempo transcurrido total, el promedio entre todas las instancias del comando y los retrasos mínimo y máximo que se observaron para cada consulta.

Si hace doble clic en la línea de detalle de comando SQL, el texto completo del comando SQL que se emitió aparece en una ventana Texto de comando de base de datos. Este es el comando real que la aplicación transmite a la base de datos en toda la interfaz ADO.NET durante la ejecución. Si la solicitud es para la ejecución de un procedimiento almacenado, aparece la llamada específica al procedimiento almacenado.

Un ejemplo de LINQ to SQL

Veamos un simple ejemplo del uso de TIP para comprender una aplicación ASP.NET que depende en gran medida del acceso a la información desde una base de datos.

TIP puede ser especialmente útil con aplicaciones que usan LINQ to SQL para obtener acceso a datos almacenados en una base de datos de SQL Server externa, porque LINQ tiende a llevar al desarrollador un paso más adelante de la base de datos física y sus características de rendimiento. Con LINQ to SQL, los diagramas Entidad:Relación (E:R) que crea en Object Relational Designer generan clases que luego usa Visual Studio como plantillas para crear comandos SQL sintácticamente correctos de manera automática.

Como LINQ to SQL elimina la mayoría de las consideraciones de codificación de lenguaje SQL y es fácil de usar, también tiende a enmascarar importantes consideraciones de rendimiento asociadas con el ajuste, la configuración y el diseño de la base de datos. Tal como ilustra este ejemplo, con LINQ puede crear fácilmente una consulta compleja que une varias tablas sin tener que considerar las implicaciones que hacerlo tiene en el rendimiento.

Con TIP, puede ver el texto de comando SQL real que LINQ to SQL genera y recopilar medidas desde la ejecución en tiempo de ejecución de estas consultas SQL. Con el texto de comando SQL, puede obtener acceso a otras herramientas de ajuste de base de datos que le ayuden a comprender mejor las implicaciones de rendimiento de cualquier operación LINQ to SQL en particular.

Mi ejemplo es una aplicación de formulario web que consulta las tablas Adventure¬Works Sales.Customer mediante el uso de un identificador de cliente específico para recuperar el historial de pedidos de ese cliente. Las tablas AdventureWorks que forman parte de esta consulta incluyen las tablas Customer, SalesOrderHeader, Sales­OrderDetail y StateProvince tables, tal como aparece en la vista de Object Relational Designer en la figura 2.

image: The AdventureWorks Tables Used to Query Sales.Customer Information

Figura 2 Las tablas AdventureWorks usadas para consultar información de Sales.Customer

En caso de que también desease mostrar la información de dirección de correo electrónico y de correo postal del cliente junto con el historial de pedidos, es necesario obtener acceso a las tablas Customer¬Address, Address y Contact. Tal como se muestra en Object Relational Designer, las tablas AdventureWorks contienen claves foráneas y principales, como CustomerID, SalesOrder y ContactID, que permiten que estas tablas se unan de manera lógica.

El código C# para crear una consulta de cliente de AdventureWorks con LINQ to SQL aparece en la figura 3. En este caso, custid es el valor de CustomerID específico solicitado. Esta consulta devuelve una colección customeryquery que contiene una sola fila de datos con los campos de datos listados en la nueva cláusula Select.

Figura 3 Consulta de cliente LINQ to SQL

var customerquery = 
  from customers in db.Customers
  from custaddrs in db.CustomerAddresses
  from addrs in db.Addresses
  where (customers.CustomerID == custid &&
         customers.CustomerID == custaddrs.CustomerID &&
         custaddrs.AddressID == addrs.AddressID)

  select new {
    customers.CustomerID,
    customers.CustomerType,
    addrs.AddressLine1,
    addrs.AddressLine2,
    addrs.City,
    addrs.StateProvince,
    addrs.PostalCode,
    customers.TerritoryID
  };

Customeryquery puede enlazarse a un control sobre una página web de ASP.NET:

DetailsView1.DataSource = customerquery;
DetailsView1.DataBind();

Ahora puedo crear una consulta para recuperar el historial de pedidos de este cliente:

var orderquery = 
  from orderhdr in db.SalesOrderHeaders
  where (orderhdr.CustomerID == custid)
  orderby orderhdr.OrderDate
  select new {
    Date = orderhdr.OrderDate.ToShortDateString(),
    orderhdr.AccountNumber,
    InvoiceNo = orderhdr.SalesOrderID,
    orderhdr.TotalDue
  };

Cuando se ejecuta esta operación de LINQ to SQL, orderquery contendrá una fila correspondiente a cada fila de la tabla OrderHdr asociada con un identificador de cliente específico. La colección orderquery contendrá varias filas si el historial del cliente indica que hubo varias transacciones de ventas.

Estas consultas se ven simples en la superficie. Pero con TIP, puede comenzar a comprender las implicaciones que estas operaciones LINQ to SQL aparentemente simples tienen en el rendimiento.

Uso de datos de TIP para ajuste

Observemos con mayor detenimiento customerquery. En tiempo de ejecución, LINQ to SQL toma las operaciones SELECT de base de datos lógicas que participan en la sentencia LINQ y las usa para generar un comando SQL válido que une datos desde cuatro tablas de AdventureWorks: Customers, Customer­Addresses, Addresses y la tabla estática StateProvince. Esto no se ve en el código LINQ to SQL que aparece aquí.

Cuando ejecuta este código en el generador de perfiles de Visual Studio, la instrumentación de TIP informa el número de veces que se ejecutó esta consulta y mide el tiempo en que se retraso la página web en espera de su ejecución. De hecho, ésta es la operación que se ejecutó seis veces durante la ejecución de generación de perfiles que se ilustró en la figura 1.

Además, y tal como vimos anteriormente, el comando SQL generado por el código LINQ to SQL también está disponible cuando se generan perfiles de la aplicación. La figura 4 muestra el comando SQL real para esta operación.

Figure 4 Comando SQL para customerquery

SELECT [t0].[CustomerID], [t0].[CustomerType], [t2].[AddressLine1], [t2].[AddressLine2], [t2].[City], [t3].[StateProvinceID], [t3].[StateProvinceCode], [t3].[CountryRegionCode], [t3].[IsOnlyStateProvinceFlag], [t3].[Name], [t3].[TerritoryID], [t3].[rowguid], [t3].[ModifiedDate], [t2].[PostalCode], [t0].[TerritoryID] AS [TerritoryID2]
FROM [Sales].[Customer] AS [t0]
CROSS JOIN [Sales].[CustomerAddress] AS [t1]
CROSS JOIN [Person].[Address] AS [t2]
INNER JOIN [Person].[StateProvince] AS [t3] ON [t3].[StateProvinceID] = [t2].[StateProvinceID]
WHERE ([t0].[CustomerID] = @p0) AND ([t0].[CustomerID] = [t1].[CustomerID]) AND ([t1].[AddressID] = [t2].[AddressID])

Observe que el texto de comando SQL incluye un token (designado aquí como “@p0”) para representar el parámetro de identificador de cliente que LINQ agrega a la consulta.

Ahora que el texto de comando SQL real generado por LINQ está disponible, es posible comprender cómo el diseño de base de datos afecta el rendimiento de la consulta.

Una acción que se puede realizar es ejecutar este comando SQL en SQL Server Management Studio y examinar su plan de ejecución, tal como aparece en la figura 5. Para obtener acceso al plan de ejecución para esta consulta, necesita agregar un comando para apuntar a la base de datos adecuada:

USE AdventureWorks ;
GO

A continuación, copie el texto de comando SQL desde el informe de TIP, recordando reemplazar el token "@p0" con un CustomerID válido desde la base de datos. Luego ejecute esta consulta de ejemplo en SQL Server Management Studio y obtenga acceso al plan de ejecución que muestra cómo el optimizador de consultas tradujo la solicitud lógica a un plan de ejecución físico.

image: The Execution Plan for the Example LINQ to SQL Operation

Figura 5 El plan de ejecución para la operación LINQ to SQL de ejemplo

En este ejemplo, el plan de ejecución para la consulta muestra que la sentencia SELECT obtuvo acceso a la tabla Customer mediante el uso de un índice agrupado en el campo CustomerID que devolvió exactamente una fila en la tabla. En SQL Server Management Studio, puede posar el mouse sobre una operación para ver sus propiedades o resalte la operación y haga clic con el botón secundario para ver la ventana Propiedades. De este modo, puede recorrer cada una de las operaciones restantes que solicita el comando. Cada una de las tres JOIN subsiguientes que aumentan la SELECT de cliente inicial también obtienen acceso a una tabla que usa su índice agrupado y devuelve una fila única.

A partir de esta investigación, puede ver que, para procesar esta consulta, es necesario obtener acceso a un total de cuatro filas, cada una desde una tabla distinta en la base de datos AdventureWorks. Cada acceso se realiza de manera eficiente utilizando la clave principal única de la tabla.

De manera similar, puede usar TIP para ver el comando SQL para el código de orderquery y agregarlo a SQL Server Management Studio para ver su plan de ejecución (vea la figura 6). Esta consulta obtiene acceso a una tabla única llamada OrderHdr mediante el uso de CustomerID como una clave foránea, por lo que necesita obtener acceso tanto a un índice no agrupado estándar como a un índice agrupado en SalesOrderHeaderID.

image: The Execution Plan for orderquery

Figura 6 El plan de ejecución para orderquery

Esta instancia de la consulta en particular devuelve nueve filas. La cláusula OrderBy en el código LINQ to SQL se traduce a una cláusula SQL ORDER BY que implica una operación Sort adicional sobre el resultset de SELECT. Esta operación representa 40% del costo general que implica ejecutar la solicitud, según lo estimado por SQL Server Plan Optimizer.

Elección de un contexto de generación de perfiles

TIP está diseñado para complementar métodos para la generación de perfiles de Visual Studio existentes a fin de recopilar medidas específicas sobre las interacciones de nivel de datos. TIP es una función de recopilación de datos secundaria y no se puede recopilar sin especificar un método de generación de perfiles principal. Los datos de TIP se pueden recopilar durante generaciones de perfiles de muestreo, instrumentación y simultaneidad para cualquier aplicación que se comunique con un nivel de datos a través de ADO.NET.

Dado que necesita elegir un método principal para la generación de perfiles para una aplicación en la que desea recopilar datos de TIP, ¿cuál debiera usar? Veamos algunas de las consideraciones para seleccionar un método de generación de perfiles principal.

¿El foco principal de la investigación de rendimiento son los retrasos asociados con las interacciones de nivel de datos? Si es así, el método principal recomendado es la generación de perfiles de muestreo, porque normalmente es la menos intrusiva de las generaciones de perfiles.

Si los retrasos de nivel de datos no son el foco principal de la investigación de rendimiento, seleccione un método de generación de perfiles en base a lo que tiene más posibilidades de proporcionar los datos de medidas y que sea más aplicable en el contexto actual. Por ejemplo, si investiga un problema asociado con la ejecución simultánea de varios subprocesos, recopile datos de simultaneidad. Si investiga un problema asociado con una aplicación dependiente de CPU, recopile datos de muestreo. Para obtener más guías sobre qué método de recopilación principal escoger, consulte el artículo “Cómo elegir métodos de recopilación”.

Si todavía no está familiarizado con el código de nivel de datos, es posible que necesite obtener ayuda desde los datos de generación de perfiles principales para encontrar el código exacto donde se originan estas llamadas de ADO.NET. TIP no captura una pila de llamadas cuando recopila información de tiempo sobre llamadas fuera de proceso de ADO.NET sincrónicas. Si necesita comprender en qué lugar de la aplicación se realizan las llamadas a métodos ADO.NET, los perfiles instrumentados serán los más útiles. Los datos de muestreo también pueden ayudarle con esto, pero no con la precisión de un perfil instrumentado.

Puede elegir recopilar datos de contención de recursos junto con las medidas de interacción de niveles, pero la recopilación de datos de contención tiende a ser una función bastante más sobrecargada que el muestreo, y los datos de contención probablemente no proporcionen ayuda alguna para determinar dónde se originan las llamadas ADO.NET específicas. Las investigaciones que requieren de generación de perfiles de asignación de memoria .NET, que normalmente son de muy alto impacto, difícilmente se beneficien de la recopilación de medidas de interacción de niveles.

Perfiles de muestreo

A menudo, las interacciones de nivel de datos son el foco principal de una investigación de rendimiento. En este caso, normalmente se obtienen los mejores resultados cuando se elige el muestreo como el método principal para la generación de perfiles. En este caso, se prefiere el muestreo porque es el método de generación de perfiles que normalmente tiene el menor efecto en el rendimiento de una aplicación. Los perfiles de muestreo también pueden resultar útiles en la navegación al código fuente donde se originan las llamadas ADO.NET que afectan mayormente al rendimiento.

Con las funciones de nivel de datos que se ejecutan fuera de proceso, las muestras de ejecución de instrucciones recopiladas durante un perfil de muestreo normalmente no reflejan nada del tiempo que pasa una aplicación en espera de que se completen las llamadas sincrónicas a través una interfaz de ADO.NET. Durante períodos en los que el subproceso de ejecución de una aplicación está en espera de que se completen estas llamadas fuera de proceso, el subproceso de la aplicación se bloquea y no se registran muestras de ejecución en él. Cuando se usa el muestreo, recopilar datos de TI es la mejor manera de comprender cuáles de los retrasos de la aplicación producidos se deben a las llamadas sincrónicas a un nivel de datos.

La instrumentación que TIP usa no captura pilas de llamadas cuando recopila datos de tiempo. Por lo tanto, si genera perfiles de una aplicación por niveles y no está completamente familiarizado con el código, puede resultar difícil determinar de manera precisa dónde se originan las llamadas al nivel de datos. Los perfiles de muestreo también pueden ayudar a identificar en qué parte del código de la aplicación se realizan las llamadas a estas interfaces de ADO.NET. Si la aplicación realiza frecuentes llamadas a las interfaces de ADO.NET, es posible que se recopilen algunas muestras con el tiempo que se pasó en módulos de ADO.NET, incluido System.Data.dll y System.Data.Linq.dll.

Al revisar los datos de muestreo y compararlos con las medidas de interacción de niveles, tenga en cuenta que mientras un subproceso de la aplicación se bloquea en espera de que se complete una llamada sincrónica a la base de datos, no se recopilan datos de muestro para el subproceso. Las muestras acumuladas durante la ejecución excluyen los retrasos fuera de proceso que TIP mide explícitamente. Sin embargo, lo que puede esperar es una correlación aproximada entre las muestras de ejecución recopiladas en métodos ADO.NET y el número de comandos de ADO.NET que TIP observa y mide. En tales casos, los perfiles de muestreo pueden ayudarle a navegar al código fuente donde se originan las llamadas de ADO.NET que TIP mide e informa.

Observe que si una aplicación tiene consultas SQL que devuelven grandes resultsets enlazados a un control enlazado a datos en un formulario, es posible que encuentre un número importante de muestras de ejecución en el método DataBind del control. Ver qué métodos DataBind aparecen en el perfil de muestreo también puede ayudarle a navegar al código fuente donde se originan las llamadas de ADO.NET.

Perfiles instrumentados

Cuando se recopilan perfiles instrumentados, los datos de tiempo para los métodos que la instrumentación registra ya incluyen cualquier tiempo que se haya pasado en espera de que se completen las llamadas fuera de proceso dentro del método. Los datos de tiempo registrados en un perfil instrumentado se recopilan al medir el tiempo en la entrada y la salida de cada uno de los métodos de la aplicación seleccionados para instrumentación. Los datos de tiempo para métodos en una aplicación que interactúan con un nivel de datos mediante llamadas de ADO.NET incluyen de manera implícita el retraso en la ejecución de cualquier llamada fuera de proceso.

Los datos de tiempo recopilados desde TIP identifican y miden explícitamente los retrasos fuera de proceso de forma separada. El retraso medido por la generación de perfiles de interacción de niveles debe ser un subconjunto del tiempo general que se pasó dentro del método, tal como se midió durante una ejecución de generación de perfiles instrumentada. Con este conocimiento, debe poder asociar los datos de tiempo desde la generación de perfiles de interacción de niveles con los datos de tiempo recopilados en el nivel del método en un perfil instrumentado para identificar el método donde se originó la llamada al nivel de datos.

Si la instrumentación a nivel del método es suficiente para permitirle saber en qué lugar de la aplicación se origina alguna llamada de ADO.NET, la generación de perfiles instrumentada se puede usar sin vacilación. Sin embargo, los perfiles instrumentados normalmente son mucho más intrusivos que los perfiles de muestreo, incurren en sobrecargas mucho mayores y tienden a generar archivos de colección .vsp mucho más grandes. Además, si la aplicación usa métodos que realizan varias llamadas a funciones de ADO.NET, los datos que la instrumentación recopila sólo le ayudarán a navegar al nivel del método, sin hacer diferencia entre las diversas llamadas de ADO.NET insertadas dentro de un método.

Por favor, más datos

La creación de aplicaciones de varios niveles es un patrón de diseño que promueve la confiabilidad y la escalabilidad, pero que también lleva a desafíos de supervisión de rendimiento cuando los componentes de la aplicación se ejecutan en distintas máquinas.

Una vista simple de una aplicación de varios niveles que no abarca todos sus niveles interconectados no puede proporcionar una imagen completa de su rendimiento. Tal como ha visto, TIP puede suministrar datos de tiempo clave, los que de otro modo se omitirían. Como sugiere el ejemplo de este artículo, es posible aumentar estos datos de tiempo con otros datos de rendimiento desde herramientas estándar para el administrador de base de datos.

Mark Friedman es arquitecto miembro del equipo de Visual Studio Ultimate en Microsoft. Es autor de dos libros sobre el rendimiento de Windows y publica periódicamente un blog acerca de los problemas del rendimiento en el sitio web blogs.msdn.com/ddperf/.

Gracias a los siguientes expertos técnicos por su ayuda en la revisión de este artículo: Daryush Laqab y Chris Schmich