Stimare i requisiti di memoria delle tabelle con ottimizzazione per la memoriaEstimate Memory Requirements for Memory-Optimized Tables

In questo argomento si applica a: SìSQL ServerSìDatabase SQL di AzurenonAzure SQL Data Warehouse non Parallel Data WarehouseTHIS TOPIC APPLIES TO: yesSQL ServeryesAzure SQL DatabasenoAzure SQL Data Warehouse noParallel Data Warehouse

Le tabelle con ottimizzazione per la memoria richiedono memoria sufficiente per mantenere tutte le righe e tutti gli indici in memoria.Memory-optimized tables require that sufficient memory exist to keep all of the rows and indexes in memory. Poiché la memoria è una risorsa limitata, è importante conoscere e gestire l'utilizzo di memoria nel sistema.Because memory is a finite resource, it is important that you understand and manage memory usage on your system. Negli argomenti di questa sezione vengono illustrati gli scenari comuni di utilizzo e gestione della memoria.The topics in this section cover common memory use and management scenarios.

Se si crea una nuova tabella ottimizzata per la memoria o si esegue la migrazione di una tabella basata su disco esistente a una tabella ottimizzata per la memoria OLTP in memoriaIn-Memory OLTP, è importante disporre di un numero ragionevole di requisiti di memoria di ogni tabella in modo da poter fornire memoria sufficiente al server.Whether you are creating a new memory-optimized table or migrating an existing disk-based table to an OLTP in 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. In questa sezione viene descritto come stimare la quantità di memoria necessaria per contenere i dati di una tabella ottimizzata per la memoria.This section describes how to estimate the amount of memory that you need to hold data for a memory-optimized table.

Se si prende in considerazione la migrazione da tabelle basate su disco a tabelle ottimizzate per la memoria, prima di procedere con questo argomento, vedere Determinare se una tabella o una stored procedure deve essere trasferita a OLTP in memoria per informazioni aggiuntive sulle tabelle più appropriate per la migrazione.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. Tutti gli argomenti disponibili in Migrazione a OLTP in memoria offrono informazioni aggiuntive sulla migrazione da tabelle basate su disco a tabelle ottimizzate per la memoria.All the topics under Migrating to In-Memory OLTP provide guidance on migrating from disk-based to memory-optimized tables.

Materiale sussidiario di base per la stima dei requisiti di memoriaBasic Guidance for Estimating Memory Requirements

A partire da SQL Server 2016SQL Server 2016non esiste alcun limite alle dimensioni delle tabelle ottimizzate per la memoria, ad eccezione della memoria disponibile.Starting with SQL Server 2016SQL Server 2016, there is no limit on the size of memory-optimized tables, though the tables do need to fit in memory. In SQL Server 2014SQL Server 2014 le dimensioni dei dati supportate sono pari a 256 GB per le tabelle SCHEMA_AND_DATA.In SQL Server 2014SQL Server 2014 the supported data size is 256GB for SCHEMA_AND_DATA tables.

Le dimensioni di una tabella ottimizzata per la memoria corrispondono alle dimensioni dei dati più l'overhead per le intestazioni di riga.The size of a memory-optimized table corresponds to the size of data plus some overhead for row headers. Durante la migrazione di una tabella basata su disco a una tabella ottimizzata per la memoria, le dimensioni della tabella ottimizzata per la memoria corrispondono approssimativamente alle dimensioni dell'indice o dell'heap cluster della tabella originale basata su 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.

Gli indici delle tabelle ottimizzate per la memoria tendono a essere più piccoli rispetto agli indici non cluster nelle tabelle basate su disco.Indexes on memory-optimized tables tend to be smaller than nonclustered indexes on disk-based tables. Le dimensioni degli indici non cluster corrispondono a [primary key size] * [row count].The size of nonclustered indexes is in the order of [primary key size] * [row count]. Le dimensioni degli indici hash corrispondono a [bucket count] * 8 bytes.The size of hash indexes is [bucket count] * 8 bytes.

Quando è presente un carico di lavoro attivo, è necessaria altra memoria per tenere conto del controllo delle versioni delle righe e di diverse operazioni.When there is an active workload, additional memory is needed to account for row versioning and various operations. La quantità di memoria necessaria dipende dal carico di lavoro, ma per sicurezza è consigliabile iniziare con il doppio della dimensione prevista di indici e tabelle ottimizzate per la memoria e quindi determinare i requisiti di memoria nella pratica.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. L'overhead per il controllo delle versioni delle righe dipende sempre dalle caratteristiche del carico di lavoro, in particolare le transazioni con esecuzione prolungata aumentano l'overhead.The overhead for row versioning always depends on the characteristics of the workload - especially long-running transactions increase the overhead. Per la maggior parte dei carichi di lavoro con database di grandi dimensioni (ad esempio >100 GB), l'overhead tende a essere limitato (25% o meno).For most workloads using larger databases (e.g., >100GB), overhead tends to be limited (25% or less).

Calcolo dettagliato dei requisiti di memoriaDetailed Computation of Memory Requirements

        </a> Esempio di tabella ottimizzata per la memoria</span><span class="sxs-lookup"><span data-stu-id="361f1-129"><a name="bkmk_ExampleTable"></a> Example memory-optimized table</span></span>  

Si consideri il seguente schema di tabella ottimizzata per la memoria: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  

Utilizzando questo schema sarà possibile stabilire la memoria minima necessaria per questa tabella ottimizzata per la memoria.Using this schema we will determine the minimum memory needed for this memory-optimized table.

Memoria per la tabellaMemory for the table

La riga di una tabella ottimizzata per la memoria è costituita da tre parti:A memory-optimized table row is comprised of three parts:

  • Timestamp Timestamps
    Intestazione di riga/timestamp = 24 byte.Row header/timestamps = 24 bytes.

  • Puntatori dell'indice Index pointers
    Per ogni indice hash nella tabella, a ogni riga è associato un puntatore all'indirizzo di 8 byte alla riga successiva nell'indice.For each hash index in the table, each row has an 8-byte address pointer to the next row in the index. Poiché sono presenti 4 indici, tramite ogni riga vengono allocati 32 byte per i puntatori dell'indice (un puntatore di 8 byte per ogni indice).Since there are 4 indexes, each row will allocate 32 bytes for index pointers (an 8 byte pointer for each index).

  • Dati Data
    Le dimensioni della parte di dati della riga vengono determinate sommando le dimensioni di tipo per ogni colonna di dati.The size of the data portion of the row is determined by summing the type size for each data column. Nella tabella di esempio sono contenuti cinque Integer a 4 byte, tre colonne di tipo carattere di 50 byte e una colonna di tipo carattere di 30 byte.In our table we have five 4-byte integers, three 50-byte character columns, and one 30-byte character column. Pertanto la parte di dati di ogni riga è 4 + 4 + 4 + 4 + 4 + 50 + 50 + 30 + 50, vale a dire 200 byte.Therefore the data portion of each row is 4 + 4 + 4 + 4 + 4 + 50 + 50 + 30 + 50 or 200 bytes.

Di seguito è riportato un calcolo di dimensioni per 5.000.000 (5 milioni) di righe in una tabella ottimizzata per la memoria.The following is a size computation for 5,000,000 (5 million) rows in a memory-optimized table. La memoria totale utilizzata dalle righe di dati viene stimata come segue:The total memory used by data rows is estimated as follows:

Memoria per le righe della tabellaMemory for the table’s rows

Dai calcoli sopra riportati, le dimensioni di ogni riga della tabella ottimizzata per la memoria sono pari a 24 + 32 + 200, vale a dire 256 byte.From the above calculations, the size of each row in the memory-optimized table is 24 + 32 + 200, or 256 bytes. Dal momento che sono presenti 5 milioni di righe, per la tabella verranno utilizzati 5.000.000 * 256 byte, vale a dire 1.280.000.000 di byte, circa 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 per gli indiciMemory for indexes

Memoria per ogni indice hashMemory for each hash index

Ogni indice hash è una matrice di hash di puntatori all'indirizzo di 8 byte.Each hash index is a hash array of 8-byte address pointers. Le dimensioni della matrice vengono determinata meglio in base al numero di valori di indice univoci per l'indice in questione, ad esempio il numero di valori Col2 univoci è un buon punto di partenza per le dimensioni della matrice per 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 matrice di hash eccessiva comporta uno spreco di memoria.A hash array that is too big wastes memory. Una matrice di hash di piccole dimensioni determina un rallentamento delle prestazioni in quanto vi saranno troppe collisioni per i valori di indice con hashing nello stesso indice.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.

Tramite gli indici hash è possibile ottenere ricerche di uguaglianza estremamente veloci, ad esempio:Hash indexes achieve very fast equality lookups such as:

SELECT * FROM t_hk  
   WHERE Col2 = 3;

Gli indici non cluster sono più veloci per le ricerche in intervalli, ad esempio:Nonclustered indexes are faster for range lookups such as:

SELECT * FROM t_hk  
   WHERE Col2 >= 3;

Se si esegue la migrazione di una tabella basata su disco, è possibile utilizzare quando riportato di seguito per determinare il numero di valori univoci per l'indice 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;

Se si crea una nuova tabella, sarà necessario stimare le dimensioni della matrice o raccogliere i dati dal test prima di eseguire la distribuzione.If you are creating a new table, you’ll need to estimate the array size or gather data from your testing prior to deployment.

Per informazioni sul funzionamento degli indici hash in tabelle ottimizzate per la memoria OLTP in memoriaIn-Memory OLTP, vedere Indici hash.For information on how hash indexes work in OLTP in memoriaIn-Memory OLTP memory-optimized tables, see Hash Indexes.

Impostazione delle dimensioni della matrice dell'indice hashSetting the hash index array size

Le dimensioni della matrice di hash vengono impostate tramite (bucket_count= value) dove value è un intero maggiore di zero.The hash array size is set by (bucket_count= value) where value is an integer value greater than zero. Se value non è una potenza di 2, il numero effettivo di bucket_count viene arrotondato per eccesso alla potenza di 2 successiva più vicina.If value is not a power of 2, the actual bucket_count is rounded up to the next closest power of 2. Nella tabella di esempio, (bucket_count = 5000000), poiché 5.000.000 non è una potenza di 2, il numero effettivo di bucket viene arrotondato per eccesso a 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). È necessario utilizzare questo numero, non 5.000.000, quando si calcola la memoria necessaria per la matrice di hash.You must use this number, not 5,000,000 when calculating memory needed by the hash array.

Pertanto, nell'esempio, la memoria necessaria per ogni matrice di hash è: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 circa 64 MB.8,388,608 * 8 = 2^23 * 8 = 2^23 * 2^3 = 2^26 = 67,108,864 or approximately 64 MB.

Poiché vi sono tre indici hash, la memoria necessaria per gli indici hash è 3 * 64 MB = 192 MB.Since we have three hash indexes, the memory needed for the hash indexes is 3 * 64MB = 192MB.

Memoria per gli indici non clusterMemory for non-clustered indexes

Gli indici non cluster vengono implementati come alberi B con nodi interni contenenti il valore di indice e i puntatori ai nodi successivi.Non-clustered indexes are implemented as BTrees with the inner nodes containing the index value and pointers to subsequent nodes. Nei nodi foglia sono inclusi il valore di indice e un puntatore alla riga di tabella in memoria.Leaf nodes contain the index value and a pointer to the table row in memory.

A differenza degli indici hash, gli indici non cluster non presentano dimensioni fisse per il bucket.Unlike hash indexes, non-clustered indexes do not have a fixed bucket size. Le dimensioni dell'indice aumentano e si riducono dinamicamente in base ai dati.The index grows and shrinks dynamically with the data.

La memoria necessaria per gli indici non cluster può essere calcolata come indicato di seguito:Memory needed by non-clustered indexes can be computed as follows:

  • Memoria allocata ai nodi non foglia Memory allocated to non-leaf nodes
    Per una configurazione tipica, la memoria allocata ai nodi non foglia è una percentuale minima della memoria globale utilizzata dall'indice,For a typical configuration, the memory allocated to non-leaf nodes is a small percentage of the overall memory taken by the index. che per le sue dimensioni contenute può essere sicuramente ignorata.This is so small it can safely be ignored.

  • Memoria per i nodi foglia Memory for leaf nodes
    I nodi foglia hanno una riga per ogni chiave univoca della tabella che punta alle righe di dati con questa chiave univoca.The leaf nodes have one row for each unique key in the table that points to the data rows with that unique key. Se si dispone di più righe con la stessa chiave, cioè si dispone di un indice non cluster non univoco, esiste un'unica riga nel nodo foglia dell'indice che punta a una delle righe con le altre righe collegate tra loro.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. Pertanto, la memoria totale necessaria può essere approssimata nel modo seguente:Thus, the total memory required can be approximated by:

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

    Gli indici non cluster rappresentano la soluzione migliore in caso di ricerche in intervalli, come esemplificato dalla query seguente:Non-clustered indexes are best when used for range lookups, as exemplified by the following query:

SELECT * FRON t_hk  
   WHERE c2 > 5;  

Memoria per il controllo delle versioni delle righeMemory for row versioning

Per evitare blocchi, tramite OLTP in memoria viene utilizzata la concorrenza ottimistica durante l'aggiornamento o l'eliminazione di righe.To avoid locks, In-Memory OLTP uses optimistic concurrency when updating or deleting rows. Pertanto, quando una riga viene aggiornata, viene creata una versione aggiuntiva della riga.This means that when a row is updated, an additional version of the row is created. Inoltre, le eliminazioni sono logiche: la riga esistente viene contrassegnata come eliminata, ma non viene rimossa immediatamente.In addition, deletes are logical - the existing row is marked as deleted, but not removed immediately. Il sistema mantiene disponibili le versioni precedenti delle righe (comprese quelle eliminate) fino al termine dell'esecuzione di tutte le transazioni che potrebbero usare una versione.The system keeps old row versions (including deleted rows) available until all transactions that could possibly use the version have finished execution.

Poiché è possibile che vi sia un numero di righe aggiuntive in memoria in qualsiasi momento in attesa del ciclo di Garbage Collection per rilasciare la memoria, è necessario disporre di memoria sufficiente per contenere queste righe aggiuntive.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.

Il numero di righe aggiuntive può essere stimato calcolando il numero massimo di aggiornamenti ed eliminazioni di righe al secondo, quindi moltiplicando il risultato per il numero di secondi impiegati dalla transazione più lunga (almeno 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).

Il valore viene quindi moltiplicato per le dimensioni della riga per ottenere il numero di byte necessari per il controllo delle versioni delle righe.That value is then multiplied by the row size to get the number of bytes you need for row versioning.

rowVersions = durationOfLongestTransctoinInSeconds * peakNumberOfRowUpdatesOrDeletesPerSecond

I requisiti di memoria per righe non aggiornate vengono quindi stimati moltiplicando il numero di righe non aggiornate per le dimensioni di una riga di tabella ottimizzata per la memoria. Vedere Memoria per la tabella precedentemente in questo argomento.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 per le variabili di tabellaMemory for table variables

La memoria utilizzata per una variabile di tabella viene rilasciata solo quando la variabile di tabella abbandona l'ambito.Memory used for a table variable is released only when the table variable goes out of scope. Le righe eliminate, incluse quelle eliminate come parte di un aggiornamento, da una variabile di tabella non vengono sottoposte a Garbage Collection.Deleted rows, including rows deleted as part of an update, from a table variable are not subject to garbage collection. Finché la variabile di tabella non abbandona l'ambito, la memoria non viene rilasciata.No memory is released until the table variable exits scope.

Le variabili di tabella definite in un batch SQL di grandi dimensioni, a differenza di un ambito di procedura, utilizzate in molte transazioni, possono richiedere una grande quantità di 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. Poiché non vengono sottoposte a Garbage Collection, le righe eliminate in una variabile di tabella possono utilizzare una grande quantità di memoria e influire negativamente sulle prestazioni poiché le operazioni di lettura devono eseguire l'analisi delle righe eliminate.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 in caso di aumento delle dimensioniMemory for growth

Con i calcoli sopra riportati vengono stimati i requisiti di memoria della tabella attuale.The above calculations estimate your memory needs for the table as it currently exists. Oltre a questa memoria, è necessario stimare la crescita della tabella e fornire una memoria sufficiente per gestire questa crescita.In addition to this memory, you need to estimate the growth of the table and provide sufficient memory to accommodate that growth. Ad esempio, se si prevede una crescita del 10%, sarà necessario moltiplicare i risultati precedenti per 1,1 per ottenere la memoria totale necessaria per la tabella.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.

Vedere ancheSee Also

Migrazione a OLTP in memoriaMigrating to In-Memory OLTP