{"id":1623,"date":"2014-01-16T13:00:00","date_gmt":"2014-01-16T21:00:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/dataplatforminsider\/2014\/01\/16\/storage-allocation-and-management-for-memory-optimized-tables\/"},"modified":"2024-01-22T22:49:04","modified_gmt":"2024-01-23T06:49:04","slug":"storage-allocation-and-management-for-memory-optimized-tables","status":"publish","type":"post","link":"https:\/\/www.microsoft.com\/en-us\/sql-server\/blog\/2014\/01\/16\/storage-allocation-and-management-for-memory-optimized-tables\/","title":{"rendered":"Storage Allocation and Management for Memory-Optimized Tables"},"content":{"rendered":"
As described in implementing durability for memory optimized tables<\/a>, the storage requirements and its management for memory optimized tables is very different compared to the disk-based tables. If you are migrating a subset of your disk-based tables to memory-optimized tables or are just developing a new application with memory-optimized tables, you will notice these differences. Unlike disk-based tables in SQL Server that use 8k pages to store data in the same format both on disk and in memory, the \u00a0memory-optimized tables utilize a different size and\u00a0 format both in-memory and on disk. This has been a point of concern by many customers as they have observed, sometimes, disproportionate storage consumed by memory optimized tables. The goal of this blog is to help alleviate this confusion by describing how storage is managed over the lifetime of data rows.\u00a0<\/p>\n The data for memory optimized tables is stored in one or more data\/delta file pairs (also referred to as checkpoint file pairs or CFP) with data file(s) storing inserted rows and delta file(s) referencing deleted rows. \u00a0During the execution of an OLTP workload, as the DML operations update, insert, and delete rows, new data\/delta files are created to persist the data. Also, existing delta files are updated to process delete of existing rows. \u00a0Over time, if the number of active rows, after accounting for deleted rows, in two or more consecutive CFPs falls below a threshold (usually < 50%) such that they can be merged into one CFP of 128 MB, they are merged automatically by a background merge process into a new CFP. \u00a0Once the merge operation is complete, the older CFPs go through a transition phase and are eventually removed (i.e. garbage collected) from the storage. \u00a0Note, SQL Server 2014 CTP2 supports up to 4096 CFPs within a database but this limit will be changed to 8192 CFPs in RTM<\/p>\n At any given time, the data\/delta file pairs are in one of the following 4 categories<\/p>\n Transitioning CFPs out of category-3 and category-4 can take up to 5 checkpoints and transaction log backup steps, if not running in simple recovery mode. For in-memory databases, the automatic checkpoint is taken when the size of transaction log exceeds 512MB since the last checkpoint.\u00a0 You can, of course, manually force the checkpoint followed by log backup to expedite the garbage collection but then this will add 5 empty CFPs (i.e. 5 data\/delta file pairs with data file of size 128MB each). Typically, in test environment, you may have to force transaction log backups and checkpoints to remove the CFPs that are not needed. In production scenarios, however, we don\u2019t expect customers to do manual checkpoint but to rely on the automatic checkpoints and log backups that are taken as part of backup strategy. The impact of this garbage collection process is that in-memory databases may have a disproportionate storage footprint compared to its size in memory.<\/p>\n To clarify the point further, let us walk through some examples of in-memory databases under various scenarios and compare their size in-memory and on storage.\u00a0 For these examples, we will assume we are running a SQL instance with 8 logical processor with 1 memory optimized table with following schema. Note, this has a row size of approximately 8KB.\u00a0<\/p>\n CREATE TABLE<\/span> dbo.t_memopt (<\/span><\/p>\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 c1 int<\/span> NOT NULL,<\/span><\/p>\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 c2 char<\/span>(40) NOT NULL,<\/span><\/p>\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 c3 char<\/span>(8000) NOT NULL,<\/span><\/p>\n \u00a0<\/span><\/p>\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 CONSTRAINT<\/span> [pk_t_memopt_c1] PRIMARY KEY NONCLUSTERED HASH<\/span> (c1) WITH<\/span><\/span><\/p>\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 (BUCKET_COUNT<\/span> = 100000)<\/span><\/p>\n ) WITH<\/span> (MEMORY_OPTIMIZED<\/span> = ON<\/span>, DURABILITY<\/span> = SCHEMA_AND_DATA)<\/span><\/p>\n As indicated earlier, the fixed storage overhead for this configuration will be 1 GB (i.e. 8 data files of 128MB each).<\/p>\n Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 memory_used_by_indexes_kb memory_used_by_table_kb<\/span><\/p>\n ———- ————————- ———————–<\/span><\/p>\n t1\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1024\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 8<\/span><\/p>\n \n<\/li>\n<\/ul>\n Though these examples were over simplified but they do illustrate the difference in storage provisioning for memory optimized tables over disk-based tables. Your storage requirement will depend upon following key factors such<\/p>\n As described in implementing durability for memory optimized tables, the storage requirements and its management for memory optimized tables is very different compared to the disk-based tables. If you are migrating a subset of your disk-based tables to memory-optimized tables or are just developing a new application with memory-optimized tables, you will notice these differences.<\/p>\n","protected":false},"author":1457,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ep_exclude_from_search":false,"_classifai_error":"","_classifai_text_to_speech_error":"","footnotes":""},"post_tag":[],"product":[],"content-type":[2424],"topic":[],"coauthors":[2487],"class_list":["post-1623","post","type-post","status-publish","format-standard","hentry","content-type-best-practices"],"yoast_head":"\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n