<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQLWorkshops.com Blog &#187; Articles</title>
	<atom:link href="http://blog.sqlworkshops.com/category/articles/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.sqlworkshops.com</link>
	<description>Microsoft SQL Server Performance Monitoring &#38; Tuning</description>
	<lastBuildDate>Mon, 16 May 2016 15:05:42 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Tempdb Metadata Contention in SQL Server &#8211; Table Variable Vs Temporary Table</title>
		<link>http://blog.sqlworkshops.com/tempdb-metadata-contention-in-sql-server-table-variable-vs-temporary-table/</link>
		<comments>http://blog.sqlworkshops.com/tempdb-metadata-contention-in-sql-server-table-variable-vs-temporary-table/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:40:07 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=246</guid>
		<description><![CDATA[In SQL Server, the concurrent creation of temporary tables from many sessions can lead to tempdb metadata contention. Tempdb metadata contention does not affect the concurrent creation of table variables. When SQL Server creates temporary tables, it has to update &#8230; <a href="http://blog.sqlworkshops.com/tempdb-metadata-contention-in-sql-server-table-variable-vs-temporary-table/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In SQL Server, the concurrent creation of temporary tables from many sessions can lead to tempdb metadata contention. Tempdb metadata contention does not affect the concurrent creation of table variables.</p>
<p>When SQL Server creates temporary tables, it has to update metadata information in the system based tables, like sys.sysschobjs (like PAGELATCH_EX and PAGELATCH_SH waits). This overhead is not there for table variables. Tempdb metadata management overhead leads to faster table variable declaration than temporary table creation, which is demonstrated in the below video. The tempdb metadata management overhead associated with temporary table is due to the temporary table having different scope than table variable where it is limited to the batch of stored procedure. Concurrent creation of temporary tables from many sessions will lead to concurrent update of metadata information in the system based tables, which leads to tempdb metadata contention.</p>
<p>Below video with hands-on example demonstrates the tempdb metadata contention. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/yIyZiNYoH-s" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out <a href="http://www.sqlvideo.com">http://www.sqlvideo.com</a> for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/tempdb-metadata-contention-in-sql-server-table-variable-vs-temporary-table/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AlwaysOn Availability Groups Synchronous Replica Readable Secondary Data Access Latency</title>
		<link>http://blog.sqlworkshops.com/alwayson-availability-groups-synchronous-replica-readable-secondary-data-access-latency/</link>
		<comments>http://blog.sqlworkshops.com/alwayson-availability-groups-synchronous-replica-readable-secondary-data-access-latency/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:39:36 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=266</guid>
		<description><![CDATA[With SQL Server AlwaysOn Availability Groups, when you configure a secondary in synchronous-commit mode for read-only access, there can be data access latency. If you make changes to your data like if you perform insert, update or delete in primary, &#8230; <a href="http://blog.sqlworkshops.com/alwayson-availability-groups-synchronous-replica-readable-secondary-data-access-latency/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>With SQL Server AlwaysOn Availability Groups, when you configure a secondary in synchronous-commit mode for read-only access, there can be data access latency.</p>
<p>If you make changes to your data like if you perform insert, update or delete in primary, those changes may not be visible in the secondary, synchronous replica enabled for read-only access for a certain amount of time, because writing to Log is synchronous, but not REDO. REDO is asynchronous, that is, applying those changes from Log is asynchronous.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/JXgcOWopk5E" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/alwayson-availability-groups-synchronous-replica-readable-secondary-data-access-latency/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Seek or Scan &#8211; Cost Based Optimizer in SQL Server</title>
		<link>http://blog.sqlworkshops.com/seek-or-scan-cost-based-optimizer-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/seek-or-scan-cost-based-optimizer-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:39:06 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=264</guid>
		<description><![CDATA[When SQL Server has a choice of plans, it will compare the cost among a set of execution plans and will choose the cheapest one. In some cases, even though the cost of seek is slightly higher than the cost &#8230; <a href="http://blog.sqlworkshops.com/seek-or-scan-cost-based-optimizer-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>When SQL Server has a choice of plans, it will compare the cost among a set of execution plans and will choose the cheapest one.</p>
<p>In some cases, even though the cost of seek is slightly higher than the cost of scan, SQL Server Optimize might still choose a seek based plan as demonstrated in the video.</p>
<p>SQL Server may not evaluate all possible plans, there are various stages of optimization and SQL Server will evaluate a subset of plans at these stages.<br />
The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/PTHzmG1a6Bg" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/seek-or-scan-cost-based-optimizer-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimize for Ad Hoc Workloads &#8211; SQL Server Configuration Parameter</title>
		<link>http://blog.sqlworkshops.com/optimize-for-ad-hoc-workloads-sql-server-configuration-parameter/</link>
		<comments>http://blog.sqlworkshops.com/optimize-for-ad-hoc-workloads-sql-server-configuration-parameter/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:38:39 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=262</guid>
		<description><![CDATA[SQL Server configuration parameter “optimized for ad hoc workloads” can be very useful when you execute lots of single use ad hoc statements or dynamic SQL statements by reducing memory usage of plan cache. If the majority of ad hoc &#8230; <a href="http://blog.sqlworkshops.com/optimize-for-ad-hoc-workloads-sql-server-configuration-parameter/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>SQL Server configuration parameter “optimized for ad hoc workloads” can be very useful when you execute lots of single use ad hoc statements or dynamic SQL statements by reducing memory usage of plan cache. If the majority of ad hoc statements or dynamic SQL statements execute more than once, then “optimize for ad hoc workloads” configuration parameter can increase the CPU usage due to additional optimization cost and hence it is not recommended in such scenarios</p>
<p>When the plan is stable, that is, when the query hash and query plan hash is the same for all executions, it is recommended that you parameterize these statements to reduce plan cache pollution.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/s4UOMzNGIzQ" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/optimize-for-ad-hoc-workloads-sql-server-configuration-parameter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extended Event Locks Lock Waits in SQL Server</title>
		<link>http://blog.sqlworkshops.com/extended-event-locks-lock-waits-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/extended-event-locks-lock-waits-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:38:18 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=260</guid>
		<description><![CDATA[When it comes to lock waits, one of the important information we need to know is which statement waited for locks and how long. This is possible with extended events; it is not possible with SQL Server profiler. locks_lock_waits event &#8230; <a href="http://blog.sqlworkshops.com/extended-event-locks-lock-waits-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>When it comes to lock waits, one of the important information we need to know is which statement waited for locks and how long. This is possible with extended events; it is not possible with SQL Server profiler.</p>
<p>locks_lock_waits event is very useful to find statements that waited for locks more than a certain amount of time.</p>
<p>When you are using extended events, always use the counters predicate to limit the amount of events you are collecting.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/j-UyTQo11rQ" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/extended-event-locks-lock-waits-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extended Event Query Post Execution Showplan in SQL Server</title>
		<link>http://blog.sqlworkshops.com/extended-event-query-post-execution-showplan-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/extended-event-query-post-execution-showplan-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:37:57 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=258</guid>
		<description><![CDATA[Query Post Execution Showplan event is a very useful event to find problematic queries and execution plans based on CPU usage or duration while analyzing performance issues. It can increase the execution time of all queries by a fraction of &#8230; <a href="http://blog.sqlworkshops.com/extended-event-query-post-execution-showplan-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Query Post Execution Showplan event is a very useful event to find problematic queries and execution plans based on CPU usage or duration while analyzing performance issues.</p>
<p>It can increase the execution time of all queries by a fraction of a millisecond, irrespective of the total query cost, which means, the overhead of query_post_execution_showplan event is high for cheaper queries compared to expensive queries.</p>
<p>In all cases, one should enable the event on an ad hoc basis and with restrictive predicate to limit the number of events.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/6cDRwAvmfcc" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/extended-event-query-post-execution-showplan-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PAGELATCH Waits with Update Statements in SQL Server &#8211; PAGELATCH_EX and PAGELATCH_SH</title>
		<link>http://blog.sqlworkshops.com/pagelatch-waits-with-update-statements-in-sql-server-pagelatch_ex-and-pagelatch_sh/</link>
		<comments>http://blog.sqlworkshops.com/pagelatch-waits-with-update-statements-in-sql-server-pagelatch_ex-and-pagelatch_sh/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:37:25 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=255</guid>
		<description><![CDATA[In SQL Server, concurrent writes or read / write to the same page can lead to PAGELATCH (like PAGELATCH_EX and PAGELATCH_SH) waits or what is knowns as PAGELATCH contention. One common use case is when invoice numbers are stored in &#8230; <a href="http://blog.sqlworkshops.com/pagelatch-waits-with-update-statements-in-sql-server-pagelatch_ex-and-pagelatch_sh/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In SQL Server, concurrent writes or read / write to the same page can lead to PAGELATCH (like PAGELATCH_EX and PAGELATCH_SH) waits or what is knowns as PAGELATCH contention.</p>
<p>One common use case is when invoice numbers are stored in a table. If the row is narrow, then many rows can fit in the 8KB page. This can lead to many invoicing number sequences being stored on the same page. When different invoicing number sequences are accessed from concurrent sessions, this can lead to PAGELATCH waits.</p>
<p>The way to solve this is to widen the rows so each row takes about a page and we don’t have contention on the same page.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/cqZA_l0fOTc" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/pagelatch-waits-with-update-statements-in-sql-server-pagelatch_ex-and-pagelatch_sh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tempdb Allocation Contention in SQL Server</title>
		<link>http://blog.sqlworkshops.com/tempdb-allocation-contention-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/tempdb-allocation-contention-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:36:53 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=248</guid>
		<description><![CDATA[In SQL Server, the concurrent creation of temporary objects (temporary tables and table variables) from many sessions can lead to tempdb allocation contention. This contention occurs on PFS and SGAM pages in tempdb (like PAGELATCH_EX and PAGELATCH_SH waits). It is &#8230; <a href="http://blog.sqlworkshops.com/tempdb-allocation-contention-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In SQL Server, the concurrent creation of temporary objects (temporary tables and table variables) from many sessions can lead to tempdb allocation contention. This contention occurs on PFS and SGAM pages in tempdb (like PAGELATCH_EX and PAGELATCH_SH waits). It is recommended to create additional data files for tempdb and implement trace flag 1118 to reduce this type of contention. Creating temporary objects, in a stored procedure will lead to temp table caching, this can also help reduce tempdb allocation contention.</p>
<p>After addressing Tempdb Allocation Contention, you will most probably encounter <a href="http://www.sqlvideo.com/AllVideos/Tempdb-Metadata-Contention---Table-Variable-Vs-Temporary-Table">Tempdb Metadata Contention</a> when you are using temporary tables (not when you are using table variables due to <a href="http://www.sqlvideo.com/AllVideos/Temp-Table-Caching-in-SQL-Server">Temp Table Caching</a>).</p>
<p>Below video with hands-on example demonstrates the tempdb allocation contention and explains the steps to reduce contention. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/Weao_qawXaE" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/tempdb-allocation-contention-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>In-Memory OLTP Memory Optimized Table Variables Vs Disk Based Table Variable in SQL Server</title>
		<link>http://blog.sqlworkshops.com/in-memory-oltp-memory-optimized-table-variables-vs-disk-based-table-variable-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/in-memory-oltp-memory-optimized-table-variables-vs-disk-based-table-variable-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:36:09 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=243</guid>
		<description><![CDATA[Starting SQL Server 2014, it is possible to use memory optimized table variables. These are table variables declared using a table type which is memory optimized. Memory optimized table variables have no disk footprint and don’t have PAGELATCH (like PAGELATCH_EX &#8230; <a href="http://blog.sqlworkshops.com/in-memory-oltp-memory-optimized-table-variables-vs-disk-based-table-variable-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Starting SQL Server 2014, it is possible to use memory optimized table variables. These are table variables declared using a table type which is memory optimized. Memory optimized table variables have no disk footprint and don’t have PAGELATCH (like PAGELATCH_EX and PAGELATCH_SH) or LOGBUFFER waits, hence they result in faster performance compared to traditional disk based table variables.</p>
<p>Memory optimized table variables can be used in place of disk based table variables when possible.</p>
<p>Below video compares the performance difference between memory optimized table variables and traditional disk based table variables. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/-DVVcxvhyhM" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/in-memory-oltp-memory-optimized-table-variables-vs-disk-based-table-variable-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Temp Table Caching in SQL Server</title>
		<link>http://blog.sqlworkshops.com/temp-table-caching-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/temp-table-caching-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:35:44 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=236</guid>
		<description><![CDATA[SQL Server caches temporary objects (temporary tables and table variables), that are created in a stored procedure. Temporary objects that are created either in dynamic SQL statement or by using sp_executesql are not cached. Temp table caching can lead to &#8230; <a href="http://blog.sqlworkshops.com/temp-table-caching-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>SQL Server caches temporary objects (temporary tables and table variables), that are created in a stored procedure. Temporary objects that are created either in dynamic SQL statement or by using sp_executesql are not cached. Temp table caching can lead to better performance by reducing <a href="http://www.sqlvideo.com/AllVideos/Tempdb-Allocation-Contention-in-SQL-Server">Tempdb Allocation Contention</a>. SQL Server will not cache temporary table in certain cases, for example, if a DDL operation is performed on the temporary table (dropping temporary table is not a problem), or if a named constraint is created on the temporary table.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/fEpziVwRxqI" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/temp-table-caching-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Filtered Statistics in SQL Server</title>
		<link>http://blog.sqlworkshops.com/filtered-statistics-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/filtered-statistics-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:35:21 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=234</guid>
		<description><![CDATA[In SQL Server, Filtered Statistics can improve cardinality estimation, i.e. when joining lookup table, or while joining fact table and dimension table. For this reason, SQL Server supports the creation of up to 30,000 statistics on non-indexed columns. Better estimation &#8230; <a href="http://blog.sqlworkshops.com/filtered-statistics-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In SQL Server, Filtered Statistics can improve cardinality estimation, i.e. when joining lookup table, or while joining fact table and dimension table. For this reason, SQL Server supports the creation of up to 30,000 statistics on non-indexed columns. Better estimation with filtered statistics can lead to faster query execution against star schema based data warehouses, in many cases by estimating the optimal join strategy, amount of memory and executing the query in parallel.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/Oz2Z19l5IwU" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/filtered-statistics-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Parallel Insert Into &#8211; Table Variable Vs Temporary Table in SQL Server</title>
		<link>http://blog.sqlworkshops.com/parallel-insert-into-table-variable-vs-temporary-table-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/parallel-insert-into-table-variable-vs-temporary-table-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:34:42 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=230</guid>
		<description><![CDATA[In SQL Server, for insert into select statements, when the target for insert into is temporary table, the select statement can execute in parallel. When the target is table variable, SQL Server will not execute the select statement in parallel, &#8230; <a href="http://blog.sqlworkshops.com/parallel-insert-into-table-variable-vs-temporary-table-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In SQL Server, for insert into select statements, when the target for insert into is temporary table, the select statement can execute in parallel. When the target is table variable, SQL Server will not execute the select statement in parallel, which can lead to poor performance.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/45UMnfz23i4" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/parallel-insert-into-table-variable-vs-temporary-table-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cardinality Estimation &#8211; Table Variable Vs Temporary Table in SQL Serve</title>
		<link>http://blog.sqlworkshops.com/cardinality-estimation-table-variable-vs-temporary-table-in-sql-serve/</link>
		<comments>http://blog.sqlworkshops.com/cardinality-estimation-table-variable-vs-temporary-table-in-sql-serve/#comments</comments>
		<pubDate>Sun, 15 May 2016 18:34:06 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=225</guid>
		<description><![CDATA[SQL Server creates and maintains statistics for temporary tables, which lead to better cardinality estimation and optimal execution plan generation. Table variables have no statistics, which can result in poor cardinality estimation and non-optimal execution plan creation. When you add &#8230; <a href="http://blog.sqlworkshops.com/cardinality-estimation-table-variable-vs-temporary-table-in-sql-serve/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>SQL Server creates and maintains statistics for temporary tables, which lead to better cardinality estimation and optimal execution plan generation. Table variables have no statistics, which can result in poor cardinality estimation and non-optimal execution plan creation. When you add query hint option (recompile) when using table variable, SQL Server can use heuristics based estimates, taking into consideration the total number of rows in the table variable; this can be helpful in some scenarios.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/jZKPmC6pCBg" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out www.sqlvideo.com for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/cardinality-estimation-table-variable-vs-temporary-table-in-sql-serve/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Understanding ASYNC_NETWORK_IO Waits in SQL Server</title>
		<link>http://blog.sqlworkshops.com/understanding-async_network_io-waits-in-sql-server/</link>
		<comments>http://blog.sqlworkshops.com/understanding-async_network_io-waits-in-sql-server/#comments</comments>
		<pubDate>Sun, 15 May 2016 04:52:40 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=198</guid>
		<description><![CDATA[In SQL Server, ASYNC_NETWORK_IO wait time can be high due to slow network, like when the database is in the cloud and the application is on premise. Furthermore, it can be slow when CPU utilization is high in the application &#8230; <a href="http://blog.sqlworkshops.com/understanding-async_network_io-waits-in-sql-server/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In SQL Server, ASYNC_NETWORK_IO wait time can be high due to slow network, like when the database is in the cloud and the application is on premise. Furthermore, it can be slow when CPU utilization is high in the application server preventing timely fetching of all rows or, in most cases, when the application reads a row, does some work processing the row, before reading the next row. When the server sends data, the ASYNC_NETWORK_IO wait time will not increase beyond 2000ms. After 2000ms the server will increase the wait count and reset the wait time, which is demonstrated in the video.</p>
<p>The below video covers ASYNC_NETWORK_IO waits while the server is sending data to the client. The video suggests ways to identify slow network and discusses high ASYNC_NETWORK_IO wait time and guidelines to reduce the waits.</p>
<p>SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/difEyUkr64g" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out <a href="http://www.sqlvideo.com"><span style="text-decoration: underline;"><span style="color: #0066cc;">http://www.sqlvideo.com</span></span></a> for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/understanding-async_network_io-waits-in-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resource Governor in SQL Server &#8211; Workload Throttling</title>
		<link>http://blog.sqlworkshops.com/resource-governor-in-sql-server-workload-throttling/</link>
		<comments>http://blog.sqlworkshops.com/resource-governor-in-sql-server-workload-throttling/#comments</comments>
		<pubDate>Sat, 14 May 2016 17:48:14 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=196</guid>
		<description><![CDATA[Resource Governor in SQL Server provides CPU, Memory and I/O throttling. In SQL Server 2014 and earlier, CPU throttling works only for similar kind of workloads and not for mixed workloads, where high importance workload group gets 9 slices of &#8230; <a href="http://blog.sqlworkshops.com/resource-governor-in-sql-server-workload-throttling/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Resource Governor in SQL Server provides CPU, Memory and I/O throttling. In SQL Server 2014 and earlier, CPU throttling works only for similar kind of workloads and not for mixed workloads, where high importance workload group gets 9 slices of CPU, medium importance gets 3 slices and low 1 slice. In SQL Server 2016, CPU throttling works fine for all kinds of workloads.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/MnUBmK_hcMM" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out <a href="http://www.sqlvideo.com"><span style="text-decoration: underline;"><span style="color: #0066cc;">http://www.sqlvideo.com</span></span></a> for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/resource-governor-in-sql-server-workload-throttling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Data Compression in SQL Server &#8211; Pros and Cons</title>
		<link>http://blog.sqlworkshops.com/data-compression-in-sql-server-pros-and-cons/</link>
		<comments>http://blog.sqlworkshops.com/data-compression-in-sql-server-pros-and-cons/#comments</comments>
		<pubDate>Tue, 10 May 2016 14:12:09 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=194</guid>
		<description><![CDATA[SQL Server supports row and page compression on tables, indexes and partitions. This can lead to reduced I/O and better performance. However, it can also result in additional CPU usage in some cases, outweighing the benefits of data compression. SQL &#8230; <a href="http://blog.sqlworkshops.com/data-compression-in-sql-server-pros-and-cons/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>SQL Server supports row and page compression on tables, indexes and partitions. This can lead to reduced I/O and better performance. However, it can also result in additional CPU usage in some cases, outweighing the benefits of data compression. SQL Server query optimizer does not cost the overhead of expanding the compressed data, which can lead to plan regression as shown in the video.</p>
<p>The below video demonstrates this with hands-on example. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/lnwq1YQvBHc" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out <a href="http://www.sqlvideo.com"><span style="text-decoration: underline;"><span style="color: #0066cc;">http://www.sqlvideo.com</span></span></a> for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/data-compression-in-sql-server-pros-and-cons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server Command Timeout &#8211; Application Timeout &#8211; Attention</title>
		<link>http://blog.sqlworkshops.com/sql-server-command-timeout-application-timeout-attention/</link>
		<comments>http://blog.sqlworkshops.com/sql-server-command-timeout-application-timeout-attention/#comments</comments>
		<pubDate>Mon, 09 May 2016 19:41:15 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=191</guid>
		<description><![CDATA[When you use ODBC or SqlClient to access data from SQL Server, by default the query will be cancelled if there is no response from the server within a certain period of time (30 seconds by default). ODBC or SqlClient &#8230; <a href="http://blog.sqlworkshops.com/sql-server-command-timeout-application-timeout-attention/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>When you use ODBC or SqlClient to access data from SQL Server, by default the query will be cancelled if there is no response from the server within a certain period of time (30 seconds by default). ODBC or SqlClient will start a timer after sending the query to SQL Server and if there are no results from the server within 30 seconds, the query will be cancelled and a timeout error message will be sent to the application. In case a network packet (containing query results) was received within the 30 seconds, and if we are expecting additional network packets (additional rows that couldn’t fit in the first network packet), then the timer is restarted, if the next network packet is not received within this 30 second period, the query will be cancelled.</p>
<p>The common reasons for SQL Command timeout are non-optimal schema or inefficient queries that execute for a long period of time or that miss indexes or lock wait issues. It is important to tune the queries rather than increase the SQL Command timeout settings.</p>
<p>In the video an example is demonstrated where decreasing the network packet size eliminates the timeout, this demonstration is to understand how network packets are involved in resetting the timer and to develop better understanding of timeout. Changing the network packet size is not a solution to avoid timeout, tuning non-optimal schema or inefficient queries or adding indexes or avoiding lock waits are the proper solution.</p>
<p>To identify the command that leads to SQL Command timeout error, you can use Extended Events and monitor event ‘sqlserver.attention’. The extended event script used in the video is available at www.sqlvideo.com/xevents.</p>
<p>In SQL Server Management Studio, the SQL Command timeout can be changed using ‘Options’ in the connection dialog. By default, this is set to ‘0’, which means no timeout. When a query or stored procedure is executing, if you click the ‘Cancel’ button (the red square), the same attention will be sent to the SQL Server (like SQL Command Timeout). And this will in-turn generate ‘sqlserver.attention’ event in Extended Events.</p>
<p>In the below video you can see an example of the SQL Command timeout. SQLTest Tool simulates the hands-on labs for you, no registration necessary. You can practice the online hands-on example while watching the video.</p>
<p><iframe src="//www.youtube.com/embed/7TKdl2nhiZM" height="315" width="560" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<p>Check out <a href="http://www.sqlvideo.com"><span style="text-decoration: underline;"><span style="color: #0066cc;">http://www.sqlvideo.com</span></span></a> for additional hands-on videos.</p>
<p>Subscribe to our newsletter: <a href="https://newsletter.sqlworkshops.com/">https://newsletter.sqlworkshops.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/sql-server-command-timeout-application-timeout-attention/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server 2012: Indirect Checkpoint (Target Recovery Time), get the real scoop</title>
		<link>http://blog.sqlworkshops.com/sql-server-2012-indirect-checkpoint-target-recovery-time-get-the-real-scoop/</link>
		<comments>http://blog.sqlworkshops.com/sql-server-2012-indirect-checkpoint-target-recovery-time-get-the-real-scoop/#comments</comments>
		<pubDate>Tue, 19 Mar 2013 21:58:48 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=161</guid>
		<description><![CDATA[SQL Server 2012 brings a new feature called Indirect Checkpoint. You can read more about it here: http://msdn.microsoft.com/en-us/library/ms189573.aspx. With Indirect Checkpoint, you get smaller and too many I/Os Checkpoint normally writes large blocks of data to disk optimally in single &#8230; <a href="http://blog.sqlworkshops.com/sql-server-2012-indirect-checkpoint-target-recovery-time-get-the-real-scoop/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>SQL Server 2012 brings a new feature called Indirect Checkpoint. You can read more about it here: <a href="http://msdn.microsoft.com/en-us/library/ms189573.aspx">http://msdn.microsoft.com/en-us/library/ms189573.aspx</a>.</p>
<p><strong>With Indirect Checkpoint, you get smaller and too many I/Os</strong></p>
<p>Checkpoint normally writes large blocks of data to disk optimally in single write operation, up to 256KB, depending on the number of contiguous dirty pages in cache that needs to be flushed to disk. Once you turn on the indirect checkpoint feature by setting target recovery time to a non-zero value, the checkpoint writes will turn into single page writes, 8KB writes.</p>
<p>This will lead to too many I/Os. We all know few large I/Os are more efficient than many small I/Os. This may slow down overall write throughput and performance. If you are hosting your server on the cloud based virtual servers, this means, it will increase the cost as you pay by the number of I/O operations you incur.</p>
<p><strong>Too many outstanding I/Os</strong></p>
<p>Normally check point throttles the number of outstanding I/Os by setting threshold based on write latency in order not to overload the storage subsystem. But once you enable indirect checkpoint, SQL Server can queue up hundreds of thousands of I/Os. This will not only overload the storage subsystem, if users want to read data from the database, their I/O requests will be queued up way behind  the indirect checkpoint writes and they may experience very slow response time and timeouts.</p>
<p>You might also see such errors in the errorlog as large number of I/Os in the queue may take a long time to complete:</p>
<p><span style="color: #ff0000;">A time-out occurred while waiting for buffer latch &#8212; type 4, bp 0000000283508040, page 1:1080, stat 0x60d, database id: 16, allocation unit Id: 0/281474976710656, task 0x00000002321BC558 : 0, waittime 300 seconds, flags 0x1a, owning task 0x00000002321BC558. Not continuing to wait.</span></p>
<p><strong>High CPU usage</strong></p>
<p>When you enable indirect checkpoint, you might encounter high CPU usage. One of the CPUs that is performing the write might spin at 100%. This can be monitored by measuring DP_LIST spins as shown below, more than 4 billion spins were noticed by running the below test just once. Also the writers will use much more CPU.</p>
<p>select * from sys.dm_os_spinlock_stats where name = &#8216;DP_LIST&#8217;</p>
<p>You will notice the updates are much slower when indirect checkpoint is enabled.</p>
<p>In extreme cases when you try to restart the SQL Server service, it will take a long time to stop. Meanwhile you can neither connect nor start the service as the service is already in the process of stopping, flushing the dirty pages before shutdown.</p>
<p><strong>You can use the below scripts to reproduce the scenario</strong></p>
<p>use master</p>
<p>if  exists (select * from sys.databases where name = &#8216;sqlworkshops&#8217;)</p>
<p>drop database sqlworkshops</p>
<p>go</p>
<p>use master</p>
<p>create database sqlworkshops on primary (name = &#8216;sqlworkshops_1&#8242;, filename = &#8216;P:sqlworkshops_1.mdf&#8217;, size = 5GB)</p>
<p>log on (name = &#8216;sqlworkshops_log_1&#8242;, filename = &#8216;Q:sqlworkshops_log_1.ldf&#8217;, size = 64MB)</p>
<p>go</p>
<p>use master</p>
<p>alter database sqlworkshops set recovery simple</p>
<p>go</p>
<p>use sqlworkshops</p>
<p>if  exists (select * from sys.objects where name = &#8216;tab71&#8242;)</p>
<p>drop table tab71</p>
<p>go</p>
<p>use sqlworkshops</p>
<p>create table tab71 (c1 int primary key clustered, c2 int, c3 char(2000))</p>
<p>insert into tab71 with (tablock) select top 500000 row_number() over (order by c1.object_id, c2.o) as c1, 1 as c2, replicate(&#8216;a&#8217;, 2000) as c3</p>
<p>from sys.all_columns c1, sys.all_columns c2</p>
<p>update statistics tab71 with fullscan</p>
<p>checkpoint</p>
<p>go</p>
<p>use sqlworkshops</p>
<p>if  exists (select * from sys.objects where name = &#8216;tab72&#8242;)</p>
<p>drop table tab72</p>
<p>go</p>
<p>use sqlworkshops</p>
<p>create table tab72 (c1 int primary key clustered, c2 int, c3 char(2000))</p>
<p>insert into tab72 with (tablock) select top 500000 row_number() over (order by c1.object_id) as c1, 1 as c2, replicate(&#8216;a&#8217;, 2000) as c3</p>
<p>from sys.all_columns c1, sys.all_columns c2</p>
<p>update statistics tab72 with fullscan</p>
<p>checkpoint</p>
<p>go</p>
<p>&nbsp;</p>
<p>&#8211;Session 1:</p>
<p>use sqlworkshops</p>
<p>update tab71 set c2 = 2</p>
<p>go</p>
<p>use sqlworkshops</p>
<p>update tab71 set c2 = 3</p>
<p>go</p>
<p>&nbsp;</p>
<p>&#8211;Session 2 (optional):</p>
<p>use sqlworkshops</p>
<p>update tab72 set c2 = 2</p>
<p>go</p>
<p>use sqlworkshops</p>
<p>update tab72 set c2 = 3</p>
<p>go</p>
<p>&nbsp;</p>
<p>&#8211;To monitor spins:</p>
<p>select * from sys.dm_os_wait_stats</p>
<p>where wait_type = &#8216;DIRTY_PAGE_POLL&#8217;</p>
<p>go</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/sql-server-2012-indirect-checkpoint-target-recovery-time-get-the-real-scoop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stale statistics on a newly created temporary table in a stored procedure can lead to poor performance</title>
		<link>http://blog.sqlworkshops.com/stale-statistics-on-a-newly-created-temporary-table-in-a-stored-procedure-can-lead-to-poor-performance/</link>
		<comments>http://blog.sqlworkshops.com/stale-statistics-on-a-newly-created-temporary-table-in-a-stored-procedure-can-lead-to-poor-performance/#comments</comments>
		<pubDate>Wed, 15 Aug 2012 15:05:09 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=149</guid>
		<description><![CDATA[When you create a temporary table you expect a new table with no past history (statistics based on past existence), this is not true if you have less than 6 updates to the temporary table. This might lead to poor &#8230; <a href="http://blog.sqlworkshops.com/stale-statistics-on-a-newly-created-temporary-table-in-a-stored-procedure-can-lead-to-poor-performance/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p dir="LTR" align="LEFT">When you create a temporary table you expect a new table with no past history (statistics based on past existence), this is not true if you have less than 6 updates to the temporary table. This might lead to poor performance of queries which are sensitive to the content of temporary tables.</p>
<p dir="LTR" align="LEFT">I was optimizing SQL Server Performance at one of my customers who provides search functionality on their website. They use stored procedure with temporary table for the search. The performance of the search depended on who searched what in the past, option (recompile) by itself had no effect. Sometimes a simple search led to timeout because of non-optimal plan usage due to this behavior. This is not a plan caching issue rather temporary table statistics caching issue, which was part of the temporary object caching feature that was introduced in SQL Server 2005 and is also present in SQL Server 2008 and SQL Server 2012. In this customer case we implemented a workaround to avoid this issue (see below for example for workarounds).</p>
<p dir="LTR" align="LEFT">When temporary tables are cached, the statistics are not newly created rather cached from the past and updated based on automatic update statistics threshold. Caching temporary tables/objects is good for performance, but caching stale statistics from the past is not optimal.</p>
<p dir="LTR" align="LEFT">We can work around this issue by disabling temporary table caching by explicitly executing a DDL statement on the temporary table. One possibility is to execute an alter table statement, but this can lead to duplicate constraint name error on concurrent stored procedure execution. The other way to work around this is to create an index.</p>
<p dir="LTR" align="LEFT">I think there might be many customers in such a situation without knowing that stale statistics are being cached along with temporary table leading to poor performance.</p>
<p dir="LTR" align="LEFT">Ideal solution is to have more aggressive statistics update when the temporary table has less number of rows when temporary table caching is used. I will open a connect item to report this issue.</p>
<p dir="LTR" align="LEFT">Meanwhile you can mitigate the issue by creating an index on the temporary table. You can monitor active temporary tables using Windows Server Performance Monitor counter: SQL Server: General Statistics-&gt;Active Temp Tables.</p>
<p dir="LTR" align="LEFT"> The script to understand the issue and the workaround is listed below:</p>
<p>set nocount on</p>
<p>set statistics time off</p>
<p>set statistics io off</p>
<p>drop table tab7</p>
<p>go</p>
<p>create table tab7 (c1 int primary key clustered, c2 int, c3 char(200))</p>
<p>go</p>
<p>create index test on tab7(c2, c1, c3)</p>
<p>go</p>
<p>begin tran</p>
<p>declare @i int</p>
<p>set @i = 1</p>
<p>while @i &lt;= 50000</p>
<p>begin</p>
<p>insert into tab7 values (@i, 1, &#8216;a&#8217;)</p>
<p>set @i = @i + 1</p>
<p>end</p>
<p>commit tran</p>
<p>go</p>
<p>insert into tab7 values (50001, 1, &#8216;a&#8217;)</p>
<p>go</p>
<p>checkpoint</p>
<p>go</p>
<p>drop proc test_slow</p>
<p>go</p>
<p>create proc test_slow @i int</p>
<p>as</p>
<p>begin</p>
<p>declare @j int</p>
<p>create table #temp1 (c1 int primary key)</p>
<p>insert into #temp1 (c1) select @i</p>
<p>select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)</p>
<p>end</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>set statistics time on</p>
<p>set statistics io on</p>
<p>go</p>
<p>&#8211;high reads as expected for parameter &#8217;1&#8242;</p>
<p>exec test_slow 1</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>go</p>
<p>&#8211;high reads that are not expected for parameter &#8217;2&#8242;</p>
<p>exec test_slow 2</p>
<p>go</p>
<p>drop proc test_with_recompile</p>
<p>go</p>
<p>create proc test_with_recompile @i int</p>
<p>as</p>
<p>begin</p>
<p>declare @j int</p>
<p>create table #temp1 (c1 int primary key)</p>
<p>insert into #temp1 (c1) select @i</p>
<p>select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)</p>
<p>option (recompile)</p>
<p>end</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>set statistics time on</p>
<p>set statistics io on</p>
<p>go</p>
<p>&#8211;high reads as expected for parameter &#8217;1&#8242;</p>
<p>exec test_with_recompile 1</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>go</p>
<p>&#8211;high reads that are not expected for parameter &#8217;2&#8242;</p>
<p>&#8211;low reads on 3rd execution as expected for parameter &#8217;2&#8242;</p>
<p>exec test_with_recompile 2</p>
<p>go</p>
<p>drop proc test_with_alter_table_recompile</p>
<p>go</p>
<p>create proc test_with_alter_table_recompile @i int</p>
<p>as</p>
<p>begin</p>
<p>declare @j int</p>
<p>create table #temp1 (c1 int primary key)</p>
<p>&#8211;to avoid caching of temporary tables one can create a constraint</p>
<p>&#8211;but this might lead to duplicate constraint name error on concurrent usage</p>
<p>alter table #temp1 add constraint test123 unique(c1)</p>
<p>insert into #temp1 (c1) select @i</p>
<p>select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)</p>
<p>option (recompile)</p>
<p>end</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>set statistics time on</p>
<p>set statistics io on</p>
<p>go</p>
<p>&#8211;high reads as expected for parameter &#8217;1&#8242;</p>
<p>exec test_with_alter_table_recompile 1</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>go</p>
<p>&#8211;low reads as expected for parameter &#8217;2&#8242;</p>
<p>exec test_with_alter_table_recompile 2</p>
<p>go</p>
<p>drop proc test_with_index_recompile</p>
<p>go</p>
<p>create proc test_with_index_recompile @i int</p>
<p>as</p>
<p>begin</p>
<p>declare @j int</p>
<p>create table #temp1 (c1 int primary key)</p>
<p>&#8211;to avoid caching of temporary tables one can create an index</p>
<p>create index test on #temp1(c1)</p>
<p>insert into #temp1 (c1) select @i</p>
<p>select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)</p>
<p>option (recompile)</p>
<p>end</p>
<p>go</p>
<p>set statistics time on</p>
<p>set statistics io on</p>
<p>dbcc dropcleanbuffers</p>
<p>go</p>
<p>&#8211;high reads as expected for parameter &#8217;1&#8242;</p>
<p>exec test_with_index_recompile 1</p>
<p>go</p>
<p>dbcc dropcleanbuffers</p>
<p>go</p>
<p>&#8211;low reads as expected for parameter &#8217;2&#8242;</p>
<p>exec test_with_index_recompile 2</p>
<p>go</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/stale-statistics-on-a-newly-created-temporary-table-in-a-stored-procedure-can-lead-to-poor-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Plan Caching and Query Memory Part 2: When not to use stored procedure or other plan caching mechanisms like sp_executesql or prepared statement</title>
		<link>http://blog.sqlworkshops.com/plan-caching-and-query-memory-part-2-when-not-to-use-stored-procedure-or-other-plan-caching-mechanisms-like-sp_executesql-or-prepared-statement/</link>
		<comments>http://blog.sqlworkshops.com/plan-caching-and-query-memory-part-2-when-not-to-use-stored-procedure-or-other-plan-caching-mechanisms-like-sp_executesql-or-prepared-statement/#comments</comments>
		<pubDate>Wed, 18 Jul 2012 15:45:18 +0000</pubDate>
		<dc:creator>R Meyyappan</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blog.sqlworkshops.com/?p=94</guid>
		<description><![CDATA[SQL Server estimates Memory requirement at compile time, when stored procedure or other plan caching mechanisms like sp_executesql or prepared statement are used, the memory requirement is estimated based on first set of execution parameters. This is a common reason &#8230; <a href="http://blog.sqlworkshops.com/plan-caching-and-query-memory-part-2-when-not-to-use-stored-procedure-or-other-plan-caching-mechanisms-like-sp_executesql-or-prepared-statement/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><span class="style18">SQL Server estimates Memory requirement at compile time, when stored procedure or other plan caching mechanisms like sp_executesql or prepared statement are used, the memory requirement is estimated based on first set of execution parameters. This is a common reason for spill over tempdb and hence poor performance. Common memory allocating queries are that perform Sort and do Hash Match operations like Hash Join or Hash Aggregation or Hash Union. This article covers Hash Match operations with examples. It is recommended to read <strong><a href="http://www.sqlworkshops.com/plancachingandquerymemory.htm">Plan Caching and Query Memory Part I</a></strong> before this article which covers an introduction and Query memory for Sort. In most cases it is cheaper to pay for the compilation cost of dynamic queries than huge cost for spill over tempdb, unless memory requirement for a query does not change significantly based on predicates.</span></p>
<p><span class="style18">This article covers underestimation / overestimation of memory for Hash Match operation. <strong><a href="http://www.sqlworkshops.com/plancachingandquerymemory.htm">Plan Caching and Query Memory Part I</a></strong> covers underestimation / overestimation for Sort. It is important to note that underestimation of memory for Sort and Hash Match operations lead to spill over tempdb and hence negatively impact performance. Overestimation of memory affects the memory needs of other concurrently executing queries. <strong>In addition, it is important to note, with Hash Match operations, overestimation of memory can actually lead to poor performance.</strong></span></p>
<p><span class="style18">To read additional articles I wrote click <strong><strong><a href="http://www.sqlworkshops.com/articles.htm">here</a></strong></strong>. To watch the webcasts click <strong><strong><a href="http://www.sqlworkshops.com/webcasts">here</a></strong></strong>.</span></p>
<p><span class="style18"><strong>The best way to learn is to practice. To create the below tables and reproduce the behavior, join the mailing list by using this link: <span style="color: #03664b;"><span style="text-decoration: underline;"><span style="text-decoration: underline;"><span class="style18"><a href="http://www.sqlworkshops.com/ml">www.sqlworkshops.com/ml</a></span></span></span></span> and I will send you the table creation script. Most of these concepts are also covered in our webcasts: <span style="text-decoration: underline;"><a href="http://www.sqlworkshops.com/webcasts">www.sqlworkshops.com/webcasts</a></span></strong></span></p>
<p>Let’s create a Customer’s State table that has 99% of customers in NY and the rest 1% in WA.Customers table used in Part I of this article is also used here.To observe Hash Warning, enable &#8216;Hash Warning&#8217; in SQL Profiler under Events &#8216;Errors and Warnings&#8217;.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">drop</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">table</span> CustomersState</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">create</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">table</span> CustomersState<span style="color: gray;">(</span>CustomerID <span style="color: blue;">int</span> <span style="color: blue;">primary</span> <span style="color: blue;">key</span><span style="color: gray;">,</span> <span style="color: blue;">Address</span> <span style="color: blue;">char</span><span style="color: gray;">(</span>200<span style="color: gray;">),</span> <span style="color: blue;">State</span> <span style="color: blue;">char</span><span style="color: gray;">(</span>2<span style="color: gray;">))</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">insert</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">into</span> CustomersState<span style="color: gray;">(</span>CustomerID<span style="color: gray;">,</span> <span style="color: blue;">Address</span><span style="color: gray;">)</span> <span style="color: blue;">select</span> CustomerID<span style="color: gray;">,</span> <span style="color: red;">&#8216;Address&#8217;</span> <span style="color: blue;">from</span> Customers</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">update</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersState <span style="color: blue;">set</span> <span style="color: blue;">State</span> <span style="color: gray;">=</span> <span style="color: red;">&#8216;NY&#8217;</span> <span style="color: blue;">where</span> CustomerID <span style="color: gray;">%</span> 100 <span style="color: gray;">!=</span> 1</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">update</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersState <span style="color: blue;">set</span> <span style="color: blue;">State</span> <span style="color: gray;">=</span> <span style="color: red;">&#8216;WA&#8217;</span> <span style="color: blue;">where</span> CustomerID <span style="color: gray;">%</span> 100 <span style="color: gray;">=</span> 1</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">update</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">statistics</span> CustomersState <span style="color: blue;">with</span> <span style="color: blue;">fullscan</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>Let’s create a stored procedure that joins customers with CustomersState table with a predicate on State.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">create</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">proc</span> CustomersByState @State <span style="color: blue;">char</span><span style="color: gray;">(</span>2<span style="color: gray;">)</span> <span style="color: blue;">as</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">begin</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">declare</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> @CustomerID <span style="color: blue;">int</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> @CustomerID <span style="color: gray;">=</span> e<span style="color: gray;">.</span>CustomerID <span style="color: blue;">from</span> Customers e</span></p>
<p class="style18"><span style="color: gray; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">inner</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: gray;">join</span> CustomersState es <span style="color: blue;">on </span><span style="color: gray;">(</span>e<span style="color: gray;">.</span>CustomerID <span style="color: gray;">=</span> es<span style="color: gray;">.</span>CustomerID<span style="color: gray;">)</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">where</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> es<span style="color: gray;">.</span><span style="color: blue;">State</span> <span style="color: gray;">=</span> @State</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">option </span><span style="color: gray; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">(</span><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">maxdop</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> 1<span style="color: gray;">)</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">end</span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>Let’s execute the stored procedure first with parameter value ‘WA’ – which will select 1% of data.</p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">set</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">statistics</span> <span style="color: blue;">time</span> <span style="color: blue;">on</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;WA&#8217;</span></span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>The stored procedure took 294 ms to complete.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h1.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure was granted 6704 KB based on 8000 rows being estimated.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h2.jpg" alt="" width="740" height="500" /></p>
<p>The estimated number of rows, 8000 is similar to actual number of rows 8000 and hence the memory estimation should be ok.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h3.jpg" alt="" width="740" height="500" /></p>
<p>There was no Hash Warning in SQL Profiler.To observe Hash Warning, enable &#8216;Hash Warning&#8217; in SQL Profiler under Events &#8216;Errors and Warnings&#8217;.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/hp1.jpg" alt="" width="740" height="500" /></p>
<p>Now let’s execute the stored procedure with parameter value ‘NY’ – which will select 99% of data.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">-Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;NY&#8217;</span></span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>The stored procedure took 2922 ms to complete.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h4.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure was granted 6704 KB based on 8000 rows being estimated.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h5.jpg" alt="" width="740" height="500" /></p>
<p>The estimated number of rows, 8000 is way different from the actual number of rows 792000 because the estimation is based on the first set of parameter value supplied to the stored procedure which is ‘WA’ in our case. This underestimation will lead to spill over tempdb, resulting in poor performance.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h6.jpg" alt="" width="740" height="500" /></p>
<p>There was Hash Warning (Recursion) in SQL Profiler.To observe Hash Warning, enable &#8216;Hash Warning&#8217; in SQL Profiler under Events &#8216;Errors and Warnings&#8217;.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/hp2.jpg" alt="" width="740" height="500" /></p>
<p>Let’s recompile the stored procedure and then let’s first execute the stored procedure with parameter value ‘NY’.<br />
In a production instance it is not advisable to use sp_recompile instead one should use DBCC FREEPROCCACHE (plan_handle). This is due to locking issues involved with sp_recompile, refer to our webcasts, <span class="style18"><span style="text-decoration: underline;"><strong><a href="http://www.sqlworkshops.com/webcasts">www.sqlworkshops.com/webcasts</a></strong></span></span> for further details.</p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: maroon;">sp_recompile</span>CustomersByState</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;NY&#8217;</span></span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>Now the stored procedure took only 1046 ms instead of 2922 ms.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h7.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure was granted 146752 KB of memory.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h8.jpg" alt="" width="740" height="500" /></p>
<p>The estimated number of rows, 792000 is similar to actual number of rows of 792000. Better performance of this stored procedure execution is due to better estimation of memory and avoiding spill over tempdb.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h9.jpg" alt="" width="740" height="500" /></p>
<p>There was no Hash Warning in SQL Profiler.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/hp1.jpg" alt="" width="740" height="500" /></p>
<p>Now let’s execute the stored procedure with parameter value ‘WA’.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;WA&#8217;</span></span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>The stored procedure took 351 ms to complete, higher than the previous execution time of 294 ms.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h10.jpg" alt="" width="740" height="500" /></p>
<p>This stored procedure was granted more memory (146752 KB) than necessary (6704 KB) based on parameter value ‘NY’ for estimation (792000 rows) instead of parameter value ‘WA’ for estimation (8000 rows). This is because the estimation is based on the first set of parameter value supplied to the stored procedure which is ‘NY’ in this case. This overestimation leads to poor performance of this Hash Match operation, it might also affect the performance of other concurrently executing queries requiring memory and hence overestimation is not recommended.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h11.jpg" alt="" width="740" height="500" /></p>
<p>The estimated number of rows, 792000 is much more than the actual number of rows of 8000.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h12.jpg" alt="" width="740" height="500" /></p>
<p><strong>Intermediate Summary:</strong> This issue can be avoided by not caching the plan for memory allocating queries. Other possibility is to use recompile hint or optimize for hint to allocate memory for predefined data range.Let’s recreate the stored procedure with recompile hint.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">drop</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">proc</span> CustomersByState</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">create</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">proc</span> CustomersByState @State <span style="color: blue;">char</span><span style="color: gray;">(</span>2<span style="color: gray;">)</span> <span style="color: blue;">as</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">begin</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">declare</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> @CustomerID <span style="color: blue;">int</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> @CustomerID <span style="color: gray;">=</span> e<span style="color: gray;">.</span>CustomerID <span style="color: blue;">from</span> Customers e</span></p>
<p class="style18"><span style="color: gray; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">inner</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: gray;">join</span> CustomersState es <span style="color: blue;">on </span><span style="color: gray;">(</span>e<span style="color: gray;">.</span>CustomerID <span style="color: gray;">=</span> es<span style="color: gray;">.</span>CustomerID<span style="color: gray;">)</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">where</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> es<span style="color: gray;">.</span><span style="color: blue;">State</span> <span style="color: gray;">=</span> @State</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">option </span><span style="color: gray; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">(</span><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">maxdop</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> 1<span style="color: gray;">,</span> <span style="color: blue;">recompile</span><span style="color: gray;">)</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">end</span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>Let’s execute the stored procedure initially with parameter value ‘WA’ and then with parameter value ‘NY’.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;WA&#8217;</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;NY&#8217;</span></span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>The stored procedure took 297 ms and 1102 ms in line with previous optimal execution times.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h13.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure with parameter value ‘WA’ has good estimation like before.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h14.jpg" alt="" width="740" height="500" /></p>
<p>Estimated number of rows of 8000 is similar to actual number of rows of 8000.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h15.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure with parameter value ‘NY’ also has good estimation and memory grant like before because the stored procedure was recompiled with current set of parameter values.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h16.jpg" alt="" width="740" height="500" /></p>
<p>Estimated number of rows of 792000 is similar to actual number of rows of 792000.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h17.jpg" alt="" width="740" height="500" /></p>
<p>The compilation time and compilation CPU of 1 ms is not expensive in this case compared to the performance benefit.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h18.jpg" alt="" width="740" height="500" /></p>
<p>There was no Hash Warning in SQL Profiler.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/hp1.jpg" alt="" width="740" height="500" /></p>
<p>Let’s recreate the stored procedure with optimize for hint of ‘NY’.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">drop</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">proc</span> CustomersByState</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">create</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">proc</span> CustomersByState @State <span style="color: blue;">char</span><span style="color: gray;">(</span>2<span style="color: gray;">)</span> <span style="color: blue;">as</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">begin</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">declare</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> @CustomerID <span style="color: blue;">int</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> @CustomerID <span style="color: gray;">=</span> e<span style="color: gray;">.</span>CustomerID <span style="color: blue;">from</span> Customers e</span></p>
<p class="style18"><span style="color: gray; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">inner</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> <span style="color: gray;">join</span> CustomersState es <span style="color: blue;">on </span><span style="color: gray;">(</span>e<span style="color: gray;">.</span>CustomerID <span style="color: gray;">=</span> es<span style="color: gray;">.</span>CustomerID<span style="color: gray;">)</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">where</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> es<span style="color: gray;">.</span><span style="color: blue;">State</span> <span style="color: gray;">=</span> @State</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">option </span><span style="color: gray; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">(</span><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">maxdop</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> 1<span style="color: gray;">,</span> optimize <span style="color: blue;">for </span><span style="color: gray;">(</span>@State <span style="color: gray;">=</span> <span style="color: red;">&#8216;NY&#8217;</span><span style="color: gray;">))</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">end</span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>Let’s execute the stored procedure initially with parameter value ‘WA’ and then with parameter value ‘NY’.</p>
<p class="style18"><span style="color: green; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">&#8211;Example provided by www.sqlworkshops.com</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;WA&#8217;</span></span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p class="style18"><span style="color: blue; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">exec</span><span style="font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;"> CustomersByState<span style="color: red;">&#8216;NY&#8217;</span></span></p>
<p class="style18"><span style="color: blue; line-height: 115%; font-family: 'Courier New'; font-size: 10pt; mso-no-proof: yes;">go</span></p>
<p>The stored procedure took 353 ms with parameter value ‘WA’, this is much slower than the optimal execution time of 294 ms we observed previously. This is because of overestimation of memory. The stored procedure with parameter value ‘NY’ has optimal execution time like before.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h19.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure with parameter value ‘WA’ has overestimation of rows because of optimize for hint value of ‘NY’.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h21.jpg" alt="" width="740" height="500" /></p>
<p>Unlike before, more memory was estimated to this stored procedure based on optimize for hint value ‘NY’.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h20.jpg" alt="" width="740" height="500" /></p>
<p>The stored procedure with parameter value ‘NY’ has good estimation because of optimize for hint value of ‘NY’. Estimated number of rows of 792000 is similar to actual number of rows of 792000.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h23.jpg" alt="" width="740" height="500" /></p>
<p>Optimal amount of memory was estimated to this stored procedure based on optimize for hint value ‘NY’.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/h22.jpg" alt="" width="740" height="500" /></p>
<p>There was no Hash Warning in SQL Profiler.</p>
<p class="style18"><img src="http://images.sqlworkshops.com/hp1.jpg" alt="" width="740" height="500" /></p>
<p><span class="style18">This article covers underestimation / overestimation of memory for Hash Match operation. <strong><a href="http://www.sqlworkshops.com/plancachingandquerymemory.htm">Plan Caching and Query Memory Part I</a></strong> covers underestimation / overestimation for Sort. It is important to note that underestimation of memory for Sort and Hash Match operations lead to spill over tempdb and hence negatively impact performance. Overestimation of memory affects the memory needs of other concurrently executing queries. <strong>In addition, it is important to note, with Hash Match operations, overestimation of memory can actually lead to poor performance.</strong></span></p>
<p><strong>Summary:</strong> Cached plan might lead to underestimation or overestimation of memory because the memory is estimated based on first set of execution parameters. It is recommended not to cache the plan if the amount of memory required to execute the stored procedure has a wide range of possibilities. <strong style="mso-bidi-font-weight: normal;">One can mitigate this by using recompile hint, but that will lead to compilation overhead. However, in most cases it might be ok to pay for compilation rather than spilling sort over tempdb which could be very expensive compared to compilation cost.</strong> The other possibility is to use optimize for hint, but in case one sorts more data than hinted by optimize for hint, this will still lead to spill. On the other side there is also the possibility of overestimation leading to unnecessary memory issues for other concurrently executing queries. In case of Hash Match operations, this overestimation of memory might lead to poor performance. When the values used in optimize for hint are archived from the database, the estimation will be wrong leading to worst performance, so one has to exercise caution before using optimize for hint, recompile hint is better in this case.</p>
<p><strong>I explain these concepts with detailed examples in my webcasts (<a href="http://www.sqlworkshops.com/webcasts">www.sqlworkshops.com/webcasts</a>), I recommend you to watch them. The best way to learn is to practice. To create the above tables and reproduce the behavior, join the mailing list at <a href="http://www.sqlworkshops.com/ml">www.sqlworkshops.com/ml</a> and I will send you the relevant SQL Scripts.</strong></p>
<p>Disclaimer and copyright information: This article refers to organizations and products that may be the trademarks or registered trademarks of their various owners. Copyright of this article belongs to Ramesh Meyyappan / <a href="http://www.sqlworkshops.com">www.sqlworkshops.com</a>. You may freely use the ideas and concepts discussed in this article with acknowledgement (<a href="http://www.sqlworkshops.com">www.sqlworkshops.com</a>), but you may not claim any of it as your own work. This article is for informational purposes only; you use any of the suggestions given here entirely at your own risk. Previously published under / <a href="http://sqlblogcasts.com/blogs/sqlworkshops/archive/2011/02/16/plan-caching-and-query-memory-part-ii-hash-match-when-not-to-use-stored-procedure-or-other-plan-caching-mechanisms-like-sp-executesql-or-prepared-statement.aspx">http://sqlblogcasts.com/blogs/sqlworkshops/archive/2011/02/16/plan-caching-and-query-memory-part-ii-hash-match-when-not-to-use-stored-procedure-or-other-plan-caching-mechanisms-like-sp-executesql-or-prepared-statement.aspx</a> / <a href="http://www.sqlworkshops.com/plancachingandquerymemory2.htm">http://www.sqlworkshops.com/plancachingandquerymemory2.htm</a> and in Level 400 Webcasts <a href="http://www.sqlworkshops.com/webcasts">http://www.sqlworkshops.com/webcasts</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.sqlworkshops.com/plan-caching-and-query-memory-part-2-when-not-to-use-stored-procedure-or-other-plan-caching-mechanisms-like-sp_executesql-or-prepared-statement/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
