{"id":375,"date":"2016-11-30T13:57:29","date_gmt":"2016-11-30T13:57:29","guid":{"rendered":"https:\/\/sqldoubleg.live-website.com\/?p=375"},"modified":"2016-11-30T13:57:29","modified_gmt":"2016-11-30T13:57:29","slug":"in-memory-logging-much-cooler-than-disk-based","status":"publish","type":"post","link":"https:\/\/www.sqldoubleg.com\/es\/2016\/11\/30\/in-memory-logging-much-cooler-than-disk-based\/","title":{"rendered":"In-Memory logging, much cooler than disk based"},"content":{"rendered":"<p>This week I want to look at one of the most important parts, in my opinion, that allow In-Memory to outperform and scale better than the traditional engine, and this is the transaction log usage.&nbsp;Last week we started exploring some of the cool features that the new In-Memory engine (code name Hekaton) has brought into play, looking at the <a href=\"https:\/\/sqldoubleg.live-website.com\/2016\/11\/23\/in-memory-nonclustered-indexes-much-cooler-than-disk-based\/\" target=\"_blank\">differences between Non-Clustered indexes<\/a> when they are memory optimized or disk based. That was cool. <\/p>\n<p>This week I want to look at one of the most important parts, in my opinion, that allow In-Memory to outperform and scale better than the traditional engine, and this is the transaction log usage.<\/p>\n<p>&nbsp;<br \/>\n<strong>Background<\/strong><\/p>\n<p>SQL Servers in order to guarantee Durability (that&#8217;s the D from <a href=\"https:\/\/en.wikipedia.org\/wiki\/ACID\" target=\"_blank\">ACID<\/a>) uses the transaction log if a way that every operation has to be written first there before sending the commit acknowledgment to the client.<\/p>\n<p>This is called <a href=\"https:\/\/technet.microsoft.com\/en-us\/library\/ms186259(v=sql.105).aspx\" target=\"_blank\">Write-Ahead logging<\/a>, and due to its own nature, there are some obvious scalability problems. <\/p>\n<p>Think about it, if each record we insert, update or delete has to be written to the transaction log first and there is only one transaction log file per database, that can be a real bottleneck for highly transactional system, where multiple processes will be competing each other to make those writes to keep processing data.<\/p>\n<p>&nbsp;<br \/>\n<strong>In-Memory Engine<\/strong><\/p>\n<p>According to the <a href=\"https:\/\/www.microsoft.com\/en-us\/research\/wp-content\/uploads\/2013\/06\/Hekaton-Sigmod2013-final.pdf\" target=\"_blank\">original whitepaper<\/a> one of the biggest challenges when developing the new engine was scalability and as we&#8217;ve seen, it&#8217;d be difficult if things kept being done the same way.<\/p>\n<p>But on the other hand, working with datasets exclusively in memory, would any failure happens, recovery might be impossible, hence there is no other way than hardening that data to disk to guarantee the Durability of each transaction which is committed.<\/p>\n<p>What is cool is how this is achieved, but as always, let me write some queries to show you. <\/p>\n<p>I&#8217;ll be using [WideWorldImporters] database if you want to follow me.<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nUSE WideWorldImporters\r\nGO\r\nSELECT VehicleTemperatureID, VehicleRegistration, ChillerSensorNumber, RecordedWhen, Temperature, FullSensorData, IsCompressed, CompressedSensorData\r\nINTO [Warehouse].[VehicleTemperatures_DiskBased] \r\nFROM [Warehouse].[VehicleTemperatures]\r\nGO\r\n<\/pre>\n<p>That would create an identical (~ish) copy of one of our In-Memory tables, but disk based so we can see the difference when we DELETE a number of rows.<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nCHECKPOINT\r\nGO\r\n\r\nBEGIN TRANSACTION DEL_100_DISK_BASED\r\n \r\nDELETE TOP(100) t\r\nFROM [Warehouse].[VehicleTemperatures_DiskBased] AS t\r\n \r\nCOMMIT\r\nGO\r\n \r\nSELECT *\r\nINTO #t\r\nFROM sys.fn_dblog(NULL, NULL)\r\n \r\nSELECT [Current LSN]\r\n\t\t, Operation\r\n\t\t, Context\r\n\t\t, [Transaction ID]\r\n\t\t, [Transaction Name]\r\n\t\t, AllocUnitId\r\n\t\t, [Page ID]\r\n\t\t, [Slot ID]\r\n\t\t, [Lock Information]\r\n\t\t, Description\r\nFROM #t\r\nWHERE [Transaction ID] = (SELECT [Transaction ID] FROM #t WHERE [Transaction Name] = 'DEL_100_DISK_BASED')\r\nORDER BY [Current LSN] ASC\r\n\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/01_disk_based_delete_100_rows_commit.png\"  target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/01_disk_based_delete_100_rows_commit.png\" alt=\"01_disk_based_delete_100_rows_commit\" width=\"1239\" height=\"438\" class=\"aligncenter size-full wp-image-377\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/01_disk_based_delete_100_rows_commit.png 1239w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/01_disk_based_delete_100_rows_commit-300x106.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/01_disk_based_delete_100_rows_commit-1024x362.png 1024w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/01_disk_based_delete_100_rows_commit-150x53.png 150w\" sizes=\"(max-width: 1239px) 100vw, 1239px\" \/><\/a><\/p>\n<p>See how for each of the records we have deleted, a record in the transaction log is also required, not very efficient but that&#8217;s how it is.<\/p>\n<p>Now we can see that it get even worse if we ROLLBACK our transaction.<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nCHECKPOINT\r\nGO\r\n\r\nBEGIN TRANSACTION DEL_100_DISK_BASED_ROLLBACK\r\n \r\nDELETE TOP(100) t\r\nFROM [Warehouse].[VehicleTemperatures_DiskBased] AS t\r\n \r\nROLLBACK\r\nGO\r\n \r\nSELECT *\r\nINTO #t2\r\nFROM sys.fn_dblog(NULL, NULL)\r\n \r\nSELECT [Current LSN]\r\n\t\t, Operation\r\n\t\t, Context\r\n\t\t, [Transaction ID]\r\n\t\t, [Transaction Name]\r\n\t\t, AllocUnitId\r\n\t\t, [Page ID]\r\n\t\t, [Slot ID]\r\n\t\t, [Lock Information]\r\n\t\t, Description\r\nFROM #t2\r\nWHERE [Transaction ID] = (SELECT [Transaction ID] FROM #t2 WHERE [Transaction Name] = 'DEL_100_DISK_BASED_ROLLBACK')\r\nORDER BY [Current LSN] ASC\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/02_disk_based_delete_100_rows_rollback.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/02_disk_based_delete_100_rows_rollback.png\" alt=\"02_disk_based_delete_100_rows_rollback\" width=\"1237\" height=\"437\" class=\"aligncenter size-full wp-image-378\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/02_disk_based_delete_100_rows_rollback.png 1237w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/02_disk_based_delete_100_rows_rollback-300x106.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/02_disk_based_delete_100_rows_rollback-1024x362.png 1024w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/02_disk_based_delete_100_rows_rollback-150x53.png 150w\" sizes=\"(max-width: 1237px) 100vw, 1237px\" \/><\/a><\/p>\n<p>Now we need double the rows, because for each row we&#8217;ve said it&#8217;s been deleted, we have to tell SQL Server that was not actually deleted (COMPENSATION due to ROLLBACK) in case of recovery (crash recovery or backup recovery). That&#8217;s so bad.<\/p>\n<p>But not everything is lost yet \ud83d\ude42 let&#8217;s check how the In-Memory engine deal with this problem<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nCHECKPOINT\r\nGO\r\n\r\nBEGIN TRANSACTION DEL_100_IN_MEMORY\r\n \r\nDELETE TOP(100) t\r\nFROM [Warehouse].[VehicleTemperatures] AS t\r\n \r\nCOMMIT\r\nGO\r\n \r\nSELECT *\r\nINTO #t3\r\nFROM sys.fn_dblog(NULL, NULL)\r\n \r\nSELECT [Current LSN]\r\n\t\t, Operation\r\n\t\t, Context\r\n\t\t, [Transaction ID]\r\n\t\t, [Transaction Name]\r\n\t\t, AllocUnitId\r\n\t\t, [Page ID]\r\n\t\t, [Slot ID]\r\n\t\t, [Lock Information]\r\n\t\t, Description\r\nFROM #t3\r\nWHERE [Transaction ID] = (SELECT [Transaction ID] FROM #t3 WHERE [Transaction Name] = 'DEL_100_IN_MEMORY')\r\nORDER BY [Current LSN] ASC\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/03_in_memory_delete_100_rows_commit.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/03_in_memory_delete_100_rows_commit.png\" alt=\"03_in_memory_delete_100_rows_commit\" width=\"1234\" height=\"183\" class=\"aligncenter size-full wp-image-379\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/03_in_memory_delete_100_rows_commit.png 1234w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/03_in_memory_delete_100_rows_commit-300x44.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/03_in_memory_delete_100_rows_commit-1024x152.png 1024w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/03_in_memory_delete_100_rows_commit-150x22.png 150w\" sizes=\"(max-width: 1234px) 100vw, 1234px\" \/><\/a><\/p>\n<p>That&#8217;s better! According to the whitepaper <strong><em>Hekaton\u2019s transaction log is designed for high efficiency and scale. Each transaction is logged in a single, potentially large, log record. <\/em><\/strong><\/p>\n<p>SQL Server would write one single record for the whole transaction as this has been committed, but how does it work when we rollback our transaction?<\/p>\n<pre class=\"brush: tsql; title: ; notranslate\" title=\"\">\r\nCHECKPOINT\r\nGO\r\n\r\nBEGIN TRANSACTION DEL_100_IN_MEMORY_ROLLBACK\r\n \r\nDELETE TOP(100) t\r\nFROM [Warehouse].[VehicleTemperatures] AS t\r\n \r\nROLLBACK\r\nGO\r\n \r\nSELECT *\r\nINTO #t4\r\nFROM sys.fn_dblog(NULL, NULL)\r\n \r\nSELECT [Current LSN]\r\n\t\t, Operation\r\n\t\t, Context\r\n\t\t, [Transaction ID]\r\n\t\t, [Transaction Name]\r\n\t\t, AllocUnitId\r\n\t\t, [Page ID]\r\n\t\t, [Slot ID]\r\n\t\t, [Lock Information]\r\n\t\t, Description\r\nFROM #t4\r\nWHERE [Transaction ID] = (SELECT [Transaction ID] FROM #t4 WHERE [Transaction Name] = 'DEL_100_IN_MEMORY_ROLLBACK')\r\nORDER BY [Current LSN] ASC\r\n\r\n<\/pre>\n<p><a href=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/04_in_memory_delete_100_rows_rollback.png\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/sqldoubleg.live-website.com\/wp-content\/uploads\/2016\/11\/04_in_memory_delete_100_rows_rollback.png\" alt=\"04_in_memory_delete_100_rows_rollback\" width=\"1236\" height=\"183\" class=\"aligncenter size-full wp-image-380\" srcset=\"https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/04_in_memory_delete_100_rows_rollback.png 1236w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/04_in_memory_delete_100_rows_rollback-300x44.png 300w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/04_in_memory_delete_100_rows_rollback-1024x152.png 1024w, https:\/\/www.sqldoubleg.com\/wp-content\/uploads\/2016\/11\/04_in_memory_delete_100_rows_rollback-150x22.png 150w\" sizes=\"(max-width: 1236px) 100vw, 1236px\" \/><\/a><\/p>\n<p>Nothing, nada, rien, nichts, \u043d\u0438\u0447\u0435\u0433\u043e. That&#8217;s even better!<\/p>\n<p>And that is because in this case, the transaction log file contains only <strong><em>enough information to redo committed transactions<\/em><\/strong>, the whole set of changes goes to CHECKPOINT files, which are out of the scope of this post, but I&#8217;ll talk about them in the future for sure since they are key in all this process.<\/p>\n<p>&nbsp;<br \/>\n<strong>Conclusion<\/strong><\/p>\n<p>The changes done in the way SQL Server can provide Durability through the In-Memory engine are really impressive and can take out all the contention created by having just one transaction log file, by reducing its usage to the minimum.<\/p>\n<p>There is still a lot to explore in this topic, so stay tuned for future posts!<\/p>\n<p>Thanks for reading.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This week I want to look at one of the most important parts, in my opinion, that allow In-Memory to outperform and scale better than the traditional engine, and this is the&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,21],"tags":[53,54,23,12,56],"_links":{"self":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/posts\/375"}],"collection":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/comments?post=375"}],"version-history":[{"count":0,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/posts\/375\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/media?parent=375"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/categories?post=375"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqldoubleg.com\/es\/wp-json\/wp\/v2\/tags?post=375"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}