Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Se aplica a:SQL Server
Azure SQL Database
Información general
En este ejemplo se muestra la característica OLTP en memoria. Muestra tablas optimizadas para memoria y procedimientos almacenados compilados de forma nativa, y se puede usar para demostrar las ventajas de rendimiento de OLTP en memoria.
Nota:
Para ver este artículo para SQL Server 2014 (12.x), vea Extensiones a AdventureWorks para demostrar In-Memory OLTP.
En el ejemplo se migran cinco tablas de la base de datos AdventureWorks2025 a optimizadas para memoria y se incluye una carga de trabajo de demostración para el procesamiento de pedidos de venta. Puede usar esta carga de trabajo de demostración para ver la ventaja de rendimiento del uso de OLTP en memoria en el servidor.
En la descripción del ejemplo, se describen los inconvenientes realizados en la migración de las tablas a OLTP en memoria para tener en cuenta las características que aún no se admiten para las tablas optimizadas para memoria.
La documentación de este ejemplo está estructurada de la manera siguiente:
Requisitos previos para instalar el ejemplo y ejecutar la carga de trabajo de demostración.
Instrucciones para instalar el ejemplo de In-Memory OLTP basado en AdventureWorks.
Descripción de las tablas y procedimientos de ejemplo : incluye descripciones de las tablas y procedimientos agregados a
AdventureWorks2025por el ejemplo OLTP en memoria, así como consideraciones para migrar algunas de las tablas originalesAdventureWorks2025para optimizar la memoria.Instrucciones para realizar mediciones de rendimiento mediante la carga de trabajo de demostración : incluye instrucciones para instalar y ejecutar ostress, una herramienta que usa para impulsar la carga de trabajo y ejecutar la propia carga de trabajo de demostración.
Requisitos previos
-
SQL Server 2016 (13.x)
Para las pruebas de rendimiento, un servidor con unas especificaciones similares al entorno de producción. Para esta muestra concreta, debe haber al menos 16 GB de memoria disponible para SQL Server. Para obtener instrucciones generales sobre hardware para OLTP en memoria, consulte la siguiente entrada de blog: Consideraciones de hardware para In-Memory OLTP en SQL Server
Instalación del ejemplo OLTP en memoria basado en AdventureWorks
Siga estos pasos para instalar el ejemplo:
Descargue
AdventureWorks2016_EXT.bakySQLServer2016Samples.zipde: https://github.com/microsoft/sql-server-samples/releases/tag/adventureworks a una carpeta local, por ejemploC:\Temp.Restaure la copia de seguridad de la base de datos mediante Transact-SQL o SQL Server Management Studio:
Identifique la carpeta de destino y el nombre de archivo del archivo de datos, por ejemplo:
H:\DATA\AdventureWorks2022_Data.mdfIdentifique la carpeta de destino y el nombre de archivo del archivo de registro, por ejemplo:
I:\DATA\AdventureWorks2022_log.ldf- El archivo de registro debe colocarse en otra unidad diferente que el archivo de datos, idealmente en una unidad de baja latencia como un almacenamiento SSD o PCIe, para obtener el máximo rendimiento.
Script T-SQL de ejemplo:
RESTORE DATABASE [AdventureWorks2022] FROM DISK = N'C:\temp\AdventureWorks2022.bak' WITH FILE = 1, MOVE N'AdventureWorks2022_Data' TO N'h:\DATA\AdventureWorks2022_Data.mdf', MOVE N'AdventureWorks2022_Log' TO N'i:\DATA\AdventureWorks2022_log.ldf', MOVE N'AdventureWorks2022_mod' TO N'h:\data\AdventureWorks2022_mod' GOPara ver los scripts de ejemplo y la carga de trabajo, desempaquete el archivo
SQLServer2016Samples.zipen una carpeta local. Consulte el archivoIn-Memory OLTP\readme.txtpara obtener instrucciones sobre cómo ejecutar la carga de trabajo.
Descripción de las tablas y los procedimientos de ejemplo:
En el ejemplo se crean nuevas tablas para productos y pedidos de venta basadas en tablas existentes de AdventureWorks2025. El esquema de las nuevas tablas es similar a las tablas existentes, con algunas diferencias, como se explica más adelante en esta sección.
Las nuevas tablas optimizadas para memoria llevan el sufijo _inmem. El ejemplo también incluye las tablas correspondientes que llevan el sufijo _ondisk : estas tablas se pueden usar para realizar una comparación uno a uno entre el rendimiento de las tablas optimizadas para memoria y las tablas basadas en disco en el sistema.
Las tablas optimizadas para memoria empleadas en la carga de trabajo para la comparación de rendimiento son totalmente durables y con registro completo. No sacrifican la durabilidad ni la confiabilidad para lograr la ganancia de rendimiento.
La carga de trabajo de destino de este ejemplo es el procesamiento de pedidos de venta, donde también tenemos en cuenta la información sobre productos y descuentos. Para ello, se usan las tablas SalesOrderHeader, SalesOrderDetail, Product, SpecialOffer y SpecialOfferProduct.
Se emplean dos nuevos procedimientos almacenados, Sales.usp_InsertSalesOrder_inmem y Sales.usp_UpdateSalesOrderShipInfo_inmem, para insertar pedidos de venta y actualizar la información de envío de un pedido de venta determinado.
El nuevo esquema Demo contiene tablas y procedimientos almacenados auxiliares para ejecutar una carga de trabajo de demostración.
En concreto, el ejemplo de OLTP en memoria agrega los siguientes objetos a AdventureWorks2025:
Tablas agregadas por el ejemplo
Las nuevas tablas
Sales.SalesOrderHeader_inmem
- Información de encabezado sobre los pedidos de venta. Cada pedido de venta tiene una fila en esta tabla.
Sales.SalesOrderDetail_inmem
- Detalles de los pedidos de venta. Cada artículo de un pedido de venta tiene una fila en esta tabla.
Sales.SpecialOffer_inmem
- Información sobre ofertas especiales, incluido el porcentaje de descuento asociado a cada oferta especial.
Sales.SpecialOfferProduct_inmem
- Tabla de referencia entre las ofertas especiales y los productos. Cada oferta especial puede abarcar cero o más productos, y cada producto puede estar incluido en cero o más ofertas especiales.
Production.Product_inmem
- Información sobre productos, incluido el precio de venta.
Demo.DemoSalesOrderDetailSeed
- Se usa en la carga de trabajo de demostración para generar pedidos de venta de ejemplo.
Variaciones basadas en disco de las tablas:
Sales.SalesOrderHeader_ondiskSales.SalesOrderDetail_ondiskSales.SpecialOffer_ondiskSales.SpecialOfferProduct_ondiskProduction.Product_ondisk
Diferencias entre las tablas originales basadas en disco y las nuevas tablas optimizadas para memoria
Normalmente, las nuevas tablas introducidas por este ejemplo usan las mismas columnas y los mismos tipos de datos que las tablas originales. Sin embargo, hay algunas diferencias. Enumeramos las diferencias en esta sección, junto con una justificación para los cambios.
Sales.SalesOrderHeader_inmem
Lasrestricciones DEFAULT se admiten en las tablas optimizadas para memoria y la mayoría de las restricciones DEFAULT se migran tal cual. Sin embargo, la tabla original
Sales.SalesOrderHeadercontiene dos restricciones predeterminadas que recuperan la fecha actual, para las columnasOrderDateyModifiedDate. En una carga de trabajo de procesamiento de pedidos de alto rendimiento con mucha simultaneidad, cualquier recurso global puede convertirse en un punto de contención. El tiempo del sistema es un recurso tan global, y hemos observado que puede llegar a ser un cuello de botella cuando se ejecuta una carga de trabajo OLTP en memoria que inserta pedidos de ventas, especialmente si es necesario recuperar el tiempo del sistema para varias columnas en el encabezado del pedido de ventas y los detalles del pedido de ventas. Para resolver el problema de este ejemplo se recupera la hora del sistema solo una vez para cada pedido de venta que se inserta, y se usa ese valores para las columnas datetime deSalesOrderHeader_inmemySalesOrderDetail_inmem, en el procedimiento almacenadoSales.usp_InsertSalesOrder_inmem.Tipos de datos definidos por el usuario de alias (UDT): la tabla original usa dos UDT de alias,
dbo.OrderNumberydbo.AccountNumber, para las columnasPurchaseOrderNumberyAccountNumber, respectivamente. SQL Server 2016 (13.x) no admite el UDT de alias para tablas optimizadas para memoria, por lo que las nuevas tablas usan tipos de datos del sistema nvarchar(25) y nvarchar(15), respectivamente.Columnas que aceptan valores NULL en las claves de índice: en la tabla original, la columna
SalesPersonIDadmite valores NULL, mientras que en las nuevas tablas la columna no admite valores NULL y tiene una restricción predeterminada con el valor (-1). Esta circunstancia se debe a que los índices de las tablas optimizadas para memoria no pueden tener columnas que aceptan valores NULL en la clave de índice; -1 es un suplente para NULL en este caso.Columnas calculadas : las columnas calculadas
SalesOrderNumberyTotalDuese omiten, ya que SQL Server 2016 (13.x) no admite columnas calculadas en tablas optimizadas para memoria. La nueva vistaSales.vSalesOrderHeader_extended_inmemrefleja las columnasSalesOrderNumberyTotalDue. Por tanto, puede usar esta vista si se necesitan estas columnas.- Se aplica a: SQL Server 2017 (14.x). A partir de SQL Server 2017 (14.x), las columnas calculadas se admiten en tablas e índices optimizados para memoria.
Las restricciones de clave externa se admiten para tablas optimizadas para memoria en SQL Server 2016 (13.x), pero solo si las tablas de referencia también están optimizadas para memoria. Las claves externas que hagan referencia a tablas de referencia que también se migran a tablas optimizadas para memoria se conservan en esas tablas migradas, mientras que otras claves externas se omiten. Además,
SalesOrderHeader_inmemes una tabla activa en la carga de trabajo de ejemplo y las restricciones de claves externas requieren un procesamiento adicional para todas las operaciones DML, ya que requiere búsquedas en todas las demás tablas a las que se hace referencia en estas restricciones. Por lo tanto, la suposición es que la aplicación garantiza la integridad referencial de laSales.SalesOrderHeader_inmemtabla y la integridad referencial no se valida cuando se insertan filas.Rowguid: la columna rowguid se omite. Aunque uniqueidentifier se admite para tablas optimizadas para memoria, la opción ROWGUIDCOL no se admite en SQL Server 2016 (13.x). Las columnas de esta clase se suelen usar para la replicación de mezcla o para tablas que incluyen columnas FILESTREAM. En este ejemplo no se incluye ninguna de ellas.
Sales.SalesOrderDetail
Restricciones predeterminadas : similares a
SalesOrderHeader, la restricción predeterminada que requiere la fecha y hora del sistema no se migra. En su lugar, el procedimiento almacenado que inserta pedidos de ventas se encarga de insertar la fecha y hora actuales del sistema en la primera inserción.Columnas calculadas : la columna
LineTotalcalculada no se migró porque las columnas calculadas no se admiten con tablas optimizadas para memoria en SQL Server 2016 (13.x). Para acceder a esta columna, use laSales.vSalesOrderDetail_extended_inmemvista .Rowguid: la columna
rowguidse omite. Para obtener detalles, vea la descripción de laSalesOrderHeader.
Production.Product
UDT de alias: en la tabla original se usa el tipo de datos definido por el usuario
dbo.Flag, que equivale al tipo de datos del sistema bit. La tabla migrada usa el tipo de datos bit en su lugar.Rowguid: la columna
rowguidse omite. Para obtener detalles, vea la descripción de laSalesOrderHeader.
Sales.SpecialOffer
-
Rowguid: la columna
rowguidse omite. Para obtener detalles, vea la descripción de laSalesOrderHeader.
Sales.SpecialOfferProduct
-
Rowguid: la columna
rowguidse omite. Para obtener detalles, vea la descripción de laSalesOrderHeader.
Consideraciones sobre los índices de tablas optimizadas para memoria
El índice de línea base para las tablas optimizadas para memoria es el índice no clúster, que admite búsquedas de puntos (búsqueda de índice en predicado de igualdad), recorridos de intervalo (búsqueda de índice en predicados de desigualdad), exámenes de índice completos y exámenes ordenados. Además, los índices no clúster admiten búsquedas en las columnas iniciales de la clave de índice. De hecho, los índices no clúster optimizados para memoria admiten todas las operaciones compatibles con los índices no clúster basados en disco, con la única excepción de los exámenes hacia atrás. Por tanto, el uso de índices no clúster es una opción segura para los índices.
Se pueden usar índices HASH para optimizar aún más la carga de trabajo. Están optimizados especialmente para búsquedas de puntos e inserciones de filas. Sin embargo, hay que tener en cuenta que no admiten escaneos de rango, escaneos ordenados o búsqueda en columnas de clave de índice inicial. Por tanto, hay que tener cuidado cuando se usen estos índices. Además, es necesario especificarlo en el momento de la creación. Normalmente se debe establecer entre una y dos veces el número de valores de clave de índice, pero la sobrestimación no suele suponer ningún problema.
Para obtener más información:
- Directrices para las operaciones de índice en línea
- Elección del elemento bucket_count adecuado
- Índices de las tablas con optimización para memoria
Los índices en las tablas migradas se ajustaron para la carga de trabajo de procesamiento de pedidos de ventas del entorno de demostración. La carga de trabajo se basa en inserciones y búsquedas de puntos de las tablas Sales.SalesOrderHeader_inmem y Sales.SalesOrderDetail_inmem, y también se basa en búsquedas de puntos de las columnas de clave principal de las tablas Production.Product_inmem y Sales.SpecialOffer_inmem.
Sales.SalesOrderHeader_inmem tiene tres índices, que son todos índices HASH por motivos de rendimiento, y porque no se necesita ningún examen ordenado o de intervalos para la carga de trabajo.
Índice de HASH de (
SalesOrderID): el valor de bucket_count tiene un tamaño de 10 millones (redondeado hasta 16 millones), ya que el número esperado de pedidos de venta es de 10 millonesÍndice de HASH de (
SalesPersonID): el valor de bucket_count es de 1 millón. El conjunto de datos proporcionado no tiene muchas personas de ventas. Pero este bucket_count grande permite un crecimiento futuro. Además, no paga ninguna penalización de rendimiento por las búsquedas de puntos si el elemento bucket_count es demasiado grande.Índice de HASH de (
CustomerID): el valor de bucket_count es de 1 millón. El conjunto de datos proporcionado no tiene muchos clientes, pero esto permite un crecimiento futuro.
Sales.SalesOrderDetail_inmem tiene tres índices, que son todos índices HASH por motivos de rendimiento, y porque no se necesita ningún examen ordenado o de intervalos para la carga de trabajo.
Índice HASH en (
SalesOrderID,SalesOrderDetailID): este es el índice de clave principal y, aunque las búsquedas en (SalesOrderID,SalesOrderDetailID) son poco frecuentes, el uso de un índice hash para la clave acelera las inserciones de filas. El elemento bucket_count tiene un tamaño de 50 millones (redondeado hasta 67 millones); el número esperado de pedidos de venta es de 10 millones y tiene un tamaño promedio de cinco artículos por pedido.Índice HASH en (
SalesOrderID): las búsquedas por pedido de venta son frecuentes: quiere encontrar todas las partidas correspondientes a un único pedido. bucket_count tiene un tamaño de 10 millones (redondeado hasta 16 millones), ya que el número esperado de pedidos de venta es 10 millonesÍndice de HASH de (
ProductID): el valor de bucket_count es de 1 millón. El conjunto de datos proporcionado no tiene muchos productos, pero esto permite un crecimiento futuro.
Production.Product_inmem tiene tres índices
Índice de HASH de (
ProductID): las búsquedas deProductIDestán en la ruta de acceso crítica de la carga de trabajo de demostración; por tanto, se trata de un índice de hash.Índice NONCLUSTERED en (
Name): esto permite exámenes ordenados de nombres de productosÍndice NONCLUSTERED en (
ProductNumber): esto permite búsquedas ordenadas de números de producto
Sales.SpecialOffer_inmem tiene un índice de HASH en (SpecialOfferID): las búsquedas de puntos de ofertas especiales están en la parte crítica de la carga de trabajo de demostración. El elemento bucket_count tiene un tamaño de 1 millón para permitir el crecimiento futuro.
Sales.SpecialOfferProduct_inmem no se menciona en la carga de trabajo de demostración y, por lo tanto, no hay una necesidad aparente de usar índices de hash en esta tabla para optimizar la carga de trabajo: los índices sobre (SpecialOfferID, ProductID) y (ProductID) son de tipo NO CLUSTER.
En el ejemplo anterior, algunos de los recuentos de grupos tienen un tamaño excesivo, pero no los recuentos de grupos de los índices en SalesOrderHeader_inmem y SalesOrderDetail_inmem: tienen un tamaño de solo 10 millones de pedidos de ventas. Esto se hizo para permitir la instalación del ejemplo en sistemas con baja disponibilidad de memoria, aunque en esos casos se produce un error en la carga de trabajo de demostración con un error de memoria insuficiente. Si desea escalar el ejemplo más allá de 10 millones de pedidos de venta, no dude en aumentar los números de cubos en consecuencia.
Consideraciones sobre el uso de memoria
El uso de memoria en la base de datos de ejemplo, tanto antes como después de ejecutar la carga de trabajo de demostración, se describe en la sección Uso de memoria para las tablas optimizadas para memoria.
Procedimientos almacenados añadidos por la muestra
Los dos procedimientos almacenados principales para insertar pedidos de venta y actualizar los detalles de envío son los siguientes:
Sales.usp_InsertSalesOrder_inmemInserta un nuevo pedido de venta en la base de datos y genera el valor de
SalesOrderIDpara ese pedido. Como parámetros de entrada, toma detalles para el encabezado de pedido de ventas y los elementos de línea en el pedido.Parámetro de salida:
-
@SalesOrderID int - el
SalesOrderIDpara el pedido de venta que se acaba de insertar
-
@SalesOrderID int - el
Parámetros de entrada (obligatorios):
- @DueDatedatetime2
- @CustomerIDint
- @BillToAddressIDint
- @ShipToAddressIDint
- @ShipMethodIDint
-
Sales.SalesOrderDetailType_inmem@SalesOrderDetails - parámetro con valores de tabla (TVP) que contiene los elementos de línea del pedido.
Parámetros de entrada (opcionales):
- @Statustinyint
- @OnlineOrderFlagbit
- @PurchaseOrderNumbernvarchar(25)
- @AccountNumbernvarchar(15)
- @SalesPersonIDint
- @TerritoryIDint
- @CreditCardIDint
- @CreditCardApprovalCodevarchar(15)
- @CurrencyRateIDint
- @Commentnvarchar(128)
Sales.usp_UpdateSalesOrderShipInfo_inmemActualice la información de envío para un pedido de venta determinado. Esto también actualiza la información de envío de todos los artículos de línea del pedido de venta.
Se trata de un procedimiento contenedor para los procedimientos almacenados
Sales.usp_UpdateSalesOrderShipInfo_nativecompilados de forma nativa con lógica de reintento para abordar posibles conflictos (inesperados) con transacciones simultáneas que actualizan el mismo pedido. Para más información, consulte Lógica de reintento.
Sales.usp_UpdateSalesOrderShipInfo_native- Este es el procedimiento almacenado compilado de forma nativa que procesa realmente la actualización de la información de envío. Está pensado para llamarse desde el procedimiento almacenado wrapper
Sales.usp_UpdateSalesOrderShipInfo_inmem. Si el cliente puede resolver los errores e implementa lógica de reintento, puede llamar a este procedimiento directamente, en lugar de usar el procedimiento almacenado contenedor.
- Este es el procedimiento almacenado compilado de forma nativa que procesa realmente la actualización de la información de envío. Está pensado para llamarse desde el procedimiento almacenado wrapper
El procedimiento almacenado siguiente se emplea para la carga de trabajo de demostración.
Demo.usp_DemoReset- Restablece la demostración vaciando y reinicializando las tablas
SalesOrderHeaderySalesOrderDetail.
- Restablece la demostración vaciando y reinicializando las tablas
Los procedimientos almacenados siguientes se usan para insertar y eliminar información de las tablas optimizadas para memoria garantizando la integridad del dominio y referencial.
Production.usp_InsertProduct_inmemProduction.usp_DeleteProduct_inmemSales.usp_InsertSpecialOffer_inmemSales.usp_DeleteSpecialOffer_inmemSales.usp_InsertSpecialOfferProduct_inmem
Por último, el procedimiento almacenado siguiente se usa para comprobar la integridad del dominio y referencial.
dbo.usp_ValidateIntegrityParámetro opcional: @object_id : identificador del objeto para validar la integridad
Este procedimiento se basa en las tablas
dbo.DomainIntegrity,dbo.ReferentialIntegrityydbo.UniqueIntegrityde las reglas de integridad que es necesario comprobar; en el ejemplo se rellenan estas tablas según las restricciones únicas, de comprobación y de clave externa que existen para las tablas originales de la base de datosAdventureWorks2025.Se basa en los procedimientos auxiliares
dbo.usp_GenerateCKCheck,dbo.usp_GenerateFKCheckydbo.GenerateUQCheckpara generar el código T-SQL necesario para realizar las comprobaciones de integridad.
Medidas de rendimiento mediante la carga de trabajo de demostración
ostress es una herramienta de línea de comandos desarrollada por el equipo de soporte técnico de MICROSOFT CSS SQL Server. Esta herramienta se puede usar para ejecutar consultas o ejecutar procedimientos almacenados en paralelo. Puede configurar el número de subprocesos para ejecutar una instrucción T-SQL determinada en paralelo y puede especificar cuántas veces se debe ejecutar la instrucción en este subproceso; ostress pone en marcha los subprocesos y ejecuta la instrucción en todos los subprocesos en paralelo. Una vez finalizada la ejecución de todos los subprocesos, ostress notifica el tiempo necesario para que todos los subprocesos finalicen la ejecución.
Instala ostress
ostress se instala como parte de las utilidades del Lenguaje de marcado de informes (RML); no hay ninguna instalación independiente para ostress.
Pasos para la instalación:
Descargue y ejecute el paquete de instalación x64 para las utilidades de RML desde la página siguiente: Descarga de RML para SQL Server.
Si hay un cuadro de diálogo que indica que ciertos archivos están en uso, seleccione "Continuar".
Ejecutar ostress
Ostress se ejecuta desde el símbolo del sistema. Es más conveniente ejecutar la herramienta desde el símbolo del sistema Cmd de RML, que está instalado como parte de las utilidades de RML.
Para abrir RML Cmd Prompt, siga estas instrucciones:
En Windows, abra el menú de inicio; para ello, seleccione la tecla de Windows y escriba rml. Seleccione RML Cmd Prompt, que se encuentra en la lista de resultados de búsqueda.
Asegúrese de que el símbolo del sistema se encuentra en la carpeta de instalación de las utilidades de RML.
Las opciones de línea de comandos para ostress se pueden ver cuando simplemente se ejecutan ostress.exe sin opciones de línea de comandos. Las principales opciones que se deben tener en cuenta para ejecutar ostress con este ejemplo son las siguientes:
| Opción | Description |
|---|---|
-S |
Nombre de la instancia de SQL Server a la que se va a conectar. |
-E |
Usar la autenticación de Windows para conectarse (valor predeterminado); Si usa la autenticación de SQL Server, use las opciones -U y -P para especificar el nombre de usuario y la contraseña, respectivamente. |
-d |
Nombre de la base de datos, para este ejemplo AdventureWorks2025. |
-Q |
Instrucción T-SQL que se va a ejecutar. |
-n |
Número de conexiones que procesan cada archivo o consulta de entrada. |
-r |
Número de iteraciones para cada conexión para ejecutar cada archivo o consulta de entrada. |
Tarea de demostración
El procedimiento almacenado principal que se usa en la carga de trabajo de demostración es Sales.usp_InsertSalesOrder_inmem/ondisk. El script del ejemplo siguiente construye un parámetro con valores de tabla (TVP) con datos de ejemplo y llama al procedimiento para insertar un pedido de ventas con cinco elementos de línea.
La herramienta ostress se usa para ejecutar las llamadas a procedimientos almacenados en paralelo, para simular que los clientes insertan pedidos de ventas simultáneamente.
Restablezca la demostración después de cada prueba de esfuerzo ejecutando Demo.usp_DemoReset. Este procedimiento elimina las filas de las tablas optimizadas para memoria, trunca las tablas basadas en disco y ejecuta un punto de comprobación de la base de datos.
El script siguiente se ejecuta simultáneamente para simular una carga de trabajo de procesamiento de pedidos de venta:
DECLARE @i AS INT = 0, @od AS Sales.SalesOrderDetailType_inmem, @SalesOrderID AS INT, @DueDate AS DATETIME2 = sysdatetime(), @CustomerID AS INT = RAND() * 8000, @BillToAddressID AS INT = RAND() * 10000, @ShipToAddressID AS INT = RAND() * 10000, @ShipMethodID AS INT = (RAND() * 5) + 1;
INSERT INTO @od
SELECT OrderQty,
ProductID,
SpecialOfferID
FROM Demo.DemoSalesOrderDetailSeed
WHERE OrderID = CAST ((RAND() * 106) + 1 AS INT);
WHILE (@i < 20)
BEGIN
EXECUTE Sales.usp_InsertSalesOrder_inmem
@SalesOrderID OUTPUT,
@DueDate,
@CustomerID,
@BillToAddressID,
@ShipToAddressID,
@ShipMethodID,
@od;
SET @i + = 1;
END
Con este script, cada pedido de ejemplo que se crea se inserta 20 veces, mediante 20 procedimientos almacenados que se ejecutan en un bucle WHILE. El bucle se usa para tener en cuenta el hecho de que la base de datos se emplea para crear el pedido de ejemplo. En entornos de producción típicos, la aplicación de nivel medio construye el pedido de ventas que se va a insertar.
El script anterior inserta pedidos de ventas en tablas optimizadas para memoria. El script para insertar pedidos de ventas en tablas basadas en disco se deriva reemplazando las dos apariciones de _inmem por _ondisk.
Usamos la herramienta ostress para ejecutar los scripts mediante varias conexiones simultáneas. Usamos el parámetro -n para controlar el número de conexiones y el parámetro r para controlar cuántas veces se ejecuta el script en cada conexión.
Ejecuta la carga de trabajo
Para probar la escala insertamos 10 millones de pedidos de venta usando 100 conexiones. Esta prueba funciona razonablemente bien en un servidor modesto (por ejemplo, 8 núcleos físicos y 16 lógicos) y con un almacenamiento SSD básico para el registro. Si la prueba no funciona bien en el hardware, eche un vistazo a la sección Solución de problemas de pruebas de ejecución lenta. Si desea reducir el nivel de esfuerzo de esta prueba, reduzca el número de conexiones cambiando el parámetro -n. Por ejemplo, para reducir el número de conexiones a 40, cambie el parámetro -n100 a -n40.
Como medida de rendimiento para la carga de trabajo, usamos el tiempo transcurrido informado por ostress.exe después de ejecutar la carga de trabajo.
Las instrucciones y mediciones siguientes usan una carga de trabajo que inserta 10 millones de órdenes de venta. Para obtener instrucciones para ejecutar una carga de trabajo reducida que inserta 1 millón de pedidos de venta, consulte las instrucciones en In-Memory OLTP\readme.txt que es parte del archivo SQLServer2016Samples.zip.
Tablas optimizadas para memoria
Comenzamos ejecutando la carga de trabajo en tablas optimizadas para memoria. El comando siguiente abre 100 subprocesos, cada uno de los cuales se ejecuta para 5.000 iteraciones. Cada iteración inserta 20 pedidos de venta en transacciones diferentes. Hay 20 inserciones por iteración para compensar el hecho de que la base de datos se usa para generar los datos que se van a insertar. Esto produce un total de 20 * 5000 * 100 = 10 000 000 inserciones de pedidos de venta.
Abra el RML Cmd Prompt y ejecute el siguiente comando:
Seleccione el botón Copy (Copiar) para copiar el comando y péguelo en el símbolo del sistema de las utilidades de RML.
ostress.exe -n100 -r5000 -S. -E -dAdventureWorks2022 -q -Q"DECLARE @i AS INT = 0, @od AS Sales.SalesOrderDetailType_inmem, @SalesOrderID AS INT, @DueDate AS DATETIME2 = SYSDATETIME(), @CustomerID AS INT = RAND() * 8000, @BillToAddressID AS INT = RAND() * 10000, @ShipToAddressID AS INT = RAND() * 10000, @ShipMethodID AS INT = (RAND() * 5) + 1; INSERT INTO @od SELECT OrderQty, ProductID, SpecialOfferID FROM Demo.DemoSalesOrderDetailSeed WHERE OrderID = CAST ((RAND() * 106) + 1 AS INT); WHILE (@i < 20) BEGIN EXECUTE Sales.usp_InsertSalesOrder_inmem @SalesOrderID OUTPUT, @DueDate, @CustomerID, @BillToAddressID, @ShipToAddressID, @ShipMethodID, @od; SET @i + = 1; END"
En un servidor de prueba con un número total de 8 núcleos físicos (16 lógicos), se tardaron 2 minutos y 5 segundos. En un segundo servidor de prueba con 24 núcleos físicos (48 lógicos), se tardó 1 minuto y 0 segundos.
Observe el uso de la CPU mientras se está ejecutando la carga de trabajo, por ejemplo con el Administrador de tareas. Verá que el uso de cpu está cerca de 100%. Si este no es el caso, tiene un cuello de botella de entrada/salida de registros. Consulte también Resolver problemas de pruebas de ejecución lenta.
Tablas basadas en disco
El comando siguiente ejecuta la carga de trabajo en tablas basadas en disco. Esta carga de trabajo puede tardar un tiempo en ejecutarse, lo que en gran medida se debe a la contención de cerrojos en el sistema. Las tablas optimizadas para memoria no tienen bloqueos temporales y, por tanto, no sufren este problema.
Abra RML Cmd Prompt y ejecute el comando siguiente:
Seleccione el botón Copy (Copiar) para copiar el comando y péguelo en el símbolo del sistema de las utilidades de RML.
ostress.exe -n100 -r5000 -S. -E -dAdventureWorks2022 -q -Q"DECLARE @i AS INT = 0, @od AS Sales.SalesOrderDetailType_ondisk, @SalesOrderID AS INT, @DueDate AS DATETIME2 = sysdatetime(), @CustomerID AS INT = RAND() * 8000, @BillToAddressID AS INT = RAND() * 10000, @ShipToAddressID AS INT = RAND() * 10000, @ShipMethodID AS INT = (RAND() * 5) + 1; INSERT INTO @od SELECT OrderQty, ProductID, SpecialOfferID FROM Demo.DemoSalesOrderDetailSeed WHERE OrderID = CAST ((RAND() * 106) + 1 AS INT); WHILE (@i < 20) BEGIN EXECUTE Sales.usp_InsertSalesOrder_ondisk @SalesOrderID OUTPUT, @DueDate, @CustomerID, @BillToAddressID, @ShipToAddressID, @ShipMethodID, @od; SET @i + = 1; END"
En un servidor de prueba con un número total de 8 núcleos físicos (16 lógicos), se tardaron 41 minutos y 25 segundos. En un segundo servidor de prueba con 24 núcleos físicos (48 lógicos), se tardaron 52 minutos y 16 segundos.
El factor principal de la diferencia de rendimiento entre las tablas optimizadas para memoria y las tablas basadas en disco en esta prueba es que cuando se usan tablas basadas en disco, SQL Server no puede usar completamente la CPU. El motivo es la contención de bloqueos temporales: las transacciones simultáneas intentan escribir en la misma página de datos; los bloqueos temporales se usan para asegurarse de que solo una transacción puede escribir en una página a la vez. El motor OLTP de In-Memory está libre de bloqueos temporales y las filas de datos no se organizan en páginas. Por lo tanto, las transacciones simultáneas no bloquean las inserciones entre sí, lo que permite que SQL Server use completamente la CPU.
Puede observar el uso de la CPU mientras se está ejecutando la carga de trabajo, por ejemplo con el Administrador de tareas. Verá con las tablas basadas en disco que el uso de cpu está lejos de 100%. En una configuración de prueba con 16 procesadores lógicos, el uso rondaría el 24 %.
Opcionalmente, puede ver el número de tiempos de espera de bloqueo temporal por segundo mediante el Monitor de rendimiento, con el contador de rendimiento \SQL Server:Latches\Latch Waits/sec.
Restablecer la demostración
Para restablecer la demostración, abra RML Cmd Prompt y ejecute el comando siguiente:
ostress.exe -S. -E -dAdventureWorks2022 -Q"EXEC Demo.usp_DemoReset"
En función del hardware, esto puede tardar unos minutos en ejecutarse.
Se recomienda restablecer la demostración tras cada ejecución. Dado que esta carga de trabajo es de solo inserción, cada ejecución consume más memoria y, por tanto, se requiere un restablecimiento para evitar que se agote la memoria. La cantidad de memoria consumida después de una ejecución se explica en la sección Utilización de memoria después de ejecutar la carga de trabajo.
Solución de problemas de pruebas de ejecución lenta
Los resultados de las pruebas suelen variar con hardware y también el nivel de simultaneidad que se usa en la ejecución de pruebas. Un par de cosas que se deben buscar si los resultados no son los esperados:
Número de transacciones simultáneas: al ejecutar la carga de trabajo en un único subproceso, es probable que la ganancia de rendimiento con In-Memory OLTP sea menor que 2X. La contención de cerrojos solo representa un problema importante si hay un alto nivel de concurrencia.
Número bajo de núcleos disponibles para SQL Server: esto significa que hay un bajo nivel de simultaneidad en el sistema, ya que solo puede haber tantas transacciones que se ejecuten simultáneamente como hay núcleos disponibles para SQL.
- Síntoma: si el uso del CPU es elevado al ejecutar la carga de trabajo en tablas en disco, esto significa que no hay mucha contención, lo que señala una falta de concurrencia.
Velocidad de la unidad de registro: si la unidad de registro no logra manejar la cantidad de transacciones en el sistema, la carga de trabajo se convierte en un cuello de botella en la E/S de la unidad de registro. Aunque el registro es más eficaz con OLTP en memoria, si la E/S de registro es un cuello de botella, se limita el aumento potencial de rendimiento.
- Síntoma: si la utilización de la CPU no está cerca del 100% o es muy variable al ejecutar la carga de trabajo en tablas optimizadas para memoria, puede haber un cuello de botella de E/S en el registro. Esto se puede confirmar abriendo el Monitor de recursos y examinando la longitud de la cola de la unidad de registro.
Uso de memoria y espacio en disco en el ejemplo
En el ejemplo siguiente, se describe qué esperar en términos de uso de espacio en disco y memoria para la base de datos de ejemplo. También se muestran los resultados de en un servidor de prueba con 16 núcleos lógicos.
Uso de memoria para las tablas optimizadas para memoria
Utilización global de la base de datos
Se puede usar la consulta siguiente para obtener la utilización de memoria total para OLTP en memoria en el sistema.
SELECT type,
name,
pages_kb / 1024 AS pages_MB
FROM sys.dm_os_memory_clerks
WHERE type LIKE '%xtp%';
Instantánea justo después de crearse la base de datos:
| type | nombre | pages_MB |
|---|---|---|
| MEMORYCLERK_XTP | Valor predeterminado | 94 |
| MEMORYCLERK_XTP | DB_ID_5 | 877 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
Los distribuidores de memoria predeterminados contienen estructuras de memoria de todo el sistema y son relativamente pequeños. El encargado de memoria de la base de datos de usuario, en este caso, la base de datos con el identificador 5 (el database_id puede diferir en su instancia), es de aproximadamente 900 MB.
Utilización de memoria por tabla
Se puede usar la consulta siguiente para explorar en profundidad la utilización de memoria de las tablas individuales y sus índices:
SELECT object_name(t.object_id) AS [Table name],
memory_allocated_for_table_kb,
memory_allocated_for_indexes_kb
FROM sys.dm_db_xtp_table_memory_stats AS dms
INNER JOIN sys.tables AS t
ON dms.object_id = t.object_id
WHERE t.type = 'U';
La tabla siguiente muestra los resultados de esta consulta para una instalación nueva del ejemplo:
| Nombre de la tabla | memory_allocated_for_table_kb |
memory_allocated_for_indexes_kb |
|---|---|---|
SpecialOfferProduct_inmem |
64 | 3840 |
DemoSalesOrderHeaderSeed |
1984 | 5,504 |
SalesOrderDetail_inmem |
15316 | 663552 |
DemoSalesOrderDetailSeed |
64 | 10432 |
SpecialOffer_inmem |
3 | 8192 |
SalesOrderHeader_inmem |
7168 | 147456 |
Product_inmem |
124 | 12352 |
Como puede ver, las tablas son bastante pequeñas: SalesOrderHeader_inmem es de aproximadamente 7 MB y SalesOrderDetail_inmem tiene aproximadamente 15 MB de tamaño.
Lo sorprendente aquí es el tamaño de la memoria asignada para los índices, en comparación con el tamaño de los datos de tabla. Esto se debe a que los índices hash del ejemplo están predimensionados para un tamaño de datos mayor. Los índices hash tienen un tamaño fijo y, por tanto, su tamaño no crece con el tamaño de los datos de la tabla.
Utilización de memoria después de ejecutar la carga de trabajo
Después de insertar 10 millones de pedidos de ventas, el uso de memoria total es similar a la siguiente consulta:
SELECT type,
name,
pages_kb / 1024 AS pages_MB
FROM sys.dm_os_memory_clerks
WHERE type LIKE '%xtp%';
Este es el conjunto de resultados.
type |
name |
pages_MB |
|---|---|---|
| MEMORYCLERK_XTP | Valor predeterminado | 146 |
| MEMORYCLERK_XTP | DB_ID_5 | 7374 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
Como puede ver, SQL Server usa un bit por debajo de 8 GB para las tablas y los índices optimizados para memoria de la base de datos de ejemplo.
Examinando el uso detallado de memoria por tabla después de ejecutar un ejemplo:
SELECT object_name(t.object_id) AS [Table name],
memory_allocated_for_table_kb,
memory_allocated_for_indexes_kb
FROM sys.dm_db_xtp_table_memory_stats AS dms
INNER JOIN sys.tables AS t
ON dms.object_id = t.object_id
WHERE t.type = 'U';
Este es el conjunto de resultados.
Table name |
memory_allocated_for_table_kb |
memory_allocated_for_indexes_kb |
|---|---|---|
| SalesOrderDetail_inmem | 5113761 | 663552 |
| DemoSalesOrderDetailSeed | 64 | 10368 |
| SpecialOffer_inmem | 2 | 8192 |
| SalesOrderHeader_inmem | 1575679 | 147456 |
| Product_inmem | 111 | 12032 |
| SpecialOfferProduct_inmem | 64 | 3712 |
| DemoSalesOrderHeaderSeed | 1984 | 5,504 |
Podemos ver un total de unos 6,5 GB de datos. El tamaño de los índices de la tabla SalesOrderHeader_inmem y SalesOrderDetail_inmem es el mismo que el tamaño de los índices antes de insertar los pedidos de ventas. El tamaño del índice no cambió porque ambas tablas usan índices hash y los índices hash son estáticos.
Después de restablecer la demostración
Se puede usar el procedimiento almacenado Demo.usp_DemoReset para restablecer la demostración. Elimina los datos de las tablas SalesOrderHeader_inmem y SalesOrderDetail_inmem, y vuelve a reseccionar los datos de las tablas originales SalesOrderHeader y SalesOrderDetail.
Ahora, aunque se eliminaron las filas de las tablas, esto no significa que la memoria se recupere inmediatamente. SQL Server recupera memoria de las filas eliminadas de las tablas optimizadas para memoria en segundo plano, según sea necesario. Verá que inmediatamente después del reinicio de la demostración, sin ninguna carga de trabajo transaccional en el sistema, la memoria de las filas eliminadas aún no se ha recuperado:
SELECT type,
name,
pages_kb / 1024 AS pages_MB
FROM sys.dm_os_memory_clerks
WHERE type LIKE '%xtp%';
Este es el conjunto de resultados.
type |
name |
pages_MB |
|---|---|---|
| MEMORYCLERK_XTP | Valor predeterminado | 2261 |
| MEMORYCLERK_XTP | DB_ID_5 | 7396 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
Esto se espera: la memoria se recupera cuando se ejecuta la carga de trabajo transaccional.
Si inicia una segunda ejecución de la carga de trabajo de demostración, verá que el uso de memoria disminuye inicialmente, ya que las filas eliminadas anteriormente se limpian. En algún momento, el tamaño de memoria aumenta de nuevo hasta que finaliza la carga de trabajo. Después de insertar 10 millones de filas tras el restablecimiento de la demostración, el uso de la memoria es muy similar al uso después de la primera ejecución. Por ejemplo:
SELECT type,
name,
pages_kb / 1024 AS pages_MB
FROM sys.dm_os_memory_clerks
WHERE type LIKE '%xtp%';
Este es el conjunto de resultados.
type |
name |
pages_MB |
|---|---|---|
| MEMORYCLERK_XTP | Valor predeterminado | 1,863 |
| MEMORYCLERK_XTP | DB_ID_5 | 7390 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
| MEMORYCLERK_XTP | Valor predeterminado | 0 |
Uso de disco para las tablas optimizadas para memoria
El tamaño total en disco de los archivos de punto de comprobación de una base de datos en un momento dado se puede averiguar con la consulta:
SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]
FROM sys.filegroups AS f
INNER JOIN sys.database_files AS df
ON f.data_space_id = df.data_space_id
WHERE f.type = N'FX';
Estado inicial
Cuando se crean inicialmente el grupo de archivos de ejemplo y las tablas optimizadas para memoria de ejemplo, se crean previamente varios archivos de punto de control y el sistema comienza a rellenar los archivos: el número de archivos de punto de control creados previamente depende del número de procesadores lógicos del sistema. Como el ejemplo es inicialmente muy pequeño, los archivos creados previamente están principalmente vacíos después de la creación inicial.
El código siguiente muestra el tamaño inicial en disco del ejemplo en un equipo con 16 procesadores lógicos:
SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]
FROM sys.filegroups AS f
INNER JOIN sys.database_files AS df
ON f.data_space_id = df.data_space_id
WHERE f.type = N'FX';
Este es el conjunto de resultados.
| Tamaño en disco en MB |
|---|
| 2312 |
Como puede ver, hay una gran discrepancia entre el tamaño en disco de los archivos de punto de control, que es de 2,3 GB y el tamaño real de los datos, que está más cerca de 30 MB.
Para examinar más de cerca de dónde procede la utilización de espacio en disco, puede usar la consulta siguiente. El tamaño del disco devuelto por esta consulta es aproximado en el caso de los archivos que tienen el estado 5 (REQUIRED FOR BACKUP/HA), 6 (IN TRANSITION TO TOMBSTONE) o 7 (TOMBSTONE).
SELECT state_desc,
file_type_desc,
COUNT(*) AS [count],
SUM(CASE WHEN state = 5 AND file_type = 0 THEN 128 * 1024 * 1024
WHEN state = 5 AND file_type = 1 THEN 8 * 1024 * 1024
WHEN state IN (6, 7) THEN 68 * 1024 * 1024
ELSE file_size_in_bytes END) / 1024 / 1024 AS [on-disk size MB]
FROM sys.dm_db_xtp_checkpoint_files
GROUP BY state, state_desc, file_type, file_type_desc
ORDER BY state, file_type;
Para el estado inicial del ejemplo, el resultado es similar a la siguiente tabla para un servidor con 16 procesadores lógicos:
| state_desc | file_type_desc | count | Tamaño en disco en MB |
|---|---|---|---|
| PRECREATED | DATOS | 16 | 2048 |
| PRECREATED | DELTA | 16 | 128 |
| EN OBRA | DATOS | 1 | 128 |
| EN OBRA | DELTA | 1 | 8 |
Como puede ver, la mayor parte del espacio la usan archivos de datos y delta creados previamente. SQL Server precreó un par de archivos (datos, delta) por procesador lógico. Además, los archivos de datos están predimensionados a 128 MB y los archivos delta a 8 MB, con el fin de que la inserción de datos en estos archivos sea más eficaz.
Los datos reales de las tablas optimizadas para memoria están en el archivo de datos.
Después de ejecutar la carga de trabajo
Después de una única serie de pruebas que inserta 10 millones de pedidos de venta, el tamaño total en disco es similar al siguiente (para un servidor de prueba de 16 núcleos):
SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]
FROM sys.filegroups AS f
INNER JOIN sys.database_files AS df
ON f.data_space_id = df.data_space_id
WHERE f.type = N'FX';
Este es el conjunto de resultados.
| Tamaño en disco en MB |
|---|
| 8828 |
El tamaño en disco es cercano a 9 GB, que es parecido al tamaño en memoria de los datos.
Si examinamos más de cerca los tamaños de los archivos de punto de comprobación en los distintos estados:
SELECT state_desc,
file_type_desc,
COUNT(*) AS [count],
SUM(CASE WHEN state = 5 AND file_type = 0 THEN 128 * 1024 * 1024
WHEN state = 5 AND file_type = 1 THEN 8 * 1024 * 1024
WHEN state IN (6, 7) THEN 68 * 1024 * 1024
ELSE file_size_in_bytes END) / 1024 / 1024 AS [on-disk size MB]
FROM sys.dm_db_xtp_checkpoint_files
GROUP BY state, state_desc, file_type, file_type_desc
ORDER BY state, file_type;
Este es el conjunto de resultados.
state_desc |
file_type_desc |
count |
on-disk size MB |
|---|---|---|---|
| PRECREATED | DATOS | 16 | 2048 |
| PRECREATED | DELTA | 16 | 128 |
| EN OBRA | DATOS | 1 | 128 |
| EN OBRA | DELTA | 1 | 8 |
Todavía tenemos 16 pares de archivos creados previamente, listos para ir a medida que se cierran los puntos de control.
Hay un par en construcción, que se usa hasta que se cierra el punto de control actual. Junto con los archivos de punto de comprobación activos, esto nos da unos 6,5 GB de uso de disco para 6,5 GB de datos en memoria. Recuerde que los índices no se conservan en el disco y, por tanto, el tamaño general del disco es menor que el tamaño en la memoria en este caso.
Después de restablecer la demostración
Después del restablecimiento de demostración, el espacio en disco no se reclama inmediatamente si no hay ninguna carga de trabajo transaccional en el sistema y no hay puntos de comprobación de base de datos. Para que los archivos de punto de control se muevan a través de sus distintas fases y finalmente se descarten, es necesario que se produzcan varios puntos de control y eventos de truncamiento de registros, para iniciar la combinación de archivos de punto de control, así como para iniciar la recolección de elementos no utilizados. Esto sucede automáticamente si tiene una carga de trabajo transaccional en el sistema (y realiza copias de seguridad de registros normales, en caso de que use el modelo de recuperación COMPLETA), pero no cuando el sistema esté inactivo, como en un escenario de demostración.
En el ejemplo, después del reinicio de la demostración, podría ver algo como:
SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]
FROM sys.filegroups AS f
INNER JOIN sys.database_files AS df
ON f.data_space_id = df.data_space_id
WHERE f.type = N'FX';
Este es el conjunto de resultados.
| Tamaño en disco en MB |
|---|
| 11839 |
Con casi 12 GB, esto es mucho más significativo que los 9 GB teníamos antes de restablecer la demostración. Esto se debe a que se iniciaron algunas combinaciones de archivos de punto de control, pero algunos de los destinos de combinación aún no se han instalado y algunos de los archivos de origen de combinación aún no se han limpiado, como se puede ver en el ejemplo siguiente:
SELECT state_desc,
file_type_desc,
COUNT(*) AS [count],
SUM(CASE WHEN state = 5 AND file_type = 0 THEN 128 * 1024 * 1024
WHEN state = 5 AND file_type = 1 THEN 8 * 1024 * 1024
WHEN state IN (6, 7) THEN 68 * 1024 * 1024
ELSE file_size_in_bytes END) / 1024 / 1024 AS [on-disk size MB]
FROM sys.dm_db_xtp_checkpoint_files
GROUP BY state, state_desc, file_type, file_type_desc
ORDER BY state, file_type;
Este es el conjunto de resultados.
state_desc |
file_type_desc |
count |
on-disk size MB |
|---|---|---|---|
| PRECREATED | DATOS | 16 | 2048 |
| PRECREATED | DELTA | 16 | 128 |
| ACTIVO | DATOS | 38 | 5152 |
| ACTIVO | DELTA | 38 | 1331 |
| OBJETIVO DE FUSIÓN | DATOS | 7 | 896 |
| OBJETIVO DE FUSIÓN | DELTA | 7 | 56 |
| ORIGEN COMBINADO | DATOS | 13 | 1,772 |
| ORIGEN COMBINADO | DELTA | 13 | 4:55 |
Los destinos de mezcla se instalan y el origen de mezcla se limpia mientras la realiza actividad transaccional en el sistema.
Después de una segunda ejecución de la carga de trabajo de prueba, insertando 10 millones de órdenes de venta tras el reinicio de la demostración, puede ver que los archivos construidos durante la primera ejecución de la carga de trabajo fueron limpiados. Si ejecuta la consulta anterior varias veces mientras se ejecuta la carga de trabajo, puede ver que los archivos de punto de control pasan por las distintas fases.
Después de la segunda ejecución de la carga de trabajo, inserte 10 millones de pedidos de ventas, verá que el uso del disco es muy similar, aunque no necesariamente igual que después de la primera ejecución, ya que el sistema es dinámico por naturaleza. Por ejemplo:
SELECT state_desc,
file_type_desc,
COUNT(*) AS [count],
SUM(CASE WHEN state = 5 AND file_type = 0 THEN 128 * 1024 * 1024
WHEN state = 5 AND file_type = 1 THEN 8 * 1024 * 1024
WHEN state IN (6, 7) THEN 68 * 1024 * 1024
ELSE file_size_in_bytes END) / 1024 / 1024 AS [on-disk size MB]
FROM sys.dm_db_xtp_checkpoint_files
GROUP BY state, state_desc, file_type, file_type_desc
ORDER BY state, file_type;
Este es el conjunto de resultados.
state_desc |
file_type_desc |
count |
on-disk size MB |
|---|---|---|---|
| PRECREATED | DATOS | 16 | 2048 |
| PRECREATED | DELTA | 16 | 128 |
| EN OBRA | DATOS | 2 | 268 |
| EN OBRA | DELTA | 2 | 16 |
| ACTIVO | DATOS | 41 | 5608 |
| ACTIVO | DELTA | 41 | 328 |
En este caso, hay dos pares de archivos de punto de control en el UNDER CONSTRUCTION estado, lo que significa que se han movido varios pares de archivos al UNDER CONSTRUCTION estado, probablemente debido al alto nivel de simultaneidad en la carga de trabajo. Varios subprocesos simultáneos requerían un nuevo par de archivos al mismo tiempo y, por tanto, mueven un par de PRECREATED a UNDER CONSTRUCTION.