{"id":875,"date":"2009-05-04T14:47:00","date_gmt":"2009-05-04T14:47:00","guid":{"rendered":"\/blogs\/paul\/post\/Misconceptions-around-null-bitmap-size.aspx"},"modified":"2013-01-01T19:43:42","modified_gmt":"2013-01-02T03:43:42","slug":"misconceptions-around-null-bitmap-size","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/","title":{"rendered":"Misconceptions around null bitmap size"},"content":{"rendered":"<p>\n<font face=\"verdana,geneva\" size=\"2\">I&#39;m starting a new series called &#39;Misconceptions&#39; &#8211; a series of short posts that debunk some of the many myths and misconceptions that exist about the way SQL Server behaves. I actually already did the first post a couple of weeks back (<\/font><a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-tf-1118\/\"><font face=\"verdana,geneva\" size=\"2\">Misconceptions around TF 1118<\/font><\/a><font face=\"verdana,geneva\" size=\"2\">) but just went back to re-tag it. <\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">In this post I want to debunk the common myth that the null bitmap only contains bits for nullable columns. It doesn&#39;t &#8211; it has one bit per column in the table definition, as long as at least one column in the table is nullable. The &#39;unused&#39; bits are always set to 1, which means &#39;null&#39;. <\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">And now the proof. I&#39;m going to create two tables, with 10 columns each (meaning that the null bitmap has to have two bytes to store all the bits, plus two bytes for the count of columns in the record). The first table will have all nullable columns. The second will have the first 9 columns not nullable, and the tenth column nullable. <\/font>\n<\/p>\n<blockquote>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">CREATE TABLE t1 (<br \/>\n\t&nbsp;&nbsp;&nbsp; c1 INT, c2 INT, c3 INT, c4 INT, c5 INT,<br \/>\n\t&nbsp;&nbsp;&nbsp; c6 INT, c7 INT, c8 INT, c9 INT, c10 INT);<br \/>\n\tGO<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">CREATE TABLE t2 (<br \/>\n\t&nbsp;&nbsp;&nbsp; c1 INT NOT NULL, c2 INT NOT NULL, c3 INT NOT NULL,<br \/>\n\t&nbsp;&nbsp;&nbsp; c4 INT NOT NULL, c5 INT NOT NULL, c6 INT NOT NULL,<br \/>\n\t&nbsp;&nbsp;&nbsp; c7 INT NOT NULL, c8 INT NOT NULL, c9 INT NOT NULL,<br \/>\n\t&nbsp;&nbsp;&nbsp; c10 INT);<br \/>\n\tGO<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">INSERT INTO t1 VALUES (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);<br \/>\n\tGO<\/font>\n\t<\/p>\n<p>\n\t<font face=\"verdana,geneva\" size=\"2\"><font face=\"courier new,courier\">INSERT INTO t2 VALUES (&nbsp;1, 2, 3, 4, 5, 6, 7, 8, 9, NULL);<br \/>\n\tGO<\/font><\/font>\n\t<\/p>\n<\/blockquote>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">And now let&#39;s look at the pages themselves. I&#39;ll get the pages involved using my <font face=\"courier new,courier\">sp_AllocationMetadata<\/font> script (see <\/font><a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-sp_allocationmetadata-putting-undocumented-system-catalog-views-to-work\/\"><font face=\"verdana,geneva\" size=\"2\">Inside The Storage Engine: sp_AllocationMetadata &#8211; putting undocumented system catalog views to work<\/font><\/a><font face=\"verdana,geneva\" size=\"2\">): <\/font>\n<\/p>\n<blockquote>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">EXEC sp_AllocationMetadata &#39;t1&#39;;<br \/>\n\tEXEC sp_allocationMetadata &#39;t2&#39;;<br \/>\n\tGO<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">Object Name&nbsp; Index ID&nbsp; Alloc Unit ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Alloc Unit Type&nbsp; First Page&nbsp; Root Page&nbsp; First IAM Page<br \/>\n\t&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8212;&#8212;<br \/>\n\tt1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 72057594042318848&nbsp; IN_ROW_DATA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1:152)&nbsp;&nbsp;&nbsp;&nbsp; (0:0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1:153)<\/font>\n\t<\/p>\n<p>\n\t<font face=\"verdana,geneva\" size=\"2\"><font face=\"courier new,courier\">Object Name&nbsp; Index ID&nbsp; Alloc Unit ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Alloc Unit Type&nbsp; First Page&nbsp; Root Page&nbsp; First IAM Page<br \/>\n\t&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8212;&#8212;<br \/>\n\tt2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2057594042384384&nbsp; IN_ROW_DATA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1:154)&nbsp;&nbsp;&nbsp;&nbsp; (0:0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1:155)<\/font><\/font>\n\t<\/p>\n<\/blockquote>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">And now dump them with DBCC PAGE to look at the row structure: <\/font>\n<\/p>\n<blockquote>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">DBCC TRACEON (3604);<br \/>\n\tGO<br \/>\n\tDBCC PAGE (&#39;NullTest&#39;, 1, 152, 3);<br \/>\n\tDBCC PAGE (&#39;NullTest&#39;, 1, 154, 3);<br \/>\n\tGO<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">&#8212; Record dump from t1, all ten columns nullable and not NULL <\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">Record Type = PRIMARY_RECORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Record Attributes =&nbsp; NULL_BITMAP<br \/>\n\tMemory Dump @0x684EC060<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">00000000:&nbsp;&nbsp; 10002c00 01000000 02000000 03000000 &dagger;..,&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t00000010:&nbsp;&nbsp; 04000000 05000000 06000000 07000000 &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t00000020:&nbsp;&nbsp; 08000000 09000000 0a000000 <strong><u>0a0000fc<\/u><\/strong> &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">&#8212; Record dump from t2, first nine columns not nullable, tenth column nullable and NULL <\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">Record Type = PRIMARY_RECORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Record Attributes =&nbsp; NULL_BITMAP<br \/>\n\tMemory Dump @0x684EC060<\/font>\n\t<\/p>\n<p>\n\t<font face=\"courier new,courier\" size=\"2\">00000000:&nbsp;&nbsp; 10002c00 01000000 02000000 03000000 &dagger;..,&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t00000010:&nbsp;&nbsp; 04000000 05000000 06000000 07000000 &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t00000020:&nbsp;&nbsp; 08000000 09000000 21212121 <strong><u>0a0000fe<\/u><\/strong> &dagger;&#8230;&#8230;..!!!!&#8230;.<\/font>\n\t<\/p>\n<\/blockquote>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">If you try this yourself, you may get a different bit pattern for the NULL c10 (I got <font face=\"courier new,courier\">0x21212121<\/font>). It&#39;s a bit of a crap-shoot depending on what memory SQL Server reuses to create the record in memory before writing to the page &#8211; the 4 bytes of the NULL column aren&#39;t overwritten from the previous usage of the memory (and don&#39;t need to be). <\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">In the first record, you can see that the null bitmap (underlined and in bold) says there&#39;s 10 columns (the <font face=\"courier new,courier\">0x0a00<\/font> gets byte-reversed into <font face=\"courier new,courier\">0x000a<\/font>) and the null bitmap is <font face=\"courier new,courier\">0xfc00<\/font>, which is <font face=\"courier new,courier\">1111110000000000<\/font> &#8211; 6 unused bits all set to 1 and 10 not-NULL column values.<\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">In the first record, you can see that the null bitmap (underlined and in bold) says there&#39;s 10 columns again&nbsp;and the null bitmap this time is <font face=\"courier new,courier\">0xfe00<\/font>, which is <font face=\"courier new,courier\">1111111000000000<\/font> &#8211;&nbsp;6 unused bits all set to 1, 1 column NULL and 9 columns not-NULL. Column 1 is the far right bit, so column 10 is the tenth from right (the first &#39;1&#39;).<\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">This clearly shows that all columns are represented in the null bitmap even if only one of the columns is nullable. It&#39;s the same if on the first column in the table is nullable, I&#39;ll leave that for you to prove to yourself.<\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">Next up: the next misconception I come across!<\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">[Edit 08\/02\/11: In 2008 if all columns are defined as SPARSE, there will not be a null bitmap at all &#8211; very special case!]<\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#39;m starting a new series called &#39;Misconceptions&#39; &#8211; a series of short posts that debunk some of the many myths and misconceptions that exist about the way SQL Server behaves. I actually already did the first post a couple of weeks back (Misconceptions around TF 1118) but just went back to re-tag it. In this [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48,61,62],"tags":[],"class_list":["post-875","post","type-post","status-publish","format-standard","hentry","category-inside-the-storage-engine","category-misconceptions","category-on-disk-structures"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Misconceptions around null bitmap size - Paul S. Randal<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Misconceptions around null bitmap size - Paul S. Randal\" \/>\n<meta property=\"og:description\" content=\"I&#039;m starting a new series called &#039;Misconceptions&#039; &#8211; a series of short posts that debunk some of the many myths and misconceptions that exist about the way SQL Server behaves. I actually already did the first post a couple of weeks back (Misconceptions around TF 1118) but just went back to re-tag it. In this [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/\" \/>\n<meta property=\"og:site_name\" content=\"Paul S. Randal\" \/>\n<meta property=\"article:published_time\" content=\"2009-05-04T14:47:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2013-01-02T03:43:42+00:00\" \/>\n<meta name=\"author\" content=\"Paul Randal\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Paul Randal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/\",\"name\":\"Misconceptions around null bitmap size - Paul S. Randal\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\"},\"datePublished\":\"2009-05-04T14:47:00+00:00\",\"dateModified\":\"2013-01-02T03:43:42+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Misconceptions around null bitmap size\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\",\"name\":\"Paul S. Randal\",\"description\":\"In Recovery...\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\",\"name\":\"Paul Randal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"caption\":\"Paul Randal\"},\"sameAs\":[\"http:\/\/3.209.169.194\/blogs\/paul\"],\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Misconceptions around null bitmap size - Paul S. Randal","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/","og_locale":"en_US","og_type":"article","og_title":"Misconceptions around null bitmap size - Paul S. Randal","og_description":"I&#39;m starting a new series called &#39;Misconceptions&#39; &#8211; a series of short posts that debunk some of the many myths and misconceptions that exist about the way SQL Server behaves. I actually already did the first post a couple of weeks back (Misconceptions around TF 1118) but just went back to re-tag it. In this [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/","og_site_name":"Paul S. Randal","article_published_time":"2009-05-04T14:47:00+00:00","article_modified_time":"2013-01-02T03:43:42+00:00","author":"Paul Randal","twitter_misc":{"Written by":"Paul Randal","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/","name":"Misconceptions around null bitmap size - Paul S. Randal","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website"},"datePublished":"2009-05-04T14:47:00+00:00","dateModified":"2013-01-02T03:43:42+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/misconceptions-around-null-bitmap-size\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/paul\/"},{"@type":"ListItem","position":2,"name":"Misconceptions around null bitmap size"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/","name":"Paul S. Randal","description":"In Recovery...","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce","name":"Paul Randal","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","caption":"Paul Randal"},"sameAs":["http:\/\/3.209.169.194\/blogs\/paul"],"url":"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/875","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/comments?post=875"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/875\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/media?parent=875"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/categories?post=875"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/tags?post=875"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}