{"id":967,"date":"2008-12-17T11:03:00","date_gmt":"2008-12-17T11:03:00","guid":{"rendered":"\/blogs\/paul\/post\/TechEd-demo-nonclustered-index-corruption.aspx"},"modified":"2017-04-13T09:54:11","modified_gmt":"2017-04-13T16:54:11","slug":"teched-demo-nonclustered-index-corruption","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/","title":{"rendered":"TechEd demo: nonclustered index corruption"},"content":{"rendered":"<p>\n<font face=\"verdana\" size=\"2\">This blog post describes the demo &quot;2 &#8211; NC Indexes&quot; from my Corruption Survival Techniques conference session from various conferences in 2008. The links to the scripts and databases to use are in <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/conference-corruption-demo-scripts-and-example-corrupt-databases\/\">this blog post<\/a>.<\/font>\n<\/p>\n<p><font size=\"2\">Edit 6\/4\/2012: Be aware that in versions of SQL Server from 2008 onwards, you may only be able to fix the corruption by doing a DROP + CREATE index, as all other methods will try to read the old index to build them. You can avoid any constraints (e.g. unique) being invalidated in between the DROP and the CREATE by wrapping the whole operation in an explicit transaction.<\/font><font face=\"verdana\"><\/font><font face=\"verdana\"> <\/p>\n<p>\n<font size=\"2\"><font face=\"verdana,geneva\">The aim of this demo is to show that sometimes its just redundant data (i.e. nonclustered indexes) that get corrupted, and so you don&#39;t have to do anything that takes the actual data offline &#8211; like restoring from a full backup or running one of the repair options (both of which require the database to be in single-user mode).<\/font> <\/font>\n<\/p>\n<p>\n<font size=\"2\"><font face=\"verdana,geneva\">Let&#39;s look at an example. Extract and restore the DemoNCIndex database, and the NCIndexCorruption.sql script. What do we get from running <font face=\"courier new,courier\">DBCC CHECKDB<\/font> on the DemoNCIndex database (lines 39-42)?<\/font> <\/font>\n<\/p>\n<blockquote><p>\n\t<font face=\"courier new,courier\"><\/p>\n<p>\n\t<font size=\"2\">DBCC CHECKDB <font color=\"#808080\">(<\/font>DemoNCIndex<font color=\"#808080\">) <\/font><font color=\"#0000ff\">WITH<\/font> <font color=\"#0000ff\">NO_INFOMSGS<\/font><font color=\"#808080\">,<\/font> <font color=\"#0000ff\">ALL_ERRORMSGS<\/font><\/font><font size=\"2\"><font color=\"#808080\">;<br \/>\n\t<\/font>GO <\/font>\n\t<\/p>\n<p>\n\t<font size=\"2\"><font color=\"#ff0000\">Msg 8951, Level 16, State 1, Line 1<br \/>\n\tTable error: table &#39;Customers&#39; (ID 453576654). Data row does not have a matching index row in the index &#39;CustomerName&#39; (ID 2). Possible missing or invalid keys for the index row matching:<br \/>\n\tMsg 8955, Level 16, State 1, Line 1<br \/>\n\tData row (1:45:28) identified by (CustomerID = 29) with index values &#39;LastName = &#39;Adams&#39; and CustomerID = 29&#39;.<br \/>\n\tMsg 8951, Level 16, State 1, Line 1<br \/>\n\tTable error: table &#39;Customers&#39; (ID 453576654). Data row does not have a matching index row in the index &#39;CustomerName&#39; (ID 2). Possible missing or invalid keys for the index row matching:<br \/>\n\tMsg 8955, Level 16, State 1, Line 1<br \/>\n\tData row (1:180:164) identified by (CustomerID = 2118) with index values &#39;LastName = &#39;Adams&#39; and CustomerID = 2118&#39;.<\/font> <\/font>\n\t<\/p>\n<p>\t<font size=\"2\">&lt;snip &#8211; removed for brevity&gt;<\/font><font color=\"#ff0000\"><font size=\"2\"> <\/font><\/p>\n<p>\n\t<font size=\"2\">Msg 8952, Level 16, State 1, Line 1<br \/>\n\tTable error: table &#39;Customers&#39; (ID 453576654). Index row in index &#39;CustomerName&#39; (ID 2) does not match any data row. Possible extra or invalid keys for:<br \/>\n\tMsg 8956, Level 16, State 1, Line 1<br \/>\n\tIndex row (1:24482:16) with values (LastName = &#39;Andersen&#39; and CustomerID = 18718) pointing to the data row identified by (CustomerID = 18718).<br \/>\n\tMsg 8952, Level 16, State 1, Line 1<br \/>\n\tTable error: table &#39;Customers&#39; (ID 453576654). Index row in index &#39;CustomerName&#39; (ID 2) does not match any data row. Possible extra or invalid keys for:<br \/>\n\tMsg 8956, Level 16, State 1, Line 1<br \/>\n\tIndex row (1:24482:127) with values (LastName = &#39;Arthur&#39; and CustomerID = 9758) pointing to the data row identified by (CustomerID = 9758).<br \/>\n\t<\/font><font size=\"2\"><font face=\"verdana,geneva\"><font face=\"courier new,courier\" color=\"#000000\">CHECKDB found 0 allocation errors and 26 consistency errors in table &#39;Customers&#39; (object ID 453576654).<br \/>\n\tCHECKDB found 0 allocation errors and 26 consistency errors in database &#39;DemoNCIndex&#39;<br \/>\n\trepair_rebuild is the minimum repair level for the errors found by DBCC CHECKDB (DemoNCIndex).<\/font>&nbsp;<\/font> <\/font>\n\t<\/p>\n<p>\t<\/font><\/font>\n<\/p><\/blockquote>\n<p>\n<font size=\"2\"><font face=\"verdana,geneva\">Lots of errors. Now, in this example there are only 26 errors, but in cases where there are hundreds of errors it can be really hard to tell whether all the corruptions are in nonclustered indexes (i.e. indexes with IDs &gt; 1). Luckily, there&#39;s an undocumented option to all the <font face=\"courier new,courier\">DBCC CHECK*<\/font> commands &#8211; <font face=\"courier new,courier\">WITH TABLERESULTS<\/font>. The option is undocumented because the output can change from release to release, but basically this converts the DBCC output into tabular form. Try running lines 48-50 in the script and you&#39;ll see what I mean. One of the columns in the output is IndexId &#8211; so you can easily see whether all the errors are in nonclustered indexes. In this case, they are, and all in one index of the Customers table.<\/font> <\/font>\n<\/p>\n<p>\n<font size=\"2\">You could run lines 55-57 of the script to prove&nbsp;to yourself that repairs can&#39;t be run online, and then realize that we can address the problem without having to run repair or restore. First off we need to figure out the name of the index to fix &#8211; index ID 2 of the Customers table. Lines 77-80 run <font face=\"courier new,courier\">sp_HelpIndex<\/font>&nbsp;on the table (although I should really be using Kimberly&#39;s <\/font><a href=\"http:\/\/www.sqlskills.com\/blogs\/kimberly\/updates-fixes-to-sp_helpindex2\/\"><font face=\"courier new,courier\" size=\"2\">sp_HelpIndex2<\/font><\/a><font size=\"2\">): <\/font>\n<\/p>\n<blockquote>\n<p>\n\t<font face=\"courier new,courier\"><font size=\"2\"><font color=\"#0000ff\">USE<\/font> DemoNCIndex<br \/>\n\tGO<br \/>\n\t<font color=\"#0000ff\">EXEC<\/font> <font color=\"#800000\">sp_HelpIndex<\/font> <font color=\"#ff0000\">&#39;Customers&#39;<\/font><\/font><font size=\"2\"><font color=\"#808080\">;<br \/>\n\t<\/font>GO<\/font><\/font><font size=\"2\"> <\/font>\n\t<\/p>\n<p>\n\t<font size=\"2\"><font face=\"Courier New\">index_name&nbsp;&nbsp;&nbsp;&nbsp; index_description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; index_keys<br \/>\n\t&#8212;&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;<br \/>\n\tCustomerName&nbsp;&nbsp; nonclustered located on PRIMARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LastName<br \/>\n\tCustomerPK&nbsp;&nbsp;&nbsp;&nbsp; clustered, unique, primary key located on PRIMARY&nbsp;&nbsp; CustomerID<\/font> <\/font>\n\t<\/p>\n<\/blockquote>\n<p><\/font><\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">The nonclustered index is called CustomerName. Plug in the&nbsp;index name to line 82, then try fixing the index by doing an online index rebuild, and run <font face=\"courier new,courier\">DBCC CHECKDB<\/font> afterwards (lines 82-89). The corruption hasn&#39;t been fixed! Online index rebuild reads the <em>old<\/em> index to build the new one so the new index has the same missing rows as the old one. We need to do an <em>offline<\/em> index rebuild &#8211; with lines 110-115. After the last <font face=\"courier new,courier\">DBCC CHECKDB<\/font>, the index is fixed up. Now, on SQL Server 2008, you may or may not get a query plan for the index rebuild that doesn&#39;t use the old index, because the query optimizer has some more plan choices available to it&nbsp;&#8211; so on SQL Server 2008 you may need to do an actual drop and create of the broken index (carefully, if its enforcing a constraint). <\/font>\n<\/p>\n<p>\n<font face=\"verdana,geneva\" size=\"2\">So &#8211; just because <font face=\"courier new,courier\">DBCC CHECKDB<\/font> reports a ton of errors, that doesn&#39;t necessarily mean that the database needs to be taken (essentially) offline to repair it &#8211; check through the errors to see if it&#39;s just nonclustered indexes that are affected.<\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog post describes the demo &quot;2 &#8211; NC Indexes&quot; from my Corruption Survival Techniques conference session from various conferences in 2008. The links to the scripts and databases to use are in this blog post. Edit 6\/4\/2012: Be aware that in versions of SQL Server from 2008 onwards, you may only be able to [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,27,30,31,34,35,38,47,74],"tags":[],"class_list":["post-967","post","type-post","status-publish","format-standard","hentry","category-checkdb-from-every-angle","category-conferences","category-corruption","category-database-maintenance","category-dbcc","category-disaster-recovery","category-example-scripts","category-indexes-from-every-angle","category-repair"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>TechEd demo: nonclustered index corruption - 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\/teched-demo-nonclustered-index-corruption\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"TechEd demo: nonclustered index corruption - Paul S. Randal\" \/>\n<meta property=\"og:description\" content=\"This blog post describes the demo &quot;2 &#8211; NC Indexes&quot; from my Corruption Survival Techniques conference session from various conferences in 2008. The links to the scripts and databases to use are in this blog post. Edit 6\/4\/2012: Be aware that in versions of SQL Server from 2008 onwards, you may only be able to [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/\" \/>\n<meta property=\"og:site_name\" content=\"Paul S. Randal\" \/>\n<meta property=\"article:published_time\" content=\"2008-12-17T11:03:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-04-13T16:54:11+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=\"5 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\/teched-demo-nonclustered-index-corruption\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/\",\"name\":\"TechEd demo: nonclustered index corruption - Paul S. Randal\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\"},\"datePublished\":\"2008-12-17T11:03:00+00:00\",\"dateModified\":\"2017-04-13T16:54:11+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"TechEd demo: nonclustered index corruption\"}]},{\"@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":"TechEd demo: nonclustered index corruption - 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\/teched-demo-nonclustered-index-corruption\/","og_locale":"en_US","og_type":"article","og_title":"TechEd demo: nonclustered index corruption - Paul S. Randal","og_description":"This blog post describes the demo &quot;2 &#8211; NC Indexes&quot; from my Corruption Survival Techniques conference session from various conferences in 2008. The links to the scripts and databases to use are in this blog post. Edit 6\/4\/2012: Be aware that in versions of SQL Server from 2008 onwards, you may only be able to [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/","og_site_name":"Paul S. Randal","article_published_time":"2008-12-17T11:03:00+00:00","article_modified_time":"2017-04-13T16:54:11+00:00","author":"Paul Randal","twitter_misc":{"Written by":"Paul Randal","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/","name":"TechEd demo: nonclustered index corruption - Paul S. Randal","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website"},"datePublished":"2008-12-17T11:03:00+00:00","dateModified":"2017-04-13T16:54:11+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/teched-demo-nonclustered-index-corruption\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/paul\/"},{"@type":"ListItem","position":2,"name":"TechEd demo: nonclustered index corruption"}]},{"@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\/967","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=967"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/967\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/media?parent=967"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/categories?post=967"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/tags?post=967"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}