Estimar los requisitos de memoria para las tablas con optimización para memoriaEstimate Memory Requirements for Memory-Optimized Tables

SE APLICA A: síSQL Server síAzure SQL Database noAzure SQL Data Warehouse noAlmacenamiento de datos paralelos APPLIES TO: yesSQL Server yesAzure SQL Database noAzure SQL Data Warehouse noParallel Data Warehouse

Las tablas con optimización para memoria requieren que exista memoria suficiente para mantener todas las filas e índices en memoria.Memory-optimized tables require that sufficient memory exist to keep all of the rows and indexes in memory. Dado que la memoria es un recurso finito, es importante que conozca y administre el uso que hace de la memoria en su sistema.Because memory is a finite resource, it is important that you understand and manage memory usage on your system. Los temas de esta sección se ocupan de situaciones de uso y administración de la memoria.The topics in this section cover common memory use and management scenarios.

Si va a crear una tabla optimizada para memoria o va a migrar una tabla basada en disco existente a una tabla optimizada para memoria de OLTP en memoriaIn-Memory OLTP, es importante tener una estimación razonable de las necesidades de memoria de cada tabla para poder aprovisionar el servidor con la memoria suficiente.Whether you are creating a new memory-optimized table or migrating an existing disk-based table to an OLTP en memoriaIn-Memory OLTP memory-optimized table, it is important to have a reasonable estimate of each table's memory needs so you can provision the server with sufficient memory. En esta sección se describe cómo calcular la cantidad de memoria necesaria para almacenar los datos de una tabla optimizada para memoria.This section describes how to estimate the amount of memory that you need to hold data for a memory-optimized table.

Si va a realizar la migración desde tablas basadas en disco a tablas optimizadas para memoria, antes de continuar en este tema, vea el tema Determinar si una tabla o un procedimiento almacenado se debe pasar a OLTP en memoria para obtener información sobre qué tablas son más adecuadas para la migración.If you are contemplating migrating from disk-based tables to memory-optimized tables, before you proceed in this topic, see the topic Determining if a Table or Stored Procedure Should Be Ported to In-Memory OLTP for guidance on which tables are best to migrate. Todos los temas de Migrar a OLTP en memoria ofrecen instrucciones sobre la migración de tablas basadas en disco a tablas optimizadas para memoria.All the topics under Migrating to In-Memory OLTP provide guidance on migrating from disk-based to memory-optimized tables.

Instrucciones básicas para estimar los requisitos de memoriaBasic Guidance for Estimating Memory Requirements

A partir de SQL Server 2016 (13.x)SQL Server 2016 (13.x), no existe límite en el tamaño de las tablas optimizadas para memoria, aunque estas deben adaptarse a la memoria.Starting with SQL Server 2016 (13.x)SQL Server 2016 (13.x), there is no limit on the size of memory-optimized tables, though the tables do need to fit in memory. En SQL Server 2014 (12.x)SQL Server 2014 (12.x) , el tamaño de datos admitido es de 256 GB para las tablas SCHEMA_AND_DATA.In SQL Server 2014 (12.x)SQL Server 2014 (12.x) the supported data size is 256GB for SCHEMA_AND_DATA tables.

El tamaño de una tabla optimizada para memoria corresponde al tamaño de los datos más alguna sobrecarga de los encabezados de fila.The size of a memory-optimized table corresponds to the size of data plus some overhead for row headers. Al migrar una tabla basada en disco a una optimizada para memoria, el tamaño de la tabla optimizada para memoria corresponderá aproximadamente al tamaño del índice agrupado o al montón de la tabla original basada en disco.When migrating a disk-based table to memory-optimized, the size of the memory-optimized table will roughly correspond to the size of the clustered index or heap of the original disk-based table.

Los índices de las tablas optimizadas para memoria tienden a ser más pequeños que los índices no agrupados de las tablas basadas en disco.Indexes on memory-optimized tables tend to be smaller than nonclustered indexes on disk-based tables. El tamaño de los índices no agrupados está en el orden de [primary key size] * [row count].The size of nonclustered indexes is in the order of [primary key size] * [row count]. El tamaño de los índices de hash es [bucket count] * 8 bytes.The size of hash indexes is [bucket count] * 8 bytes.

Cuando existe una carga de trabajo activa, se necesita tener en cuenta la memoria adicional para las versiones de fila y para diversas operaciones.When there is an active workload, additional memory is needed to account for row versioning and various operations. La cantidad de memoria que se necesita en la práctica depende de la carga de trabajo, pero para no tener problemas la recomendación es empezar con dos veces el tamaño esperado de las tablas e índices optimizados para memoria y observar cuáles son los requisitos de memoria en realidad.How much memory is needed in practice depends on the workload, but to be safe the recommendation is to start with two times the expected size of memory-optimized tables and indexes, and observe what are the memory requirements in practice. La sobrecarga de las versiones de fila siempre depende de las características de la carga de trabajo; especialmente las transacciones de larga ejecución aumentan la sobrecarga.The overhead for row versioning always depends on the characteristics of the workload - especially long-running transactions increase the overhead. Para la mayoría de cargas de trabajo que usan bases de datos más grandes (por ejemplo, más de 100 GB), la sobrecarga tiende a limitarse (25 % o menos).For most workloads using larger databases (e.g., >100GB), overhead tends to be limited (25% or less).

Cálculo detallado de los requisitos de memoriaDetailed Computation of Memory Requirements

tabla optimizada para memoria de ejemploExample memory-optimized table

Considere el esquema de tabla optimizada para memoria siguiente:Consider the following memory-optimized table schema:

CREATE TABLE t_hk
(  
  col1 int NOT NULL  PRIMARY KEY NONCLUSTERED,  

  col2 int NOT NULL  INDEX t1c2_index   
      HASH WITH (bucket_count = 5000000),  

  col3 int NOT NULL  INDEX t1c3_index   
      HASH WITH (bucket_count = 5000000),  

  col4 int NOT NULL  INDEX t1c4_index   
      HASH WITH (bucket_count = 5000000),  

  col5 int NOT NULL  INDEX t1c5_index NONCLUSTERED,  

  col6 char (50) NOT NULL,  
  col7 char (50) NOT NULL,   
  col8 char (30) NOT NULL,   
  col9 char (50) NOT NULL  

)   WITH (memory_optimized = on)  ;
GO  

Con este esquema determinaremos la memoria mínima necesaria para esta tabla optimizada para memoria.Using this schema we will determine the minimum memory needed for this memory-optimized table.

Memoria para la tablaMemory for the table

Una fila de una tabla optimizada para memoria consta de tres partes:A memory-optimized table row is comprised of three parts:

  • Marcas de tiempo Timestamps
    Encabezado de fila/marcas de tiempo = 24 bytes.Row header/timestamps = 24 bytes.

  • Punteros de índice Index pointers
    Para cada índice hash de la tabla, cada fila tiene un puntero de direcciones de 8 bytes a la siguiente fila del índice.For each hash index in the table, each row has an 8-byte address pointer to the next row in the index. Puesto que hay 4 índices, cada fila asignará 32 bytes para los punteros de índice (un puntero de 8 bytes para cada índice).Since there are 4 indexes, each row will allocate 32 bytes for index pointers (an 8 byte pointer for each index).

  • Datos Data
    El tamaño de la parte de datos de la fila se determina sumando el tamaño del tipo de cada columna de datos.The size of the data portion of the row is determined by summing the type size for each data column. En nuestra tabla tenemos cinco enteros de 4 bytes, tres columnas de caracteres de 50 bytes y una columna de caracteres de 30 bytes.In our table we have five 4-byte integers, three 50-byte character columns, and one 30-byte character column. Por tanto, la parte de datos de cada fila es 4 + 4 + 4 + 4 + 4 + 50 + 50 + 30 + 50 o 200 bytes.Therefore the data portion of each row is 4 + 4 + 4 + 4 + 4 + 50 + 50 + 30 + 50 or 200 bytes.

A continuación se muestra un cálculo de tamaño para 5.000.000 filas (5 millones de filas) en una tabla optimizada para memoria:The following is a size computation for 5,000,000 (5 million) rows in a memory-optimized table. La memoria total utilizada por las filas de datos se calcula de la forma siguiente:The total memory used by data rows is estimated as follows:

Memoria para las filas de la tablaMemory for the table's rows

Según se desprende de los cálculos anteriores, el tamaño de cada fila de la tabla optimizada para memoria es 24 + 32 + 200, o 256 bytes.From the above calculations, the size of each row in the memory-optimized table is 24 + 32 + 200, or 256 bytes. Como tenemos 5 millones de filas, la tabla usará 5 000 000 * 256 bytes, o 1 280 000 000 bytes, aproximadamente 1,28 GB.Since we have 5 million rows, the table will consume 5,000,000 * 256 bytes, or 1,280,000,000 bytes - approximately 1.28 GB.

Memoria para índicesMemory for indexes

Memoria para cada índice hashMemory for each hash index

Cada índice hash es una matriz hash de punteros de direcciones de 8 bytes.Each hash index is a hash array of 8-byte address pointers. El tamaño de la matriz se determina mejor con el número de valores de índice único para ese índice; por ejemplo, el número de valores únicos Col2 es un buen punto de partida para el tamaño de matriz de t1c2_index.The size of the array is best determined by the number of unique index values for that index - e.g., the number of unique Col2 values is a good starting point for the array size for the t1c2_index. Una matriz hash que es demasiado grande desperdicia memoria.A hash array that is too big wastes memory. Una matriz hash que es demasiado pequeña reduce el rendimiento, ya que habrá demasiadas colisiones de valores de índice que aplican el algoritmo hash al mismo índice.A hash array that is too small slows performance since there will be too many collisions by index values that hash to the same index.

Los índices hash consiguen búsquedas de igualdad muy rápidas, por ejemplo:Hash indexes achieve very fast equality lookups such as:

SELECT * FROM t_hk  
   WHERE Col2 = 3;

Los índices no clúster son más rápidos para búsquedas de intervalo como:Nonclustered indexes are faster for range lookups such as:

SELECT * FROM t_hk  
   WHERE Col2 >= 3;

Si va a migrar una tabla basada en disco, puede usar lo siguiente para determinar el número de valores únicos para el índice t1c2_index.If you are migrating a disk-based table you can use the following to determine the number of unique values for the index t1c2_index.

SELECT COUNT(DISTINCT [Col2])  
  FROM t_hk;

Si va a crear una tabla, tendrá que estimar el tamaño de la matriz o recopilar datos de la prueba antes de la implementación.If you are creating a new table, you'll need to estimate the array size or gather data from your testing prior to deployment.

Para obtener información sobre cómo funcionan los índices de hash en las tablas optimizadas para memoria de OLTP en memoriaIn-Memory OLTP , vea Indexes for Memory-Optimized Tables (Índices para tablas optimizadas para memoria).For information on how hash indexes work in OLTP en memoriaIn-Memory OLTP memory-optimized tables, see Hash Indexes.

Establecer el tamaño de la matriz de índices hashSetting the hash index array size

El tamaño de la matriz hash se establece mediante (bucket_count= value) donde value es un valor entero mayor que cero.The hash array size is set by (bucket_count= value) where value is an integer value greater than zero. Si value no es una potencia de 2, el valor real de bucket_count se redondea a la siguiente potencia más cercana de 2.If value is not a power of 2, the actual bucket_count is rounded up to the next closest power of 2. En la tabla de ejemplo (bucket_count = 5000000), como 5 000 000 no es una potencia de 2, el número de cubos real se redondea hasta 8 388 608 (2^23).In our example table, (bucket_count = 5000000), since 5,000,000 is not a power of 2, the actual bucket count rounds up to 8,388,608 (2^23). Debe usar este número, no 5.000.000, al calcular la memoria necesaria para la matriz hash.You must use this number, not 5,000,000 when calculating memory needed by the hash array.

Así, en nuestro ejemplo, la memoria necesaria para cada matriz hash es:Thus, in our example, the memory needed for each hash array is:

8 388 608 * 8 = 2^23 * 8 = 2^23 * 2^3 = 2^26 = 67 108 864 o, aproximadamente, 64 MB.8,388,608 * 8 = 2^23 * 8 = 2^23 * 2^3 = 2^26 = 67,108,864 or approximately 64 MB.

Puesto que tenemos tres índices hash, la memoria necesaria para los índices hash es 3 * 64 MB = 192 MB.Since we have three hash indexes, the memory needed for the hash indexes is 3 * 64MB = 192MB.

Memoria para los índices no clústerMemory for non-clustered indexes

Los índices no clúster se implementan como árboles b donde los nodos internos contienen el valor de índice y punteros a los nodos posteriores.Non-clustered indexes are implemented as BTrees with the inner nodes containing the index value and pointers to subsequent nodes. Los nodos hoja contienen el valor de índice y un puntero a la fila de la tabla en memoria.Leaf nodes contain the index value and a pointer to the table row in memory.

A diferencia de los índices hash, los índices no clúster no tienen un tamaño de cubo fijo.Unlike hash indexes, non-clustered indexes do not have a fixed bucket size. El índice aumenta y disminuye dinámicamente con los datos.The index grows and shrinks dynamically with the data.

La memoria que necesitan los índices no clúster se puede calcular de la manera siguiente:Memory needed by non-clustered indexes can be computed as follows:

  • Memoria asignada a los nodos no hoja Memory allocated to non-leaf nodes
    Para una configuración típica, la memoria asignada a los nodos no hoja es un porcentaje muy pequeño de la memoria total usada por el índice.For a typical configuration, the memory allocated to non-leaf nodes is a small percentage of the overall memory taken by the index. Es tan pequeña que se puede omitir de forma segura.This is so small it can safely be ignored.

  • Memoria para los nodos hoja Memory for leaf nodes
    Los nodos hoja tienen un fila por cada clave única de la tabla que apunta a las filas de datos con esa clave única.The leaf nodes have one row for each unique key in the table that points to the data rows with that unique key. Si tiene varias filas con la misma clave (es decir, tiene un índice no clúster que no es único), solo hay una fila en el nodo hoja del índice que apunta a una de las filas con las demás filas vinculadas entre sí.If you have multiple rows with the same key (i.e., you have a non-unique non-clustered index), there is only one row in the index leaf node that points to one of the rows with the other rows linked to each other. Así, se puede calcular aproximadamente la memoria total necesaria de esta forma:Thus, the total memory required can be approximated by:

    • memoryForNonClusteredIndex = (pointerSize + sum (keyColumnDataTypeSizes)) * rowsWithUniqueKeysmemoryForNonClusteredIndex = (pointerSize + sum(keyColumnDataTypeSizes)) * rowsWithUniqueKeys

Los índices no clúster son los más adecuados cuando se emplean para búsquedas de intervalo, como se ilustra en la consulta siguiente:Non-clustered indexes are best when used for range lookups, as exemplified by the following query:

SELECT * FRON t_hk  
   WHERE c2 > 5;  

Memoria para versiones de filaMemory for row versioning

Para evitar bloqueos, OLTP en memoria emplea simultaneidad optimista al actualizar o eliminar filas.To avoid locks, In-Memory OLTP uses optimistic concurrency when updating or deleting rows. Esto significa que cuando se actualiza una fila, se crea una versión adicional de la fila.This means that when a row is updated, an additional version of the row is created. Además, las eliminaciones se realizan de manera lógica: la fila existente se marca como eliminada, pero no se quita de inmediato.In addition, deletes are logical - the existing row is marked as deleted, but not removed immediately. El sistema conserva versiones de filas anteriores (incluidas las filas eliminadas) disponibles hasta que finaliza la ejecución de todas las transacciones que podrían usar la versión.The system keeps old row versions (including deleted rows) available until all transactions that could possibly use the version have finished execution.

Puesto que en cualquier momento puede haber varias filas adicionales en memoria que esperan que el ciclo de recopilación de elementos no utilizados libere su memoria, debe tener la memoria adecuada para admitir estas filas adicionales.Because there may be a number of additional rows in memory at any time waiting for the garbage collection cycle to release their memory, you must have sufficient memory to accommodate these additional rows.

Se puede estimar el número de filas adicionales calculando el número máximo de actualizaciones y eliminaciones de filas por segundo, y multiplicando después ese valor por el número de segundos que tarda la transacción más larga (mínimo de 1).The number of additional rows can be estimated by computing the peak number of row updates and deletions per second, then multiplying that by the number of seconds the longest transaction takes (minimum of 1).

A continuación, se multiplica ese valor por el tamaño de fila para obtener el número de bytes necesarios para las versiones de fila.That value is then multiplied by the row size to get the number of bytes you need for row versioning.

rowVersions = durationOfLongestTransctoinInSeconds * peakNumberOfRowUpdatesOrDeletesPerSecond

Las necesidades de memoria para las filas obsoletas se calculan después multiplicando el número de filas obsoletas por el tamaño de una fila de una tabla optimizada para memoria (vea Memoria para la tabla anteriormente).Memory needs for stale rows is then estimated by multiplying the number of stale rows by the size of a memory-optimized table row (See Memory for the table above).

memoryForRowVersions = rowVersions * rowSize

Memoria para variables de tablaMemory for table variables

La memoria usada para una variable de tabla solo se libera cuando la variable de tabla sale del ámbito.Memory used for a table variable is released only when the table variable goes out of scope. Las filas eliminadas, incluidas las filas eliminadas como parte de una actualización, de una variable de tabla no están sujetas a recolección de elementos no utilizados.Deleted rows, including rows deleted as part of an update, from a table variable are not subject to garbage collection. No se libera memoria hasta que la variable de tabla no sale del ámbito.No memory is released until the table variable exits scope.

Las variables de tabla definidas en un lote de SQL de gran tamaño, en comparación con un ámbito de procedimiento, que se usan en muchas transacciones, pueden consumir mucha memoria.Table variables defined in a large SQL batch, as opposed to a procedure scope, which are used in many transactions, can consume a lot of memory. Como no se eliminan mediante el recolector de elementos no utilizados, las filas eliminadas de una variable de tabla pueden usar mucha memoria y disminuir el rendimiento porque las operaciones de lectura deben examinar más allá de las filas eliminadas.Because they are not garbage collected, deleted rows in a table variable can consume a lot memory and degrade performance since read operations need to scan past the deleted rows.

Memoria para el crecimientoMemory for growth

Los cálculos anteriores estiman sus necesidades de memoria para la tabla tal y como es actualmente.The above calculations estimate your memory needs for the table as it currently exists. Además de esta memoria, debe calcular el crecimiento de la tabla y proporcionar la memoria adecuada para permitir ese crecimiento.In addition to this memory, you need to estimate the growth of the table and provide sufficient memory to accommodate that growth. Por ejemplo, si prevé un crecimiento del 10 %, necesita multiplicar los resultados anteriores por 1,1 para obtener la memoria total necesaria para la tabla.For example, if you anticipate 10% growth then you need to multiple the results from above by 1.1 to get the total memory needed for your table.

Consulte tambiénSee Also

Migrar a OLTP en memoriaMigrating to In-Memory OLTP