<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Klaus Aschenbrenner</title>
    <link>http://www.sqlpassion.at/blog/</link>
    <description>A life between bits &amp; bytes</description>
    <language>en-us</language>
    <copyright>Klaus Aschenbrenner</copyright>
    <lastBuildDate>Thu, 01 Dec 2011 19:43:51 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6315.0</generator>
    <managingEditor>Klaus.Aschenbrenner@csharp.at</managingEditor>
    <webMaster>Klaus.Aschenbrenner@csharp.at</webMaster>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=0cf203a4-963f-4db0-b26f-4e4d3fb41610</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,0cf203a4-963f-4db0-b26f-4e4d3fb41610.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,0cf203a4-963f-4db0-b26f-4e4d3fb41610.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=0cf203a4-963f-4db0-b26f-4e4d3fb41610</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A few days ago, one of my customers asked if there is a possibility to get a notification
from SQL Server when a query has to wait for a longer time, because an incompatible
lock exists on the same object. The answer to this question was easy, because SQL
Server provides you for this functionality the so-called <strong>Blocked Process Report</strong>.
Unfortunately this functionality is not enabled by default. Therefore I want to give
you a short overview about the Blocked Process Report in this weblog posting, and
you can use it to further troubleshoot locking scenarios inside your SQL Server installation. 
</p>
        <p>
The Blocked Process Report itself is a simple event that you can trace through SQL
Server Profiler or SQL Trace. The event is called <strong>Blocked Process Report</strong> and
you can find it within the event group <strong>Errors and Warnings</strong>: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/120111_1943_TheBlockedP1.png" alt="" />
        </p>
        <p>
But that event is only raised, when you enable the Blocked Process Report functionality
on the SQL Server instance level through the <strong>sp_configure</strong> option <strong>blocked
process threshold</strong>. That option just accepts a number between 0 and 86400
and is the number of seconds that a query must wait for a lock until SQL Server raises
the <strong>Blocked Process Report</strong> event. By default that configuration option
has a value of 0 which means that this event is never raised. The following code sets
the threshold value to 10 seconds: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:maroon">sp_configure</span>
            <span style="color:red">'blocked
process threshold'<span style="color:gray">,</span> 10</span>
          </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">RECONFIGURE </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
To demonstrate the <strong>Blocked Process Report</strong>, I'm just creating a new
transaction inside the AdventureWorks2008R2 database through an <strong>UPDATE</strong> statement: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">BEGIN</span>
            <span style="color:blue">TRANSACTION </span>
          </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">UPDATE</span> Person<span style="color:gray">.</span>Person </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SET</span> Title <span style="color:gray">=</span><span style="color:red">'Mr' </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> BusinessEntityID <span style="color:gray">=</span> 1</span>
        </p>
        <p>
After the execution of this statement, the query has now acquired an Exclusive Lock
(X) on the record where the column <strong>BusinessEntityID</strong> is equal to 1.
In a second session I'm now trying to read the same record. During the reading SQL
Server tries to acquire a Shared Lock (S) which leads to a blocking scenario: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span>
            <span style="color:gray">*</span>
            <span style="color:blue">FROM</span> Person<span style="color:gray">.</span>Person </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> BusinessEntityID <span style="color:gray">=</span> 1 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
When you have started SQL Server Profiler and when you have configured the <strong>Blocked
Process Report</strong> event, you will see that the event is reported about after
10 seconds: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/120111_1943_TheBlockedP2.png" alt="" />
        </p>
        <p>
As you can see from the screenshot, the Blocked Process Report itself is just XML
data, so it is very easy to further analyze it, when you are familiar with XML and
XQuery.There are 2 important nodes of XML Data - <strong>&lt;blocked-process&gt;</strong> and <strong>&lt;blocking-process&gt;</strong>.
The first one - <strong>&lt;blocked-process&gt;</strong> describes the session that
was blocked. In our case this was the second session that issued the SELECT statement
against the <strong>AdventureWorks2008R2</strong> database. The most important thing
here is the XML attribute <strong>waitresource</strong>, which contains the locked
resource on which the session was waiting and exceeding the <strong>Blocked Process
Threshold</strong> configuration option. 
</p>
        <p>
The second node <strong>&lt;blocking-process&gt;</strong> describes the session that
currently holds the incompatible lock on the resource, on which the other session
wants to acquire the lock. The most important part here is the XML element <strong>&lt;inputbuf&gt;</strong> which
shows the SQL statement that acquired the incompatible lock. With that information
in your hand it is very easy to further troubleshoot why the Blocking Threshold was
exceeded and how you can continue on that (like killing the other session, when it
is an orphaned transaction). 
</p>
        <p>
The most important thing that you have to remember when you are working with the <strong>Blocked
Process Report</strong> is the fact that SQL Server just generates that XML report,
SQL Server WILL NOT resolve the locking/blocking scenario for you! In our case this
means that the second session with the SELECT statement will be also running and waiting
after SQL Server has raised the <strong>Blocked Process Report</strong> – SQL Server
will never kill here a session – SQL Server just reports that one session has exceeded
the <strong>Blocked Process Threshold</strong> – nothing more. 
</p>
        <p>
Thanks for reading 
</p>
        <p>
-Klaus
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=0cf203a4-963f-4db0-b26f-4e4d3fb41610" />
      </body>
      <title>The Blocked Process Report</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,0cf203a4-963f-4db0-b26f-4e4d3fb41610.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,0cf203a4-963f-4db0-b26f-4e4d3fb41610.aspx</link>
      <pubDate>Thu, 01 Dec 2011 19:43:51 GMT</pubDate>
      <description>&lt;p&gt;
A few days ago, one of my customers asked if there is a possibility to get a notification
from SQL Server when a query has to wait for a longer time, because an incompatible
lock exists on the same object. The answer to this question was easy, because SQL
Server provides you for this functionality the so-called &lt;strong&gt;Blocked Process Report&lt;/strong&gt;.
Unfortunately this functionality is not enabled by default. Therefore I want to give
you a short overview about the Blocked Process Report in this weblog posting, and
you can use it to further troubleshoot locking scenarios inside your SQL Server installation. 
&lt;/p&gt;
&lt;p&gt;
The Blocked Process Report itself is a simple event that you can trace through SQL
Server Profiler or SQL Trace. The event is called &lt;strong&gt;Blocked Process Report&lt;/strong&gt; and
you can find it within the event group &lt;strong&gt;Errors and Warnings&lt;/strong&gt;: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/120111_1943_TheBlockedP1.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
But that event is only raised, when you enable the Blocked Process Report functionality
on the SQL Server instance level through the &lt;strong&gt;sp_configure&lt;/strong&gt; option &lt;strong&gt;blocked
process threshold&lt;/strong&gt;. That option just accepts a number between 0 and 86400
and is the number of seconds that a query must wait for a lock until SQL Server raises
the &lt;strong&gt;Blocked Process Report&lt;/strong&gt; event. By default that configuration option
has a value of 0 which means that this event is never raised. The following code sets
the threshold value to 10 seconds: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:maroon"&gt;sp_configure&lt;/span&gt; &lt;span style="color:red"&gt;'blocked
process threshold'&lt;span style="color:gray"&gt;,&lt;/span&gt; 10&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;RECONFIGURE &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
To demonstrate the &lt;strong&gt;Blocked Process Report&lt;/strong&gt;, I'm just creating a new
transaction inside the AdventureWorks2008R2 database through an &lt;strong&gt;UPDATE&lt;/strong&gt; statement: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;BEGIN&lt;/span&gt; &lt;span style="color:blue"&gt;TRANSACTION &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;UPDATE&lt;/span&gt; Person&lt;span style="color:gray"&gt;.&lt;/span&gt;Person &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SET&lt;/span&gt; Title &lt;span style="color:gray"&gt;=&lt;/span&gt; &lt;span style="color:red"&gt;'Mr' &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; BusinessEntityID &lt;span style="color:gray"&gt;=&lt;/span&gt; 1&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
After the execution of this statement, the query has now acquired an Exclusive Lock
(X) on the record where the column &lt;strong&gt;BusinessEntityID&lt;/strong&gt; is equal to 1.
In a second session I'm now trying to read the same record. During the reading SQL
Server tries to acquire a Shared Lock (S) which leads to a blocking scenario: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; &lt;span style="color:gray"&gt;*&lt;/span&gt; &lt;span style="color:blue"&gt;FROM&lt;/span&gt; Person&lt;span style="color:gray"&gt;.&lt;/span&gt;Person &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; BusinessEntityID &lt;span style="color:gray"&gt;=&lt;/span&gt; 1 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
When you have started SQL Server Profiler and when you have configured the &lt;strong&gt;Blocked
Process Report&lt;/strong&gt; event, you will see that the event is reported about after
10 seconds: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/120111_1943_TheBlockedP2.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
As you can see from the screenshot, the Blocked Process Report itself is just XML
data, so it is very easy to further analyze it, when you are familiar with XML and
XQuery.There are 2 important nodes of XML Data - &lt;strong&gt;&amp;lt;blocked-process&amp;gt;&lt;/strong&gt; and &lt;strong&gt;&amp;lt;blocking-process&amp;gt;&lt;/strong&gt;.
The first one - &lt;strong&gt;&amp;lt;blocked-process&amp;gt;&lt;/strong&gt; describes the session that
was blocked. In our case this was the second session that issued the SELECT statement
against the &lt;strong&gt;AdventureWorks2008R2&lt;/strong&gt; database. The most important thing
here is the XML attribute &lt;strong&gt;waitresource&lt;/strong&gt;, which contains the locked
resource on which the session was waiting and exceeding the &lt;strong&gt;Blocked Process
Threshold&lt;/strong&gt; configuration option. 
&lt;/p&gt;
&lt;p&gt;
The second node &lt;strong&gt;&amp;lt;blocking-process&amp;gt;&lt;/strong&gt; describes the session that
currently holds the incompatible lock on the resource, on which the other session
wants to acquire the lock. The most important part here is the XML element &lt;strong&gt;&amp;lt;inputbuf&amp;gt;&lt;/strong&gt; which
shows the SQL statement that acquired the incompatible lock. With that information
in your hand it is very easy to further troubleshoot why the Blocking Threshold was
exceeded and how you can continue on that (like killing the other session, when it
is an orphaned transaction). 
&lt;/p&gt;
&lt;p&gt;
The most important thing that you have to remember when you are working with the &lt;strong&gt;Blocked
Process Report&lt;/strong&gt; is the fact that SQL Server just generates that XML report,
SQL Server WILL NOT resolve the locking/blocking scenario for you! In our case this
means that the second session with the SELECT statement will be also running and waiting
after SQL Server has raised the &lt;strong&gt;Blocked Process Report&lt;/strong&gt; – SQL Server
will never kill here a session – SQL Server just reports that one session has exceeded
the &lt;strong&gt;Blocked Process Threshold&lt;/strong&gt; – nothing more. 
&lt;/p&gt;
&lt;p&gt;
Thanks for reading 
&lt;/p&gt;
&lt;p&gt;
-Klaus
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=0cf203a4-963f-4db0-b26f-4e4d3fb41610" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,0cf203a4-963f-4db0-b26f-4e4d3fb41610.aspx</comments>
      <category>.NET German</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=e694b727-09fa-454e-aad0-a112dfb1bbd7</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,e694b727-09fa-454e-aad0-a112dfb1bbd7.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,e694b727-09fa-454e-aad0-a112dfb1bbd7.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=e694b727-09fa-454e-aad0-a112dfb1bbd7</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have a lot of customers with some impressive SQL Server workloads, those databases
are several hundred GB large, with several hundred simultaneous users – just great
environments for performance tuning and troubleshooting. Some weeks ago I thought
about how I can simulate such workloads in my own environment, so that I can make
my performance troubleshooting sessions and workshops more realistic and impressive.
I'm not the big fan of using the (small) AdventureWorks database with some prepared
queries for real performance troubleshooting. Unfortunately no one of my customers
wants to share their workload and their specific problems with me and the whole other
world in public ;-) 
</p>
        <p>
Because of that I was looking in the last days for some free tools, with which I can
simulate large OLTP workloads with hundreds of different users, and where I'm also
able to scale out the workload to thousands of users – if I want and I have the requirement
to do it. During the weekend I finally found one very interesting tool that is free
and simulates a whole TPC-C workload: it's called <strong>Hammerora</strong> and it
is a free Open Source Oracle Load Test Tool that simulates an OLTP based TPC-C workload.
Yes, you read correct: the tool is written for Oracle, but fortunately they also support
SQL Server! You can find the tool at <a href="http://hammerora.sourceforge.net">http://hammerora.sourceforge.net</a>.
In this weblog posting I want to give you a quick overview about the usage of the
tool, and how easy it is to run a whole TPC-C workload on your own SQL Server within
a few minutes. 
</p>
        <p>
After the installation of the tool, you can start it through the provided batch file <strong>hammerora.bat</strong>,
which is stored in the installation directory. 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC1.png" alt="" />
        </p>
        <p>
When you want to simulate a TPC-C based workload, you have to do 2 different things: 
</p>
        <ul>
          <li>
Creating the necessary database with the initial data 
</li>
          <li>
Run the TPC-C against the created database 
</li>
        </ul>
        <p>
Let's have a more detailed look on both of these steps. Before you can create the
actual database, you have to tell the tool with which database system you are working.
Hammerora supports the following database systems: 
</p>
        <ul>
          <li>
Oracle 
</li>
          <li>
MySQL 
</li>
          <li>
Microsoft SQL Server 
</li>
        </ul>
        <p>
You can set your actual database through the menu option <strong>Benchmark/Benchmark
Options</strong>: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC2.png" alt="" />
        </p>
        <p>
When you are working with Oracle or MySQL, Hammerora also supports a TPC-H (Data Warehouse)
based workload. After you have set your database system to SQL Server, you can go
to the menu <strong>Benchmark/TPC-C/TPC-C Schema Options</strong>. 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC3.png" alt="" />
        </p>
        <p>
This dialog allows you to set all the necessary options that are needed by Hammerora
to create the actual TPC-C database schema. In the first part of the dialog you can
specify your SQL Server connection info, and in the following part you can define
the number of warehouses (parameter <strong>Number of Warehouses</strong>) that Hammerora
creates in the database. You can find more detailed information about the database
structure on the official TPC website at <a href="http://tpc.org/tpcc/detail.asp">http://tpc.org/tpcc/detail.asp</a>,
which also describes the concept of a warehouse that is used by the TPC-C benchmark.
With the parameter <strong>Virtual User to Build Schema</strong> you can specify how
many sessions Hammerora should use during the creation of your database. You can think
of a Virtual User as a session in SQL Server. This option allows you to create your
TPC-C database in parallel with simultaneous sessions. When you have specified the
necessary configuration options, you are ready to create your database. You just have
to hit the <strong>Create TPC Schema</strong> symbol in the toolbar (12th symbol from
left.). The creation of one warehouse needs around 130MB in the database. So it's
also very easy to create a database with several hundred GBs of data in it – just
increase the number of warehouses, but trust – it will take some time! <span style="font-family:Wingdings">J</span></p>
        <p>
After the creation of the TPC-C database, you have to configure which kind of test
suite Hammerora has to execute against your database. The test suite itself is implemented
as a so-called <strong>Driver Script</strong>. When you go again to the menu <strong>Benchmark/TPC-C/TPC-C
Schema Options</strong>, you can see that Hammerora supports 2 kinds of driver scripts: 
</p>
        <ul>
          <li>
Standard Driver Script 
</li>
          <li>
Timed Test Driver Script 
</li>
        </ul>
        <p>
The <strong>Standard Driver Script</strong> just executes a continuous workload against
your SQL Server database: when one query is finished the next query is submitted without
any pausing. Your SQL Server will be hammered with a continuous workload, and how
can see how far your SQL Server installation will scale. With the <strong>Timed Test
Driver Script</strong> Hammerora introduces so-called <strong>Keying- and Thinking
Times</strong>, which are also part of the official TPC-C benchmark. With this option,
Hammerora submits about 3 queries per minute to your SQL Server, because Hammerora
tries to simulate real users, which have to key in their data (Keying Time) and need
some time for thinking (Thinking Time). With the Timed Test Driver Script you need
a very high amount of Virtual Users to get a reasonable workload on your SQL Server.
Further information about the various options that the Timed Test Driver Scripts accepts
can be also found in the documentation of Hammerora. 
</p>
        <p>
For my scenarios I have just used the Standard Driver Scripts, because I want to have
a continuous workload against SQL Server, so that I can demonstrate various performance
tuning and troubleshooting techniques. When you have selected the corresponding driver
script, you have to generate the actual script that is used for creating the workload
against SQL Server. You can generate that script by using the menu option <strong>Benchmark/TPC-C/TPC-C
Driver Script</strong>. When you have selected that option, Hammerora shows the driver
script as an output in the main window: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC4.png" alt="" />
        </p>
        <p>
The only thing that you finally have to configure is the amount of Virtual Users that
Hammerora uses to execute the Driver Script against your SQL Server database. You
can set the amount of Virtual Users through the menu option <strong>Virtual Users/Vuser
Options</strong>: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC5.png" alt="" />
        </p>
        <p>
As a last step you need to create those Virtual Users inside Hammerora by using the
symbol <strong>Create Virtual Users</strong> (10th symbol from left) from the toolbar.
You can see the created Virtual Users in the middle part of the main window. Finally
you can use the symbol <strong>Run Hammerora Loadtest</strong> (11th symbol from left)
from the toolbar to start the TPC-C workload against SQL Server. It takes some seconds
until Hammerora has created all the necessary sessions, but then the actual TPC-C
workload is executed against SQL Server: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC6.png" alt="" />
        </p>
        <p>
As you can see from this weblog posting, it is very easy to create an OLTP based workload
that is executed against SQL Server. With this approach it is also very easy to demonstrate
some key performance problems inside SQL Server like incorrect Transaction Log usage,
Locking/Blocking scenarios, Memory Management, misconfigured I/O subsystems etc. 
</p>
        <p>
On the other hand you can also demonstrate some other advanced concepts like Clustering,
Database Mirroring, Log Shipping, Replication etc. with real workloads, and how some
features affects the availability of your database. The possible scenarios are just
endless, and you are just working with a real OLTP workload which can scale very easily
to thousands of concurrent users, if you want and you have the resources… I think
this approach can give our conference sessions and workshops a new feeling when we
demonstrate SQL Server concepts and performance troubleshooting <span style="font-family:Wingdings">J</span></p>
        <p>
Thanks for reading 
</p>
        <p>
-Klaus
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=e694b727-09fa-454e-aad0-a112dfb1bbd7" />
      </body>
      <title>Running a TPC-C workload on SQL Server</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,e694b727-09fa-454e-aad0-a112dfb1bbd7.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,e694b727-09fa-454e-aad0-a112dfb1bbd7.aspx</link>
      <pubDate>Wed, 23 Nov 2011 19:38:50 GMT</pubDate>
      <description>&lt;p&gt;
I have a lot of customers with some impressive SQL Server workloads, those databases
are several hundred GB large, with several hundred simultaneous users – just great
environments for performance tuning and troubleshooting. Some weeks ago I thought
about how I can simulate such workloads in my own environment, so that I can make
my performance troubleshooting sessions and workshops more realistic and impressive.
I'm not the big fan of using the (small) AdventureWorks database with some prepared
queries for real performance troubleshooting. Unfortunately no one of my customers
wants to share their workload and their specific problems with me and the whole other
world in public ;-) 
&lt;/p&gt;
&lt;p&gt;
Because of that I was looking in the last days for some free tools, with which I can
simulate large OLTP workloads with hundreds of different users, and where I'm also
able to scale out the workload to thousands of users – if I want and I have the requirement
to do it. During the weekend I finally found one very interesting tool that is free
and simulates a whole TPC-C workload: it's called &lt;strong&gt;Hammerora&lt;/strong&gt; and it
is a free Open Source Oracle Load Test Tool that simulates an OLTP based TPC-C workload.
Yes, you read correct: the tool is written for Oracle, but fortunately they also support
SQL Server! You can find the tool at &lt;a href="http://hammerora.sourceforge.net"&gt;http://hammerora.sourceforge.net&lt;/a&gt;.
In this weblog posting I want to give you a quick overview about the usage of the
tool, and how easy it is to run a whole TPC-C workload on your own SQL Server within
a few minutes. 
&lt;/p&gt;
&lt;p&gt;
After the installation of the tool, you can start it through the provided batch file &lt;strong&gt;hammerora.bat&lt;/strong&gt;,
which is stored in the installation directory. 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC1.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
When you want to simulate a TPC-C based workload, you have to do 2 different things: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Creating the necessary database with the initial data 
&lt;/li&gt;
&lt;li&gt;
Run the TPC-C against the created database 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Let's have a more detailed look on both of these steps. Before you can create the
actual database, you have to tell the tool with which database system you are working.
Hammerora supports the following database systems: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Oracle 
&lt;/li&gt;
&lt;li&gt;
MySQL 
&lt;/li&gt;
&lt;li&gt;
Microsoft SQL Server 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
You can set your actual database through the menu option &lt;strong&gt;Benchmark/Benchmark
Options&lt;/strong&gt;: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC2.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
When you are working with Oracle or MySQL, Hammerora also supports a TPC-H (Data Warehouse)
based workload. After you have set your database system to SQL Server, you can go
to the menu &lt;strong&gt;Benchmark/TPC-C/TPC-C Schema Options&lt;/strong&gt;. 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC3.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
This dialog allows you to set all the necessary options that are needed by Hammerora
to create the actual TPC-C database schema. In the first part of the dialog you can
specify your SQL Server connection info, and in the following part you can define
the number of warehouses (parameter &lt;strong&gt;Number of Warehouses&lt;/strong&gt;) that Hammerora
creates in the database. You can find more detailed information about the database
structure on the official TPC website at &lt;a href="http://tpc.org/tpcc/detail.asp"&gt;http://tpc.org/tpcc/detail.asp&lt;/a&gt;,
which also describes the concept of a warehouse that is used by the TPC-C benchmark.
With the parameter &lt;strong&gt;Virtual User to Build Schema&lt;/strong&gt; you can specify how
many sessions Hammerora should use during the creation of your database. You can think
of a Virtual User as a session in SQL Server. This option allows you to create your
TPC-C database in parallel with simultaneous sessions. When you have specified the
necessary configuration options, you are ready to create your database. You just have
to hit the &lt;strong&gt;Create TPC Schema&lt;/strong&gt; symbol in the toolbar (12th symbol from
left.). The creation of one warehouse needs around 130MB in the database. So it's
also very easy to create a database with several hundred GBs of data in it – just
increase the number of warehouses, but trust – it will take some time! &lt;span style="font-family:Wingdings"&gt;J&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
After the creation of the TPC-C database, you have to configure which kind of test
suite Hammerora has to execute against your database. The test suite itself is implemented
as a so-called &lt;strong&gt;Driver Script&lt;/strong&gt;. When you go again to the menu &lt;strong&gt;Benchmark/TPC-C/TPC-C
Schema Options&lt;/strong&gt;, you can see that Hammerora supports 2 kinds of driver scripts: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Standard Driver Script 
&lt;/li&gt;
&lt;li&gt;
Timed Test Driver Script 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The &lt;strong&gt;Standard Driver Script&lt;/strong&gt; just executes a continuous workload against
your SQL Server database: when one query is finished the next query is submitted without
any pausing. Your SQL Server will be hammered with a continuous workload, and how
can see how far your SQL Server installation will scale. With the &lt;strong&gt;Timed Test
Driver Script&lt;/strong&gt; Hammerora introduces so-called &lt;strong&gt;Keying- and Thinking
Times&lt;/strong&gt;, which are also part of the official TPC-C benchmark. With this option,
Hammerora submits about 3 queries per minute to your SQL Server, because Hammerora
tries to simulate real users, which have to key in their data (Keying Time) and need
some time for thinking (Thinking Time). With the Timed Test Driver Script you need
a very high amount of Virtual Users to get a reasonable workload on your SQL Server.
Further information about the various options that the Timed Test Driver Scripts accepts
can be also found in the documentation of Hammerora. 
&lt;/p&gt;
&lt;p&gt;
For my scenarios I have just used the Standard Driver Scripts, because I want to have
a continuous workload against SQL Server, so that I can demonstrate various performance
tuning and troubleshooting techniques. When you have selected the corresponding driver
script, you have to generate the actual script that is used for creating the workload
against SQL Server. You can generate that script by using the menu option &lt;strong&gt;Benchmark/TPC-C/TPC-C
Driver Script&lt;/strong&gt;. When you have selected that option, Hammerora shows the driver
script as an output in the main window: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC4.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
The only thing that you finally have to configure is the amount of Virtual Users that
Hammerora uses to execute the Driver Script against your SQL Server database. You
can set the amount of Virtual Users through the menu option &lt;strong&gt;Virtual Users/Vuser
Options&lt;/strong&gt;: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC5.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
As a last step you need to create those Virtual Users inside Hammerora by using the
symbol &lt;strong&gt;Create Virtual Users&lt;/strong&gt; (10th symbol from left) from the toolbar.
You can see the created Virtual Users in the middle part of the main window. Finally
you can use the symbol &lt;strong&gt;Run Hammerora Loadtest&lt;/strong&gt; (11th symbol from left)
from the toolbar to start the TPC-C workload against SQL Server. It takes some seconds
until Hammerora has created all the necessary sessions, but then the actual TPC-C
workload is executed against SQL Server: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/112311_1938_RunningaTPC6.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
As you can see from this weblog posting, it is very easy to create an OLTP based workload
that is executed against SQL Server. With this approach it is also very easy to demonstrate
some key performance problems inside SQL Server like incorrect Transaction Log usage,
Locking/Blocking scenarios, Memory Management, misconfigured I/O subsystems etc. 
&lt;/p&gt;
&lt;p&gt;
On the other hand you can also demonstrate some other advanced concepts like Clustering,
Database Mirroring, Log Shipping, Replication etc. with real workloads, and how some
features affects the availability of your database. The possible scenarios are just
endless, and you are just working with a real OLTP workload which can scale very easily
to thousands of concurrent users, if you want and you have the resources… I think
this approach can give our conference sessions and workshops a new feeling when we
demonstrate SQL Server concepts and performance troubleshooting &lt;span style="font-family:Wingdings"&gt;J&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
Thanks for reading 
&lt;/p&gt;
&lt;p&gt;
-Klaus
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=e694b727-09fa-454e-aad0-a112dfb1bbd7" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,e694b727-09fa-454e-aad0-a112dfb1bbd7.aspx</comments>
      <category>.NET German</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=dc66b0ab-93f3-47f0-a6b7-b2f130e028ac</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,dc66b0ab-93f3-47f0-a6b7-b2f130e028ac.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,dc66b0ab-93f3-47f0-a6b7-b2f130e028ac.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=dc66b0ab-93f3-47f0-a6b7-b2f130e028ac</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <span style="color:black">I'm very proud to announce today that I'm running next year
a new event series across Europe: the </span>
          <strong>SQL Server 2012 Deep Dive Days</strong>
          <span style="color:black">.
You can learn in this 3 day event all about the new things in SQL Server 2012. The
event series is currently planned for the following cities around Europe: </span>
        </p>
        <ul>
          <li>
            <span style="color:black">March 3 – 5, 2012 in Vienna/Austria </span>
          </li>
          <li>
            <span style="color:black">March 12 – 14, 2012 in Munich/Germany </span>
          </li>
          <li>
            <span style="color:black">March 19 – 21, 2012 in Zürich/Switzerland </span>
          </li>
          <li>
            <span style="color:black">April 16 – 18, 2012 in Cologne/Germany </span>
          </li>
        </ul>
        <p>
          <span style="color:black">You can find further detailed information at <a href="http://www.sqlpassion.at/events.html" target="_blank">http://www.sqlpassion.at/events.html</a> where
you can also register for the various locations. If you are not from the German speaking
area of Europe, I'm also planning 2 events in English in May 2012 at the following
locations: </span>
        </p>
        <ul>
          <li>
            <span style="color:black">Brussels/Belgium </span>
          </li>
          <li>
            <span style="color:black">London/United Kingdom </span>
          </li>
        </ul>
        <p>
          <span style="color:black">In this 3 days long event I'm covering the following topics
about SQL Server 2012: </span>
        </p>
        <p>
          <span style="color:black; text-decoration:underline">
            <strong>Day 1: SQL Server 2012
Development</strong>
          </span>
        </p>
        <ul>
          <li>
            <span style="color:black">Project Juneau </span>
          </li>
          <li>
            <span style="color:black">T-SQL Enhancements </span>
          </li>
          <li>
            <span style="color:black">Spatial Data Types </span>
          </li>
          <li>
            <span style="color:black">File Table </span>
          </li>
          <li>
            <span style="color:black">Fulltext Indexes </span>
          </li>
          <li>
            <span style="color:black">Semantic Search </span>
          </li>
          <li>
            <span style="color:black">Service Broker </span>
          </li>
          <li>
            <span style="color:black">SQL Express Edition - LocalDB </span>
          </li>
          <li>
            <span style="color:black">Contained Databases </span>
          </li>
          <li>
            <span style="color:black">Metadata Discovery </span>
          </li>
          <li>
            <span style="color:black">SQL Server Integration Services </span>
          </li>
        </ul>
        <p>
          <span style="color:black; text-decoration:underline">
            <strong>Day 2: SQL Server 2012
Administration</strong>
          </span>
          <span style="font-size:12pt">
          </span>
        </p>
        <ul>
          <li>
            <span style="color:black">Extended Events </span>
          </li>
          <li>
            <span style="color:black">Columnstore Indexes </span>
          </li>
          <li>
            <span style="color:black">LOB Online Index Rebuilds </span>
          </li>
          <li>
            <span style="color:black">Adding Online Non-NULL Values </span>
          </li>
          <li>
            <span style="color:black">Custom Server Roles </span>
          </li>
          <li>
            <span style="color:black">Resource Governor </span>
          </li>
          <li>
            <span style="color:black">Database Recovery Advisor </span>
          </li>
          <li>
            <span style="color:black">Distributed Replay </span>
          </li>
          <li>
            <span style="color:black">Memory Management </span>
          </li>
          <li>
            <span style="color:black">Partitioned Tables </span>
          </li>
          <li>
            <span style="color:black">Troubleshooting Enhancements </span>
          </li>
          <li>
            <span style="color:black">Windows Server Core Support </span>
          </li>
          <li>
            <span style="color:black">Windows Server 8 &amp; SQL Server 2012 </span>
          </li>
        </ul>
        <p>
          <span style="color:black; text-decoration:underline">
            <strong>Day 3: SQL Server 2012
High Availability</strong>
          </span>
        </p>
        <ul>
          <li>
            <div>
              <span style="color:black">Failover Clustering Enhancements </span>
            </div>
            <ul>
              <li>
                <span style="color:black">Local TempDb </span>
              </li>
              <li>
                <span style="color:black">Health Check Policies </span>
              </li>
              <li>
                <span style="color:black">Failover Policy Levels </span>
              </li>
              <li>
                <span style="color:black">Indirect Checkpoints </span>
              </li>
            </ul>
          </li>
          <li>
            <div>
              <span style="color:black">AlwaysOn </span>
            </div>
            <ul>
              <li>
                <span style="color:black">Availability Groups </span>
              </li>
              <li>
                <span style="color:black">Availability Group Listeners </span>
              </li>
              <li>
                <span style="color:black">Monitoring &amp; Troubleshooting </span>
              </li>
            </ul>
          </li>
          <li>
            <div>
              <span style="color:black">Multiple Secondaries </span>
            </div>
            <ul>
              <li>
                <span style="color:black">Automatic Failovers </span>
              </li>
              <li>
                <span style="color:black">Read-Only Connections </span>
              </li>
              <li>
                <span style="color:black">Backups </span>
              </li>
            </ul>
          </li>
        </ul>
        <p>
          <span style="color:black">If you are interested in attending one of these events,
don't hesitate and register at <a href="http://www.sqlpassion.at/events.html" target="_blank">http://www.sqlpassion.at/events.html</a>.
There is also an Early-Bird price available until the end of this year. </span>
        </p>
        <p>
          <span style="color:black">BTW: if you have missed the news, Microsoft released a few
hours ago the RC0 version of SQL Server 2012 – you can download the bits here: <a href="http://www.microsoft.com/download/en/details.aspx?id=28145" target="_blank">http://www.microsoft.com/download/en/details.aspx?id=28145</a></span>
        </p>
        <p>
          <span style="color:black">Thanks for reading! </span>
        </p>
        <p>
          <span style="color:black">-Klaus</span>
        </p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=dc66b0ab-93f3-47f0-a6b7-b2f130e028ac" />
      </body>
      <title>My new event series across Europe: SQL Server 2012 Deep Dive Days</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,dc66b0ab-93f3-47f0-a6b7-b2f130e028ac.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,dc66b0ab-93f3-47f0-a6b7-b2f130e028ac.aspx</link>
      <pubDate>Thu, 17 Nov 2011 17:51:00 GMT</pubDate>
      <description>&lt;p&gt;
&lt;span style="color:black"&gt;I'm very proud to announce today that I'm running next year
a new event series across Europe: the &lt;/span&gt;&lt;strong&gt;SQL Server 2012 Deep Dive Days&lt;/strong&gt;&lt;span style="color:black"&gt;.
You can learn in this 3 day event all about the new things in SQL Server 2012. The
event series is currently planned for the following cities around Europe: &lt;/span&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;March 3 – 5, 2012 in Vienna/Austria &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;March 12 – 14, 2012 in Munich/Germany &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;March 19 – 21, 2012 in Zürich/Switzerland &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;April 16 – 18, 2012 in Cologne/Germany &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;span style="color:black"&gt;You can find further detailed information at &lt;a href="http://www.sqlpassion.at/events.html" target="_blank"&gt;http://www.sqlpassion.at/events.html&lt;/a&gt; where
you can also register for the various locations. If you are not from the German speaking
area of Europe, I'm also planning 2 events in English in May 2012 at the following
locations: &lt;/span&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Brussels/Belgium &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;London/United Kingdom &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;span style="color:black"&gt;In this 3 days long event I'm covering the following topics
about SQL Server 2012: &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black; text-decoration:underline"&gt;&lt;strong&gt;Day 1: SQL Server 2012
Development&lt;/strong&gt; &lt;/span&gt; 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Project Juneau &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;T-SQL Enhancements &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Spatial Data Types &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;File Table &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Fulltext Indexes &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Semantic Search &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Service Broker &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;SQL Express Edition - LocalDB &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Contained Databases &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Metadata Discovery &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;SQL Server Integration Services &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;span style="color:black; text-decoration:underline"&gt;&lt;strong&gt;Day 2: SQL Server 2012
Administration&lt;/strong&gt; &lt;/span&gt;&lt;span style="font-size:12pt"&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Extended Events &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Columnstore Indexes &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;LOB Online Index Rebuilds &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Adding Online Non-NULL Values &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Custom Server Roles &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Resource Governor &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Database Recovery Advisor &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Distributed Replay &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Memory Management &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Partitioned Tables &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Troubleshooting Enhancements &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Windows Server Core Support &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Windows Server 8 &amp;amp; SQL Server 2012 &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;span style="color:black; text-decoration:underline"&gt;&lt;strong&gt;Day 3: SQL Server 2012
High Availability&lt;/strong&gt; &lt;/span&gt; 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="color:black"&gt;Failover Clustering Enhancements &lt;/span&gt; 
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Local TempDb &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Health Check Policies &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Failover Policy Levels &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Indirect Checkpoints &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="color:black"&gt;AlwaysOn &lt;/span&gt; 
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Availability Groups &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Availability Group Listeners &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Monitoring &amp;amp; Troubleshooting &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="color:black"&gt;Multiple Secondaries &lt;/span&gt; 
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Automatic Failovers &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Read-Only Connections &lt;/span&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;span style="color:black"&gt;Backups &lt;/span&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;span style="color:black"&gt;If you are interested in attending one of these events,
don't hesitate and register at &lt;a href="http://www.sqlpassion.at/events.html" target="_blank"&gt;http://www.sqlpassion.at/events.html&lt;/a&gt;.
There is also an Early-Bird price available until the end of this year. &lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black"&gt;BTW: if you have missed the news, Microsoft released a few
hours ago the RC0 version of SQL Server 2012 – you can download the bits here: &lt;a href="http://www.microsoft.com/download/en/details.aspx?id=28145" target="_blank"&gt;http://www.microsoft.com/download/en/details.aspx?id=28145&lt;/a&gt; &lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black"&gt;Thanks for reading! &lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black"&gt;-Klaus&lt;/span&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=dc66b0ab-93f3-47f0-a6b7-b2f130e028ac" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,dc66b0ab-93f3-47f0-a6b7-b2f130e028ac.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Today I want to talk about a phenomenon regarding memory management in SQL Server.
A few weeks ago I had a consulting customer where we made some SQL Server performance
improvements. As a side note the customer asked me, why SQL Server isn't using as
much memory as possible on their production system. Their database was about 500 GB,
and when we looked into the Task Manager of Windows, we saw that SQL Server was just
consuming a few hundred MBs: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/110411_2120_WhySQLServe1.png" alt="" />
        </p>
        <p>
In the first step this behavior of SQL Server was a little bit amazing, but the answer
was found very fast, when we looked into the details of their production configuration.
The problem was that the customer granted the <strong>Locked Pages in Memory</strong> privilege
to the service account under which SQL Server was running. You can check if you have
granted this privilege when you look into the current SQL Server Error Log. If you
have granted that privilege, you can see following informational message during the
startup of SQL Server: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/110411_2120_WhySQLServe2.png" alt="" />
        </p>
        <p>
In the first step of this posting I want to explain why and when you should use that
privilege for SQL Server, and in the second step you will see, how SQL Server uses
that privilege and why Task Manager is lying to you regarding the memory consumption. 
</p>
        <p>
Every time when the Windows OS gets into memory pressure, the Windows OS raises a
so-called <strong>Memory Resource Notification Event</strong> to all processes that
are currently running on the box (see <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366541(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/windows/desktop/aa366541(v=vs.85).aspx</a> for
the corresponding API function). SQL Server subscribes to this event and processes
it internally through a component called the <strong>Resource Monitor</strong>. Additional
information about the Resource Monitor component is reported through the Ring Buffer
type <strong>RING_BUFFER_RESOURCE_MONITOR</strong> that is stored inside the DMV <strong>sys.dm_os_ring_buffers</strong>.
When SQL Server receives the Memory Resource Notification Event, SQL Server must trim
its internal caches, like the Buffer Pool, or the Plan Cache to get out of memory
pressure. But there are some scenarios in which SQL Server reacts to slow to memory
pressure. In that case the Windows OS will do a so-called <strong>Hard Working Set
Trim</strong>, and pages the process (in our case SQL Server) out to the page file.
The Windows OS just want to survive and get out of its memory pressure. Imagine that
– the Buffer Pool, the Plan Cache – In-Memory buffers – are paged out to the page
file! Accessing the Buffer Pool – our in-memory cache - means reading pages from the
physical disk! You can imagine that the performance of SQL Server will decrease massively… 
</p>
        <p>
Another case when a Hard Working Set Trim can occur is, when you have device drivers
that have bugs, or when the Windows OS has bugs that leads to Hard Working Set Trims.
Under Windows Server 2003 there were several bugs reported that caused Hard Working
Set Trims, like: 
</p>
        <ul>
          <li>
Copying large files from the SQL Server box 
</li>
          <li>
Establishing a Remote Desktop Connection to your SQL Server box 
</li>
        </ul>
        <p>
But how you can find out if your performance problems occur because of Hard Working
Set Trims? When you are running a version of SQL Server prior to SQL Server 2005 SP2,
you have to monitor the overall performance of your SQL Server instance, there are
no messages or indications inside SQL Server that can tell you, if a Hard Working
Set Trim degraded the performance of SQL Server. Beginning with SQL Server 2005 SP2
Microsoft has added an error message to the SQL Server Log, as soon as a Hard Working
Set Trim occurred, like: 
</p>
        <p>
          <strong>
            <em>" A significant part of sql server process memory has been paged out.
This may result in a performance degradation. Duration: 0 seconds. Working set (KB):
1086400, committed (KB): 2160928, memory utilization: 50%" </em>
          </strong>
        </p>
        <p>
In such cases you can enable the Locked Pages in Memory privilege to get rid of this
issue. In this case the Windows OS is not allowed to page out pages that SQL Server
allocated for the Buffer Pool. Yes, you read correct: Locked Pages in Memory is only
used for Buffer Pool allocations inside SQL Server! 
</p>
        <p>
But on the other hand you also have to investigate <strong>WHY</strong> a Hard Working
Set Trim occurred on your system. A Hard Working Set Trim is just the result of another
problem that you have on your Windows box. So you should find the root cause, and
eliminate it, instead of using the shortcut (enabling Locked Pages in Memory) infinitely.
I know a lot of DBAs who are using Locked Pages in Memory by default, and there are
several pro and cons for this which I don't want to discuss here again. Glen Berry
has a great article which describes more of those pros and cons (see <a href="http://sqlserverperformance.wordpress.com/2011/02/14/sql-server-and-the-lock-pages-in-memory-right-in-windows-server">http://sqlserverperformance.wordpress.com/2011/02/14/sql-server-and-the-lock-pages-in-memory-right-in-windows-server</a>).
One thing that I want to mention here again is the fact that you should limit the
memory that SQL Server can allocate for the Buffer Pool when you use Locked Pages
in Memory. You can limit the memory through the <strong>Max Memory Setting</strong> of
your SQL Server instance. 
</p>
        <p>
By now you know when and how you can enable Locked Pages in Memory for your SQL Server
instance. But why the heck Task Manager is reporting a wrong Working Set size when
SQL Server is using that privilege. For this explanation we have to dig a little bit
deeper into the Win32API. By default (without Locked Pages in Memory) SQL Server allocates
memory for the Buffer Pool through the <strong>VirtualAlloc</strong> function of the
Win32API (see <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx)">http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx)</a>.
But when the SQL Server service account has the Locked Pages in Memory privilege,
SQL Server internally uses the <strong>AllocateUserPhysicalPages</strong> Win32API
function (see <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366528(v=vs.85).aspx)">http://msdn.microsoft.com/en-us/library/windows/desktop/aa366528(v=vs.85).aspx)</a> to
do Buffer Pool allocations. This function can be only called by a process, when the
process has the <strong>SeLockMemoryPrivilege</strong> – in other words the Locked
Pages in Memory privilege which is the user-friendly name. The Win32API function <strong>AllocateUserPhysicalPages</strong> is
part of the Address Windowing Extensions API (AWE). Therefore those memory allocations
can't be paged out by the Windows OS, because AWE memory regions are not page able
by design. Those memory regions are just locked in memory, therefore the name of this
privilege. When you have Locked Pages in Memory for your SQL Server service account
enabled, it also means that you are using AWE indirectly – funny isn't it? As you
can see from this explanation, Locked Pages in Memory is rather a Windows OS concept
than a SQL Server concept. It has nothing to do directly with SQL Server. SQL Server
is just a consumer of it. 
</p>
        <p>
With this basic knowledge in your hand, it is now very easy to explain why Task Manager
doesn't show the correct Working Set of the SQL Server process: Task Manager is not
reporting those memory allocations that are done through the Win32API function <strong>AllocateUserPhysicalPages</strong> –
that's all about this phenomenon. 
</p>
        <p>
But how can you now find out, how much memory SQL Server is really using? There are
several possibilities. Inside SQL Server you can use the DMV <strong>sys.dm_os_process_memory</strong> and
the column <strong>physical_memory_in_use_kb</strong>. This returns you the physical
memory that SQL Server is currently using including AWE memory allocations. If you
want to have a more detailed breakdown of the memory consumption of SQL Server, you
can use the DMV <strong>sys.dm_os_memory_clerks</strong>. A memory clerk is a component
inside SQL Server, which tracks memory allocations for a specific component inside
SQL Server. SQL Server gives you a memory clerks for each major component for each
available NUMA node in your system. The column <strong>awe_allocated_kb</strong> shows
you the AWE memory allocations in kb that were allocated by SQL Server through the
Win32API function <strong>AllocateUserPhysicalPages</strong>. 
</p>
        <p>
          <strong>Update</strong>:<br />
Aaron Bertrand (see <a href="http://sqlblog.com/blogs/aaron_bertrand">http://sqlblog.com/blogs/aaron_bertrand</a>)
mentioned that it would also make sense to reference a Performance Monitor counter
to track the memory consumption of SQL Server. So here it is: 
</p>
        <p>
Outside of SQL Server you can use the Performance Monitor counter <strong>SQLServer:Memory
Manager/Total Server Memory (KB)</strong> to track how large the Buffer Pool currently
is. 
</p>
        <p>
As you have seen with this posting, memory management inside SQL Server is a really
complicated topic, and we just have touched the tip of the iceberg. So don't trust
Task Manager blindly regarding the memory consumption of SQL Server, you really have
to know how SQL Server is configured to get the correct picture. 
</p>
        <p>
Thanks for reading 
</p>
        <p>
-Klaus
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08" />
      </body>
      <title>Why SQL Server is using so LESS memory</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08.aspx</link>
      <pubDate>Fri, 04 Nov 2011 21:20:13 GMT</pubDate>
      <description>&lt;p&gt;
Today I want to talk about a phenomenon regarding memory management in SQL Server.
A few weeks ago I had a consulting customer where we made some SQL Server performance
improvements. As a side note the customer asked me, why SQL Server isn't using as
much memory as possible on their production system. Their database was about 500 GB,
and when we looked into the Task Manager of Windows, we saw that SQL Server was just
consuming a few hundred MBs: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/110411_2120_WhySQLServe1.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
In the first step this behavior of SQL Server was a little bit amazing, but the answer
was found very fast, when we looked into the details of their production configuration.
The problem was that the customer granted the &lt;strong&gt;Locked Pages in Memory&lt;/strong&gt; privilege
to the service account under which SQL Server was running. You can check if you have
granted this privilege when you look into the current SQL Server Error Log. If you
have granted that privilege, you can see following informational message during the
startup of SQL Server: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/110411_2120_WhySQLServe2.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
In the first step of this posting I want to explain why and when you should use that
privilege for SQL Server, and in the second step you will see, how SQL Server uses
that privilege and why Task Manager is lying to you regarding the memory consumption. 
&lt;/p&gt;
&lt;p&gt;
Every time when the Windows OS gets into memory pressure, the Windows OS raises a
so-called &lt;strong&gt;Memory Resource Notification Event&lt;/strong&gt; to all processes that
are currently running on the box (see &lt;a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366541(v=vs.85).aspx"&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/aa366541(v=vs.85).aspx&lt;/a&gt; for
the corresponding API function). SQL Server subscribes to this event and processes
it internally through a component called the &lt;strong&gt;Resource Monitor&lt;/strong&gt;. Additional
information about the Resource Monitor component is reported through the Ring Buffer
type &lt;strong&gt;RING_BUFFER_RESOURCE_MONITOR&lt;/strong&gt; that is stored inside the DMV &lt;strong&gt;sys.dm_os_ring_buffers&lt;/strong&gt;.
When SQL Server receives the Memory Resource Notification Event, SQL Server must trim
its internal caches, like the Buffer Pool, or the Plan Cache to get out of memory
pressure. But there are some scenarios in which SQL Server reacts to slow to memory
pressure. In that case the Windows OS will do a so-called &lt;strong&gt;Hard Working Set
Trim&lt;/strong&gt;, and pages the process (in our case SQL Server) out to the page file.
The Windows OS just want to survive and get out of its memory pressure. Imagine that
– the Buffer Pool, the Plan Cache – In-Memory buffers – are paged out to the page
file! Accessing the Buffer Pool – our in-memory cache - means reading pages from the
physical disk! You can imagine that the performance of SQL Server will decrease massively… 
&lt;/p&gt;
&lt;p&gt;
Another case when a Hard Working Set Trim can occur is, when you have device drivers
that have bugs, or when the Windows OS has bugs that leads to Hard Working Set Trims.
Under Windows Server 2003 there were several bugs reported that caused Hard Working
Set Trims, like: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Copying large files from the SQL Server box 
&lt;/li&gt;
&lt;li&gt;
Establishing a Remote Desktop Connection to your SQL Server box 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
But how you can find out if your performance problems occur because of Hard Working
Set Trims? When you are running a version of SQL Server prior to SQL Server 2005 SP2,
you have to monitor the overall performance of your SQL Server instance, there are
no messages or indications inside SQL Server that can tell you, if a Hard Working
Set Trim degraded the performance of SQL Server. Beginning with SQL Server 2005 SP2
Microsoft has added an error message to the SQL Server Log, as soon as a Hard Working
Set Trim occurred, like: 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;em&gt;" A significant part of sql server process memory has been paged out.
This may result in a performance degradation. Duration: 0 seconds. Working set (KB):
1086400, committed (KB): 2160928, memory utilization: 50%" &lt;/em&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
In such cases you can enable the Locked Pages in Memory privilege to get rid of this
issue. In this case the Windows OS is not allowed to page out pages that SQL Server
allocated for the Buffer Pool. Yes, you read correct: Locked Pages in Memory is only
used for Buffer Pool allocations inside SQL Server! 
&lt;/p&gt;
&lt;p&gt;
But on the other hand you also have to investigate &lt;strong&gt;WHY&lt;/strong&gt; a Hard Working
Set Trim occurred on your system. A Hard Working Set Trim is just the result of another
problem that you have on your Windows box. So you should find the root cause, and
eliminate it, instead of using the shortcut (enabling Locked Pages in Memory) infinitely.
I know a lot of DBAs who are using Locked Pages in Memory by default, and there are
several pro and cons for this which I don't want to discuss here again. Glen Berry
has a great article which describes more of those pros and cons (see &lt;a href="http://sqlserverperformance.wordpress.com/2011/02/14/sql-server-and-the-lock-pages-in-memory-right-in-windows-server"&gt;http://sqlserverperformance.wordpress.com/2011/02/14/sql-server-and-the-lock-pages-in-memory-right-in-windows-server&lt;/a&gt;).
One thing that I want to mention here again is the fact that you should limit the
memory that SQL Server can allocate for the Buffer Pool when you use Locked Pages
in Memory. You can limit the memory through the &lt;strong&gt;Max Memory Setting&lt;/strong&gt; of
your SQL Server instance. 
&lt;/p&gt;
&lt;p&gt;
By now you know when and how you can enable Locked Pages in Memory for your SQL Server
instance. But why the heck Task Manager is reporting a wrong Working Set size when
SQL Server is using that privilege. For this explanation we have to dig a little bit
deeper into the Win32API. By default (without Locked Pages in Memory) SQL Server allocates
memory for the Buffer Pool through the &lt;strong&gt;VirtualAlloc&lt;/strong&gt; function of the
Win32API (see &lt;a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx)"&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx)&lt;/a&gt;.
But when the SQL Server service account has the Locked Pages in Memory privilege,
SQL Server internally uses the &lt;strong&gt;AllocateUserPhysicalPages&lt;/strong&gt; Win32API
function (see &lt;a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366528(v=vs.85).aspx)"&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/aa366528(v=vs.85).aspx)&lt;/a&gt; to
do Buffer Pool allocations. This function can be only called by a process, when the
process has the &lt;strong&gt;SeLockMemoryPrivilege&lt;/strong&gt; – in other words the Locked
Pages in Memory privilege which is the user-friendly name. The Win32API function &lt;strong&gt;AllocateUserPhysicalPages&lt;/strong&gt; is
part of the Address Windowing Extensions API (AWE). Therefore those memory allocations
can't be paged out by the Windows OS, because AWE memory regions are not page able
by design. Those memory regions are just locked in memory, therefore the name of this
privilege. When you have Locked Pages in Memory for your SQL Server service account
enabled, it also means that you are using AWE indirectly – funny isn't it? As you
can see from this explanation, Locked Pages in Memory is rather a Windows OS concept
than a SQL Server concept. It has nothing to do directly with SQL Server. SQL Server
is just a consumer of it. 
&lt;/p&gt;
&lt;p&gt;
With this basic knowledge in your hand, it is now very easy to explain why Task Manager
doesn't show the correct Working Set of the SQL Server process: Task Manager is not
reporting those memory allocations that are done through the Win32API function &lt;strong&gt;AllocateUserPhysicalPages&lt;/strong&gt; –
that's all about this phenomenon. 
&lt;/p&gt;
&lt;p&gt;
But how can you now find out, how much memory SQL Server is really using? There are
several possibilities. Inside SQL Server you can use the DMV &lt;strong&gt;sys.dm_os_process_memory&lt;/strong&gt; and
the column &lt;strong&gt;physical_memory_in_use_kb&lt;/strong&gt;. This returns you the physical
memory that SQL Server is currently using including AWE memory allocations. If you
want to have a more detailed breakdown of the memory consumption of SQL Server, you
can use the DMV &lt;strong&gt;sys.dm_os_memory_clerks&lt;/strong&gt;. A memory clerk is a component
inside SQL Server, which tracks memory allocations for a specific component inside
SQL Server. SQL Server gives you a memory clerks for each major component for each
available NUMA node in your system. The column &lt;strong&gt;awe_allocated_kb&lt;/strong&gt; shows
you the AWE memory allocations in kb that were allocated by SQL Server through the
Win32API function &lt;strong&gt;AllocateUserPhysicalPages&lt;/strong&gt;. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update&lt;/strong&gt;:&lt;br /&gt;
Aaron Bertrand (see &lt;a href="http://sqlblog.com/blogs/aaron_bertrand"&gt;http://sqlblog.com/blogs/aaron_bertrand&lt;/a&gt;)
mentioned that it would also make sense to reference a Performance Monitor counter
to track the memory consumption of SQL Server. So here it is: 
&lt;/p&gt;
&lt;p&gt;
Outside of SQL Server you can use the Performance Monitor counter &lt;strong&gt;SQLServer:Memory
Manager/Total Server Memory (KB)&lt;/strong&gt; to track how large the Buffer Pool currently
is. 
&lt;/p&gt;
&lt;p&gt;
As you have seen with this posting, memory management inside SQL Server is a really
complicated topic, and we just have touched the tip of the iceberg. So don't trust
Task Manager blindly regarding the memory consumption of SQL Server, you really have
to know how SQL Server is configured to get the correct picture. 
&lt;/p&gt;
&lt;p&gt;
Thanks for reading 
&lt;/p&gt;
&lt;p&gt;
-Klaus
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,dfc894e6-caf4-4a31-a7d9-eaf6bbe7ba08.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=6e9447c6-212e-4638-8f52-499a88758517</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,6e9447c6-212e-4638-8f52-499a88758517.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,6e9447c6-212e-4638-8f52-499a88758517.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=6e9447c6-212e-4638-8f52-499a88758517</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
On October 18, 2011 I have made unfair and incorrect words on Twitter, Facebook, LinkedIn,
and Xing against the owners of SQLWorkshops.com. Because of this misbehavior of me,
I got a so-called dissuasion letter from SQLWorkshops.com, which I have signed today,
because I'm committing me now not to make such unfair and incorrect words any more
in the future against SQLWorkshops.com. 
</p>
        <p>
I also want to take the chance and correct my unfair and incorrect statements of October
18, 2011. It was incorrect and wrong by me that I have blamed SQLWorkshops.com for
the following things: 
</p>
        <ul>
          <li>
Unfair Business Conduct ("Some people are not playing fair") 
</li>
          <li>
Sending of threatening emails and letters ("They wrote me and Adam Machanic hard threating
emails, because we were presenting on memory spills at sqlpass. At least I and Adam
Machanic got a sqlsue email, because we have presented on memory spills at sqlpass.") 
</li>
          <li>
Organizing and running workshops of bad quality and of oversized prices ("They are
charging horrible amounts for their workshops. Talked to some customers and they really
suck. The attendees are not really amazed. Content is not really that bright…") 
</li>
          <li>
They have made pressure against me to remove my query memory spills demo from my various
session downloads. 
</li>
        </ul>
        <p>
I apologize for any inconveniences that I have made with these unfair and incorrect
statements. 
</p>
        <p>
-Klaus 
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=6e9447c6-212e-4638-8f52-499a88758517" />
      </body>
      <title>Correction of my unfair and incorrect words against SQLWorkshops.com</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,6e9447c6-212e-4638-8f52-499a88758517.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,6e9447c6-212e-4638-8f52-499a88758517.aspx</link>
      <pubDate>Wed, 02 Nov 2011 16:16:15 GMT</pubDate>
      <description>&lt;p&gt;
On October 18, 2011 I have made unfair and incorrect words on Twitter, Facebook, LinkedIn,
and Xing against the owners of SQLWorkshops.com. Because of this misbehavior of me,
I got a so-called dissuasion letter from SQLWorkshops.com, which I have signed today,
because I'm committing me now not to make such unfair and incorrect words any more
in the future against SQLWorkshops.com. 
&lt;/p&gt;
&lt;p&gt;
I also want to take the chance and correct my unfair and incorrect statements of October
18, 2011. It was incorrect and wrong by me that I have blamed SQLWorkshops.com for
the following things: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Unfair Business Conduct ("Some people are not playing fair") 
&lt;/li&gt;
&lt;li&gt;
Sending of threatening emails and letters ("They wrote me and Adam Machanic hard threating
emails, because we were presenting on memory spills at sqlpass. At least I and Adam
Machanic got a sqlsue email, because we have presented on memory spills at sqlpass.") 
&lt;/li&gt;
&lt;li&gt;
Organizing and running workshops of bad quality and of oversized prices ("They are
charging horrible amounts for their workshops. Talked to some customers and they really
suck. The attendees are not really amazed. Content is not really that bright…") 
&lt;/li&gt;
&lt;li&gt;
They have made pressure against me to remove my query memory spills demo from my various
session downloads. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
I apologize for any inconveniences that I have made with these unfair and incorrect
statements. 
&lt;/p&gt;
&lt;p&gt;
-Klaus 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=6e9447c6-212e-4638-8f52-499a88758517" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,6e9447c6-212e-4638-8f52-499a88758517.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=8cf856fa-21b6-4525-8d30-4d6714011ab0</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,8cf856fa-21b6-4525-8d30-4d6714011ab0.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,8cf856fa-21b6-4525-8d30-4d6714011ab0.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8cf856fa-21b6-4525-8d30-4d6714011ab0</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Today I want to talk about a specified wait type that can be sometimes very hard to
troubleshoot: the <strong>THREADPOOL</strong> wait type. This wait type is specific
to the internal thread scheduling mechanism inside SQL Server. 
</p>
        <p>
As you might know SQL Server internally uses its own "operating system" to implement
thread scheduling and memory management – the SQLOS. The SQLOS provides a set of worker
threads that are used to execute queries that are submitted to SQL Server. The problem
is that those worker threads can be exhausted sometimes - maybe because of a Locking/Blocking
scenario. In this case SQL Server isn't able to execute any more requests inside the
engine, because no free worker threads are available any more. 
</p>
        <p>
You can configure through the <strong>max worker threads</strong> option (through <strong>sp_configure</strong>)
how many worker threads are available to SQLOS. By default the value of this option
is 0, which means SQL Server itself decides how many worker threads are used. The
number of the available worker threads depends on the processor architecture (x32,
x64) and the number of CPUs that you have available. Books Online (see <a href="http://msdn.microsoft.com/en-us/library/ms187024.aspx">http://msdn.microsoft.com/en-us/library/ms187024.aspx</a>)
has the following table that describes the various possible combinations: 
</p>
        <div>
          <table style="border-collapse:collapse" border="0">
            <colgroup>
              <col style="width:196px" />
              <col style="width:85px" />
              <col style="width:76px" />
            </colgroup>
            <tbody valign="top">
              <tr>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  solid 0.5pt; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>Number of CPUs</strong>
                  </p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  solid 0.5pt; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>x32</strong>
                  </p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  solid 0.5pt; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>x64</strong>
                  </p>
                </td>
              </tr>
              <tr>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>&lt;= 4 Processors</strong>
                  </p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
256
</p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
512
</p>
                </td>
              </tr>
              <tr>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>8 Processors</strong>
                  </p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
288
</p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
576
</p>
                </td>
              </tr>
              <tr>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>16 Processors</strong>
                  </p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
352
</p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
704
</p>
                </td>
              </tr>
              <tr>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
                    <strong>32 Processors</strong>
                  </p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
480
</p>
                </td>
                <td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt">
                  <p>
960
</p>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
        <p>
        </p>
        <p>
You can also check through the column <strong>max_workers_count</strong> in <strong>sys.dm_os_sys_info</strong> how
many worker threads your SQL Server instance is using. With the following example
I want to demonstrate now how you can get thread starvation in SQL Server and how
you can resolve it. 
</p>
        <p>
          <span style="color:red">
            <strong>CAUTION: DON'T DO THE FOLLOWING STEPS ON A PRODUCTION
SYSTEM!!! </strong>
          </span>
        </p>
        <p>
In the first step we create a new database and a simple table for our sample scenario.
I want to be unique as possible; therefore I use unique table and column names ;-) 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">USE</span>
            <span style="color:blue">master </span>
          </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">CREATE</span>
            <span style="color:blue">DATABASE</span> ThreadPoolWaits </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">USE</span> ThreadPoolWaits </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Create a new
test table (this one will be unique on earth - hopefully...) </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">CREATE</span>
            <span style="color:blue">TABLE</span> [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] </span>
        </p>
        <p>
          <span style="color:gray; font-family:Courier New; font-size:9pt">( </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> [MyUniqueColumnName1_F67DAC4A-C202-49BB-829A-071130BF1160] </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">INT</span>
            <span style="color:blue">IDENTITY<span style="color:gray">(</span>1<span style="color:gray">,</span> 1<span style="color:gray">)</span><span style="color:gray">NOT</span><span style="color:gray">NULL</span> PRIMARY</span>
            <span style="color:blue">KEY<span style="color:gray">, </span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> [MyUniqueColumnName2_438B7184-B476-48A4-B5FA-DC34B99FA0A4] </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">INT </span>
          </span>
        </p>
        <p>
          <span style="color:gray; font-family:Courier New; font-size:9pt">) </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Insert a record </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">INSERT</span>
            <span style="color:blue">INTO</span> [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">VALUES <span style="color:gray">(</span>1<span style="color:gray">) </span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
As you can see from the previous listing, our table definition is very simple. In
the next step I'm creating a new stored procedure that encapsulates some read workload
inside that database. 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Create a stored
procedure that encapsulates a read workload </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">CREATE</span>
            <span style="color:blue">PROCEDURE</span> MyCustomUniqueStoredProcedureName_ReadWorkload </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">AS </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">BEGIN </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span>
            <span style="color:gray">*</span>
            <span style="color:blue">FROM</span> [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">END </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
Finally we are beginning a new transaction, making an update to the previous created
table, and never committing that transaction: 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Begin a transaction
that never commits... </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">BEGIN</span>
            <span style="color:blue">TRANSACTION </span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">UPDATE</span> [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WITH <span style="color:gray">(<span style="color:blue">TABLOCKX<span style="color:gray">) </span></span></span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SET</span> [MyUniqueColumnName2_438B7184-B476-48A4-B5FA-DC34B99FA0A4] <span style="color:gray">=</span> 2<br /><span style="color:blue">GO</span></span>
        </p>
        <p>
By now you have a pending transaction inside your SQL Server instance that holds an
exclusive table lock because of the <strong>TABLOCKX</strong> query hint. When you
now execute the previous created stored procedure from a different session, the stored
procedure is waiting because it needs to acquire a Shared lock for reading the record: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">EXEC</span> MyCustomUniqueStoredProcedureName_ReadWorkload </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
You can also check this Locking/Blocking scenario through the DMV <strong>sys.dm_db_tran_locks</strong>,
which will show you a waiting request: 
</p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">SELECT </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> resource_associated_entity_id<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> request_mode<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> request_status<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> request_session_id </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">FROM</span>
            <span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_tran_locks </span></span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> resource_database_id <span style="color:gray">=</span><span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'ThreadPoolWaits'<span style="color:gray">) </span></span></span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:gray">AND</span> resource_type <span style="color:gray">=</span><span style="color:red">'OBJECT' </span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
In this simple scenario with just one waiting query inside SQL Server, nothing special
occurs. But how will SQL Server react when you use a massive amount of queries that
is larger than the possible max worker threads? Let's try it. I'm using for this task
the ostress.exe utility that is part of the RML Tools that are provided free by Microsoft
(see <a href="http://www.microsoft.com/download/en/details.aspx?id=4511">here</a>).
In my configuration (x64, 8 CPUs) SQL Server uses internally 576 worker threads. So
I'm simulating with ostress.exe 600 concurrent connections to SQL Server through the
following command line: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <strong>ostress.exe<br />
-Q"EXEC ThreadPoolWaits.dbo.MyCustomUniqueStoredProcedureName_ReadWorkload"<br />
-n600 </strong>
          </span>
        </p>
        <p>
When you execute that command prompt, it takes a few seconds until ostress.exe has
created the 600 worker threads, and nothing special happens. Seems so far so good.
Let's now analyze the situation and create a new connection through SQL Server Management
Studio to your SQL Server instance. Oops, the connection can't be made: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo1.png" alt="" />
        </p>
        <p>
SQL Server isn't responding anymore!!! This makes sense, because we have now exhausted
the maximum available worker threads. Almost all submitted requests to SQL Server
are currently waiting for a Shared Lock (<strong>LCK_M_S</strong> wait type), and
all the other ones can't be enqueued inside SQL Server because no worker threads are
available anymore (<strong>THREADPOOL</strong> wait type). But how can we troubleshoot
that scenario now? Restarting SQL Server isn't always really an option… 
</p>
        <p>
Fortunately Microsoft provides since SQL Server 2005 the so-called <strong>Dedicated
Admin Connection</strong> (DAC). With this connection you are able to log into SQL
Server even when you have worker thread starvation or high memory pressure, because
the DAC has its own 
</p>
        <ul>
          <li>
Scheduler 
</li>
          <li>
Memory Node 
</li>
          <li>
TCP Port 
</li>
        </ul>
        <p>
inside SQLOS. Therefore SQL Server is able to accept and serve the DAC connection
– even in high sophisticated troubleshooting scenarios like this one. But there is
only one available DAC for the whole SQL Server instance, which must be also taken
into account! When you want to connect through the DAC, you have to use the following
syntax: <strong>admin:&lt;servername&gt;</strong> where <strong>&lt;servername&gt;</strong> is
the name of your SQL Server instance. So let's start up a new instance of SQL Server
Management Studio and log into SQL Server through the DAC. Please be aware that you
don't connect the Object Explorer through the DAC, because the DAC isn't supported
for the Object Explorer. You can only use a simple query window that connects through
the DAC: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo2.png" alt="" />
        </p>
        <p>
When you have successfully connected through the DAC, you are now able to run your
diagnostic queries. You must be also aware that the DAC doesn't support Auto Completion,
because Auto Completion uses its own connection in the background – so you have to
know the DMVs you want to use for troubleshooting <span style="font-family:Wingdings">J</span>.
In the first step we can check <strong>sys.dm_exec_requests</strong> which requests
are currently waiting inside SQL Server: 
</p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">SELECT </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>command<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.<span style="color:blue">sql_handle<span style="color:gray">, </span></span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>plan_handle<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>wait_type<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>wait_resource<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>wait_time<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>session_id<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> r<span style="color:gray">.</span>blocking_session_id </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">FROM</span>
            <span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_exec_requests</span> r </span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:gray">INNER</span>
            <span style="color:gray">JOIN</span>
            <span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_exec_sessions</span> s <span style="color:blue">ON</span> r.</span>session_id <span style="color:gray">=</span> s<span style="color:gray">.</span>session_id </span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> s<span style="color:gray">.</span>is_user_process <span style="color:gray">=</span> 1 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
In my configuration this query returns me 547 rows, which means 547 user requests
(<strong>WHERE s.is_user_process = 1</strong>) are currently waiting inside SQL Server.
But we have started our stored procedure with 600 concurrent users… <strong>sys.dm_exec_requests</strong> shows
you only those requests that have an underlying worker thread inside SQL Server, because
those requests are currently executing inside SQL Server. But where are the others?
Those other pending requests are only accessible through <strong>sys.dm_os_waiting_tasks</strong> –
they have a wait type of <strong>THREADPOOL</strong>: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span>
            <span style="color:gray">*</span>
            <span style="color:blue">FROM</span>
            <span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_os_waiting_tasks </span></span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> wait_type <span style="color:gray">=</span><span style="color:red">'THREADPOOL' </span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
They are just waiting until a new thread from the worker pool gets free. But in our
scenario every thread is currently suspended and bound to a user request, therefore
those requests will wait forever! You can also see the <strong>THREADPOOL</strong> wait
type only inside <strong>sys.dm_os_waiting_tasks</strong> and never in <strong>sys.dm_exec_requests</strong>,
because a request in <strong>sys.dm_exec_requests</strong> is already bound to a worker
thread inside SQL Server. When you look back to the output of <strong>sys.dm_exec_requests</strong> you
can also see the columns <strong>session_id</strong> and <strong>blocking_session_id</strong> at
the end of the result set. Those 2 columns are showing you the blocking chain inside
SQL Server: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo3.png" alt="" />
        </p>
        <p>
As you can see almost every session has <strong>a blocking_session_id</strong> of
56, and the <strong>session_id</strong> 56 has a <strong>blocking_session_id</strong> of
52. <strong>The session_id</strong> 52 is our head blocker! Let's further analyze
the session of the head blocker: 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Analyze the head
blocker session </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">SELECT </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> login_time<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> [host_name]<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> [program_name]<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> login_name </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">FROM</span>
            <span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_exec_sessions </span></span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> session_id <span style="color:gray">=</span> 52 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Analye the head
blocker connection </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">SELECT </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> connect_time<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> client_tcp_port<span style="color:gray">, </span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> most_recent_sql_handle </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">FROM</span>
            <span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_exec_connections </span></span></span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> session_id <span style="color:gray">=</span> 52 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
The most interesting column is here <strong>most_recent_sql_handle</strong> from <strong>sys.dm_exec_connections</strong> which
we can use to retrieve the executed SQL statement. When you use the DMF <strong>sys.dm_exec_sql_text</strong> and
pass in the value of the <strong>most_recent_sql_handle</strong> column you are able
to retrieve the executed SQL statement: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> [text] <span style="color:blue">FROM</span><span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_exec_sql_text<span style="color:gray">(</span>0x01001A0015BE5D3170CC4483000000000000000000000000<span style="color:gray">) </span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
This SELECT statement will return you the following string: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">-- Begin a transaction that never
commits... BEGIN TRANSACTION UPDATE [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49]
WITH (TABLOCKX) SET</span>
          <span style="font-family:Courier New; font-size:9pt">[MyUniqueColumnName2_438B7184-B476-48A4-B5FA-DC34B99FA0A4]
= 2 </span>
        </p>
        <p>
This is our initial query where we left our transaction open. By now we have tracked
down the problematic query that had leaded to <strong>THREADPOOL</strong> and <strong>LCK_M_S</strong> waits,
and finally we can kill that session through the DAC: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">KILL</span> 52 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
Now it takes several seconds until the session is killed, and finally our blocking
scenario is gone. By now your SQL Server is again able to accept new connections and
will work in the usual way. When you are done with troubleshooting through the DAC
connection, don't forget to close that special connection, because there is only one
DAC available for the whole SQL Server instance! When you afterwards look into the
SQL Server Error Log, you will also see a message like the following one: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <strong>New queries assigned
to process on Node 0 have not been picked up by a worker thread in the last 1680 seconds.
Blocking or long-running queries can contribute to this condition, and may degrade
client response time. Use the "max worker threads" configuration option to increase
number of allowable threads, or optimize current running queries. SQL Process Utilization:
0%. System Idle: 96%. </strong>
          </span>
        </p>
        <p>
This is also an indication that you had worker thread starvation inside your SQL Server
instance. As a side-effect this scenario has also leaded to so-called <strong>Deadlocked
Schedulers</strong>, which <a href="http://www.troubleshootingsql.com">Amit Banerjee</a> describes
in more detail <a href="http://troubleshootingsql.com/2011/08/15/debugging-the-deadlock-but-for-the-scheduler-part-1-of-2/">here</a>.
When SQL Server encounters Deadlocked Schedulers, SQL Server will write out a Stack
Dump to your SQL Server <strong>LOG</strong> directory. You can also see a Deadlocked
Scheduler inside the SQL Server Error Log: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo4.png" alt="" />
        </p>
        <p>
Sometimes I see customers which just blindly reconfigure the <strong>max worker threads</strong> setting
inside SQL Server, because they think they need more worker threads for their workload.
But as with almost every problem in SQL Server, there is some root cause which has
leaded to the problem that you are currently seeing. In our scenario the root cause
was an uncommitted transaction, which leaded to a blocking scenario, which leaded
to thread starvation, which finally leaded to an unresponsive SQL Server. As you can
see from this explanation, there could be a very long chain until you find your root
cause – so keep that in mind for your next troubleshooting scenarios. 
</p>
        <p>
To make it easy for you to reproduce that special scenario, you can download the needed
scripts from <a href="http://www.sqlpassion.at/downloads/threadpool.zip">here</a>. 
</p>
        <p>
Thanks for reading! 
</p>
        <p>
-Klaus
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=8cf856fa-21b6-4525-8d30-4d6714011ab0" />
      </body>
      <title>Troubleshooting THREADPOOL Waits</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,8cf856fa-21b6-4525-8d30-4d6714011ab0.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,8cf856fa-21b6-4525-8d30-4d6714011ab0.aspx</link>
      <pubDate>Tue, 25 Oct 2011 21:03:49 GMT</pubDate>
      <description>&lt;p&gt;
Today I want to talk about a specified wait type that can be sometimes very hard to
troubleshoot: the &lt;strong&gt;THREADPOOL&lt;/strong&gt; wait type. This wait type is specific
to the internal thread scheduling mechanism inside SQL Server. 
&lt;/p&gt;
&lt;p&gt;
As you might know SQL Server internally uses its own "operating system" to implement
thread scheduling and memory management – the SQLOS. The SQLOS provides a set of worker
threads that are used to execute queries that are submitted to SQL Server. The problem
is that those worker threads can be exhausted sometimes - maybe because of a Locking/Blocking
scenario. In this case SQL Server isn't able to execute any more requests inside the
engine, because no free worker threads are available any more. 
&lt;/p&gt;
&lt;p&gt;
You can configure through the &lt;strong&gt;max worker threads&lt;/strong&gt; option (through &lt;strong&gt;sp_configure&lt;/strong&gt;)
how many worker threads are available to SQLOS. By default the value of this option
is 0, which means SQL Server itself decides how many worker threads are used. The
number of the available worker threads depends on the processor architecture (x32,
x64) and the number of CPUs that you have available. Books Online (see &lt;a href="http://msdn.microsoft.com/en-us/library/ms187024.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms187024.aspx&lt;/a&gt;)
has the following table that describes the various possible combinations: 
&lt;/p&gt;
&lt;div&gt;
&lt;table style="border-collapse:collapse" border="0"&gt;
&lt;colgroup&gt;
&lt;col style="width:196px" /&gt;
&lt;col style="width:85px" /&gt;
&lt;col style="width:76px" /&gt;
&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  solid 0.5pt; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;Number of CPUs&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  solid 0.5pt; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;x32&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  solid 0.5pt; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;x64&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;&amp;lt;= 4 Processors&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
256
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
512
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;8 Processors&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
288
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
576
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;16 Processors&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
352
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
704
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  solid 0.5pt; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
&lt;strong&gt;32 Processors&lt;/strong&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
480
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="padding-left: 7px; padding-right: 7px; border-top:  none; border-left:  none; border-bottom:  solid 0.5pt; border-right:  solid 0.5pt"&gt;
&lt;p&gt;
960
&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
You can also check through the column &lt;strong&gt;max_workers_count&lt;/strong&gt; in &lt;strong&gt;sys.dm_os_sys_info&lt;/strong&gt; how
many worker threads your SQL Server instance is using. With the following example
I want to demonstrate now how you can get thread starvation in SQL Server and how
you can resolve it. 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:red"&gt;&lt;strong&gt;CAUTION: DON'T DO THE FOLLOWING STEPS ON A PRODUCTION
SYSTEM!!! &lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
In the first step we create a new database and a simple table for our sample scenario.
I want to be unique as possible; therefore I use unique table and column names ;-) 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;USE&lt;/span&gt; &lt;span style="color:blue"&gt;master &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;CREATE&lt;/span&gt; &lt;span style="color:blue"&gt;DATABASE&lt;/span&gt; ThreadPoolWaits &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;USE&lt;/span&gt; ThreadPoolWaits &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Create a new
test table (this one will be unique on earth - hopefully...) &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;CREATE&lt;/span&gt; &lt;span style="color:blue"&gt;TABLE&lt;/span&gt; [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:gray; font-family:Courier New; font-size:9pt"&gt;( &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; [MyUniqueColumnName1_F67DAC4A-C202-49BB-829A-071130BF1160] &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; &lt;span style="color:blue"&gt;INT&lt;/span&gt; &lt;span style="color:blue"&gt;IDENTITY&lt;span style="color:gray"&gt;(&lt;/span&gt;1&lt;span style="color:gray"&gt;,&lt;/span&gt; 1&lt;span style="color:gray"&gt;)&lt;/span&gt; &lt;span style="color:gray"&gt;NOT&lt;/span&gt; &lt;span style="color:gray"&gt;NULL&lt;/span&gt; PRIMARY&lt;/span&gt; &lt;span style="color:blue"&gt;KEY&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; [MyUniqueColumnName2_438B7184-B476-48A4-B5FA-DC34B99FA0A4] &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; &lt;span style="color:blue"&gt;INT &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:gray; font-family:Courier New; font-size:9pt"&gt;) &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Insert a record &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;INSERT&lt;/span&gt; &lt;span style="color:blue"&gt;INTO&lt;/span&gt; [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;VALUES &lt;span style="color:gray"&gt;(&lt;/span&gt;1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
As you can see from the previous listing, our table definition is very simple. In
the next step I'm creating a new stored procedure that encapsulates some read workload
inside that database. 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Create a stored
procedure that encapsulates a read workload &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;CREATE&lt;/span&gt; &lt;span style="color:blue"&gt;PROCEDURE&lt;/span&gt; MyCustomUniqueStoredProcedureName_ReadWorkload &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;AS &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;BEGIN &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; &lt;span style="color:blue"&gt;SELECT&lt;/span&gt; &lt;span style="color:gray"&gt;*&lt;/span&gt; &lt;span style="color:blue"&gt;FROM&lt;/span&gt; [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;END &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
Finally we are beginning a new transaction, making an update to the previous created
table, and never committing that transaction: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Begin a transaction
that never commits... &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;BEGIN&lt;/span&gt; &lt;span style="color:blue"&gt;TRANSACTION &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; &lt;span style="color:blue"&gt;UPDATE&lt;/span&gt; [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49] &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; &lt;span style="color:blue"&gt;WITH &lt;span style="color:gray"&gt;(&lt;span style="color:blue"&gt;TABLOCKX&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; &lt;span style="color:blue"&gt;SET&lt;/span&gt; [MyUniqueColumnName2_438B7184-B476-48A4-B5FA-DC34B99FA0A4] &lt;span style="color:gray"&gt;=&lt;/span&gt; 2&lt;br /&gt;
&lt;span style="color:blue"&gt;GO&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
By now you have a pending transaction inside your SQL Server instance that holds an
exclusive table lock because of the &lt;strong&gt;TABLOCKX&lt;/strong&gt; query hint. When you
now execute the previous created stored procedure from a different session, the stored
procedure is waiting because it needs to acquire a Shared lock for reading the record: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;EXEC&lt;/span&gt; MyCustomUniqueStoredProcedureName_ReadWorkload &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
You can also check this Locking/Blocking scenario through the DMV &lt;strong&gt;sys.dm_db_tran_locks&lt;/strong&gt;,
which will show you a waiting request: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;SELECT &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; resource_associated_entity_id&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; request_mode&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; request_status&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; request_session_id &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_tran_locks &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; resource_database_id &lt;span style="color:gray"&gt;=&lt;/span&gt; &lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'ThreadPoolWaits'&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:gray"&gt;AND&lt;/span&gt; resource_type &lt;span style="color:gray"&gt;=&lt;/span&gt; &lt;span style="color:red"&gt;'OBJECT' &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
In this simple scenario with just one waiting query inside SQL Server, nothing special
occurs. But how will SQL Server react when you use a massive amount of queries that
is larger than the possible max worker threads? Let's try it. I'm using for this task
the ostress.exe utility that is part of the RML Tools that are provided free by Microsoft
(see &lt;a href="http://www.microsoft.com/download/en/details.aspx?id=4511"&gt;here&lt;/a&gt;).
In my configuration (x64, 8 CPUs) SQL Server uses internally 576 worker threads. So
I'm simulating with ostress.exe 600 concurrent connections to SQL Server through the
following command line: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;strong&gt;ostress.exe&lt;br /&gt;
-Q"EXEC ThreadPoolWaits.dbo.MyCustomUniqueStoredProcedureName_ReadWorkload"&lt;br /&gt;
-n600 &lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
When you execute that command prompt, it takes a few seconds until ostress.exe has
created the 600 worker threads, and nothing special happens. Seems so far so good.
Let's now analyze the situation and create a new connection through SQL Server Management
Studio to your SQL Server instance. Oops, the connection can't be made: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo1.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
SQL Server isn't responding anymore!!! This makes sense, because we have now exhausted
the maximum available worker threads. Almost all submitted requests to SQL Server
are currently waiting for a Shared Lock (&lt;strong&gt;LCK_M_S&lt;/strong&gt; wait type), and
all the other ones can't be enqueued inside SQL Server because no worker threads are
available anymore (&lt;strong&gt;THREADPOOL&lt;/strong&gt; wait type). But how can we troubleshoot
that scenario now? Restarting SQL Server isn't always really an option… 
&lt;/p&gt;
&lt;p&gt;
Fortunately Microsoft provides since SQL Server 2005 the so-called &lt;strong&gt;Dedicated
Admin Connection&lt;/strong&gt; (DAC). With this connection you are able to log into SQL
Server even when you have worker thread starvation or high memory pressure, because
the DAC has its own 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Scheduler 
&lt;/li&gt;
&lt;li&gt;
Memory Node 
&lt;/li&gt;
&lt;li&gt;
TCP Port 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
inside SQLOS. Therefore SQL Server is able to accept and serve the DAC connection
– even in high sophisticated troubleshooting scenarios like this one. But there is
only one available DAC for the whole SQL Server instance, which must be also taken
into account! When you want to connect through the DAC, you have to use the following
syntax: &lt;strong&gt;admin:&amp;lt;servername&amp;gt;&lt;/strong&gt; where &lt;strong&gt;&amp;lt;servername&amp;gt;&lt;/strong&gt; is
the name of your SQL Server instance. So let's start up a new instance of SQL Server
Management Studio and log into SQL Server through the DAC. Please be aware that you
don't connect the Object Explorer through the DAC, because the DAC isn't supported
for the Object Explorer. You can only use a simple query window that connects through
the DAC: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo2.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
When you have successfully connected through the DAC, you are now able to run your
diagnostic queries. You must be also aware that the DAC doesn't support Auto Completion,
because Auto Completion uses its own connection in the background – so you have to
know the DMVs you want to use for troubleshooting &lt;span style="font-family:Wingdings"&gt;J&lt;/span&gt;.
In the first step we can check &lt;strong&gt;sys.dm_exec_requests&lt;/strong&gt; which requests
are currently waiting inside SQL Server: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;SELECT &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;command&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;span style="color:blue"&gt;sql_handle&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;plan_handle&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;wait_type&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;wait_resource&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;wait_time&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;session_id&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; r&lt;span style="color:gray"&gt;.&lt;/span&gt;blocking_session_id &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_exec_requests&lt;/span&gt; r &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:gray"&gt;INNER&lt;/span&gt; &lt;span style="color:gray"&gt;JOIN&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_exec_sessions&lt;/span&gt; s &lt;span style="color:blue"&gt;ON&lt;/span&gt; r.&lt;/span&gt;session_id &lt;span style="color:gray"&gt;=&lt;/span&gt; s&lt;span style="color:gray"&gt;.&lt;/span&gt;session_id &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; s&lt;span style="color:gray"&gt;.&lt;/span&gt;is_user_process &lt;span style="color:gray"&gt;=&lt;/span&gt; 1 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
In my configuration this query returns me 547 rows, which means 547 user requests
(&lt;strong&gt;WHERE s.is_user_process = 1&lt;/strong&gt;) are currently waiting inside SQL Server.
But we have started our stored procedure with 600 concurrent users… &lt;strong&gt;sys.dm_exec_requests&lt;/strong&gt; shows
you only those requests that have an underlying worker thread inside SQL Server, because
those requests are currently executing inside SQL Server. But where are the others?
Those other pending requests are only accessible through &lt;strong&gt;sys.dm_os_waiting_tasks&lt;/strong&gt; –
they have a wait type of &lt;strong&gt;THREADPOOL&lt;/strong&gt;: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; &lt;span style="color:gray"&gt;*&lt;/span&gt; &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_os_waiting_tasks &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; wait_type &lt;span style="color:gray"&gt;=&lt;/span&gt; &lt;span style="color:red"&gt;'THREADPOOL' &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
They are just waiting until a new thread from the worker pool gets free. But in our
scenario every thread is currently suspended and bound to a user request, therefore
those requests will wait forever! You can also see the &lt;strong&gt;THREADPOOL&lt;/strong&gt; wait
type only inside &lt;strong&gt;sys.dm_os_waiting_tasks&lt;/strong&gt; and never in &lt;strong&gt;sys.dm_exec_requests&lt;/strong&gt;,
because a request in &lt;strong&gt;sys.dm_exec_requests&lt;/strong&gt; is already bound to a worker
thread inside SQL Server. When you look back to the output of &lt;strong&gt;sys.dm_exec_requests&lt;/strong&gt; you
can also see the columns &lt;strong&gt;session_id&lt;/strong&gt; and &lt;strong&gt;blocking_session_id&lt;/strong&gt; at
the end of the result set. Those 2 columns are showing you the blocking chain inside
SQL Server: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo3.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
As you can see almost every session has &lt;strong&gt;a blocking_session_id&lt;/strong&gt; of
56, and the &lt;strong&gt;session_id&lt;/strong&gt; 56 has a &lt;strong&gt;blocking_session_id&lt;/strong&gt; of
52. &lt;strong&gt;The session_id&lt;/strong&gt; 52 is our head blocker! Let's further analyze
the session of the head blocker: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Analyze the head
blocker session &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;SELECT &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; login_time&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; [host_name]&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; [program_name]&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; login_name &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_exec_sessions &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; session_id &lt;span style="color:gray"&gt;=&lt;/span&gt; 52 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Analye the head
blocker connection &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;SELECT &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; connect_time&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; client_tcp_port&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; most_recent_sql_handle &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_exec_connections &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; session_id &lt;span style="color:gray"&gt;=&lt;/span&gt; 52 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
The most interesting column is here &lt;strong&gt;most_recent_sql_handle&lt;/strong&gt; from &lt;strong&gt;sys.dm_exec_connections&lt;/strong&gt; which
we can use to retrieve the executed SQL statement. When you use the DMF &lt;strong&gt;sys.dm_exec_sql_text&lt;/strong&gt; and
pass in the value of the &lt;strong&gt;most_recent_sql_handle&lt;/strong&gt; column you are able
to retrieve the executed SQL statement: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; [text] &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_exec_sql_text&lt;span style="color:gray"&gt;(&lt;/span&gt;0x01001A0015BE5D3170CC4483000000000000000000000000&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
This SELECT statement will return you the following string: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;-- Begin a transaction that never
commits... BEGIN TRANSACTION UPDATE [SomeCrazyUniqueTableName_6EFF088F-443B-4EBC-A4C7-9FC146D2EE49]
WITH (TABLOCKX) SET&lt;/span&gt; &lt;span style="font-family:Courier New; font-size:9pt"&gt;[MyUniqueColumnName2_438B7184-B476-48A4-B5FA-DC34B99FA0A4]
= 2 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
This is our initial query where we left our transaction open. By now we have tracked
down the problematic query that had leaded to &lt;strong&gt;THREADPOOL&lt;/strong&gt; and &lt;strong&gt;LCK_M_S&lt;/strong&gt; waits,
and finally we can kill that session through the DAC: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;KILL&lt;/span&gt; 52 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
Now it takes several seconds until the session is killed, and finally our blocking
scenario is gone. By now your SQL Server is again able to accept new connections and
will work in the usual way. When you are done with troubleshooting through the DAC
connection, don't forget to close that special connection, because there is only one
DAC available for the whole SQL Server instance! When you afterwards look into the
SQL Server Error Log, you will also see a message like the following one: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;strong&gt;New queries assigned
to process on Node 0 have not been picked up by a worker thread in the last 1680 seconds.
Blocking or long-running queries can contribute to this condition, and may degrade
client response time. Use the "max worker threads" configuration option to increase
number of allowable threads, or optimize current running queries. SQL Process Utilization:
0%. System Idle: 96%. &lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
This is also an indication that you had worker thread starvation inside your SQL Server
instance. As a side-effect this scenario has also leaded to so-called &lt;strong&gt;Deadlocked
Schedulers&lt;/strong&gt;, which &lt;a href="http://www.troubleshootingsql.com"&gt;Amit Banerjee&lt;/a&gt; describes
in more detail &lt;a href="http://troubleshootingsql.com/2011/08/15/debugging-the-deadlock-but-for-the-scheduler-part-1-of-2/"&gt;here&lt;/a&gt;.
When SQL Server encounters Deadlocked Schedulers, SQL Server will write out a Stack
Dump to your SQL Server &lt;strong&gt;LOG&lt;/strong&gt; directory. You can also see a Deadlocked
Scheduler inside the SQL Server Error Log: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/102511_2103_Troubleshoo4.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
Sometimes I see customers which just blindly reconfigure the &lt;strong&gt;max worker threads&lt;/strong&gt; setting
inside SQL Server, because they think they need more worker threads for their workload.
But as with almost every problem in SQL Server, there is some root cause which has
leaded to the problem that you are currently seeing. In our scenario the root cause
was an uncommitted transaction, which leaded to a blocking scenario, which leaded
to thread starvation, which finally leaded to an unresponsive SQL Server. As you can
see from this explanation, there could be a very long chain until you find your root
cause – so keep that in mind for your next troubleshooting scenarios. 
&lt;/p&gt;
&lt;p&gt;
To make it easy for you to reproduce that special scenario, you can download the needed
scripts from &lt;a href="http://www.sqlpassion.at/downloads/threadpool.zip"&gt;here&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Thanks for reading! 
&lt;/p&gt;
&lt;p&gt;
-Klaus
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=8cf856fa-21b6-4525-8d30-4d6714011ab0" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,8cf856fa-21b6-4525-8d30-4d6714011ab0.aspx</comments>
      <category>.NET German</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=2a24830a-5cf9-4438-96e9-af0a6d7372c3</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,2a24830a-5cf9-4438-96e9-af0a6d7372c3.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,2a24830a-5cf9-4438-96e9-af0a6d7372c3.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=2a24830a-5cf9-4438-96e9-af0a6d7372c3</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
When you sometimes look at Execution Plans, you can see that the SELECT operator has
sometimes a so-called <strong>Memory Grant</strong> assigned. This Memory Grant is
specified in kilobytes and is needed for the query execution, when some operators
(like Sort/Hash operators) in the Execution Plans need memory for execution – the
so called <strong>Query Memory</strong>. 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory1.png" alt="" />
        </p>
        <p>
This query memory must be granted by SQL Server before the query is actually executed.
The Query Optimizer uses the underlying Statistics to determine how much Query Memory
must be acquired for a given query. The problem is now, when the Statistics are out-of-date,
and SQL Server underestimates the processed rows. In this case, SQL Server will also
request to less Query Memory for the given query. But when the query actually executes,
the query can't resize its granted Query Memory, and can't just request more. The
query must operate within the granted Query Memory. In this case, SQL Server has to
spill the Sort/Hash-Operation into TempDb, which means that our very fast in-memory
operation becomes a very slow physical On-Disk operation. SQL Server Profiler will
report those Query Memory Spills through the events <strong>Sort Warnings</strong> and <strong>Hash
Warning</strong>. 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory2.png" alt="" />
        </p>
        <p>
Unfortunately SQL Server 2008 (R2) provides you no events through Extended Events
to track down those Memory Spills. In SQL Server 2012 this will change, and you will
have additional events available inside Extended Events for troubleshooting this problem.
In this posting I will illustrate you with a simple example how you can reproduce
a simple Query Memory Spill because of out-of-date statistics. Let's create a new
database and a simple test table inside it: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SET</span>
            <span style="color:blue">STATISTICS</span>
            <span style="color:blue">IO</span>
            <span style="color:blue">ON </span>
          </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SET</span>
            <span style="color:blue">STATISTICS</span>
            <span style="color:blue">TIME</span>
            <span style="color:blue">ON </span>
          </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Create a new
database </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">CREATE</span>
            <span style="color:blue">DATABASE</span> InsufficientMemoryGrants </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SUE</span> InsufficientMemoryGrants </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Create a test
table </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">CREATE</span>
            <span style="color:blue">TABLE</span> TestTable </span>
        </p>
        <p>
          <span style="color:gray; font-family:Courier New; font-size:9pt">( </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> Col1 <span style="color:blue">INT</span><span style="color:blue">IDENTITY</span><span style="color:blue">PRIMARY</span><span style="color:blue">KEY<span style="color:gray">, </span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> Col2 <span style="color:blue">INT<span style="color:gray">, </span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt"> Col3 <span style="color:blue">CHAR<span style="color:gray">(</span>4000<span style="color:gray">) </span></span></span>
        </p>
        <p>
          <span style="color:gray; font-family:Courier New; font-size:9pt">) </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Create a Non-Clustered
Index on column Col2 </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">CREATE</span>
            <span style="color:blue">NONCLUSTERED</span>
            <span style="color:blue">INDEX</span> idxTable1_Column2 <span style="color:blue">ON</span> TestTable<span style="color:gray">(</span>Col2<span style="color:gray">) </span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
The table <strong>TestTable</strong> contains the primary key on the first column,
and the second column is indexed through a Non-Clustered Index. The third column is
a <strong>CHAR(4000)</strong> column which isn't indexed. We will use that column
afterwards for an <strong>ORDER BY</strong>, so that the Query Optimizer must generate
an explicit Sort Operator inside the Execution Plan. In the next step I'm just inserting
1500 records, where we have an even data distribution across all the values in the
second column – each value exists once in our table. 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory3.png" alt="" />
        </p>
        <p>
With that test data prepared we can now execute a simple query, which must use a separate
Sort operator in the Execution Plan: 
</p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">DECLARE</span> @x <span style="color:blue">INT </span></span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> @x <span style="color:gray">=</span> Col2 <span style="color:blue">FROM</span> TestTable </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> Col2 <span style="color:gray">=</span> 2 </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">ORDER</span>
            <span style="color:blue">BY</span> Col3 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
This query uses the following Execution Plan: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory4.png" alt="" />
        </p>
        <p>
When you look into SQL Server Profiler and you have enabled the above mentioned events,
nothing happens. You can also use the DMV <strong>sys.dm_io_virtual_file_stats</strong> and
the columns <strong>num_of_writes</strong> and <strong>num_of_bytes_written</strong> to
find out if there was some activity in TempDb for a given query. This works – of course
only – when you are the only person who currently uses the given SQL Server instance: 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Check the activity
in TempDb before we execute the sort operation. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> num_of_writes<span style="color:gray">,</span> num_of_bytes_written <span style="color:blue">FROM</span></span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">sys<span style="color:gray">.<span style="color:green">dm_io_virtual_file_stats<span style="color:gray">(<span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'tempdb'<span style="color:gray">),</span> 1<span style="color:gray">) </span></span></span></span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Select a record
through the previous created Non-Clustered Index from the table. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server retrieves
the record through a Non-Clustered Index Seek operator. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server estimates
for the sort operator 1 record, which also reflects </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- the actual number
of rows. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server requests
a memory grant of 1024kb - the sorting is done inside </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- the memory. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">DECLARE</span> @x <span style="color:blue">INT </span></span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> @x <span style="color:gray">=</span> Col2 <span style="color:blue">FROM</span> TestTable </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> Col2 <span style="color:gray">=</span> 2 </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">ORDER</span>
            <span style="color:blue">BY</span> Col3 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Check the activity
in TempDb after the execution of the sort operation. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- There was no
activity in TempDb during the previous SELECT statement. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> num_of_writes<span style="color:gray">,</span> num_of_bytes_written <span style="color:blue">FROM</span></span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">sys<span style="color:gray">.<span style="color:green">dm_io_virtual_file_stats<span style="color:gray">(<span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'tempdb'<span style="color:gray">),</span> 1<span style="color:gray">) </span></span></span></span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
Again you will see no activity in TempDb, which means the output from <strong>sys.dm_io_virtual_file_stats</strong> is
the same before and after executing the query. The query takes on my system around
1ms of execution time. 
</p>
        <p>
Now we have a table with 1500 records, means that our table needs 20% + 500 rows of
data changes so that SQL Server will update the statistics. If you're doing the math,
we need 800 data modifications in that table (500 + 300). So let's just insert 799
additional rows where the value of the second column is 2. We are just changing the
data distribution and SQL Server WILL NOT update the statistics, because one additional
data change is still missing, until Update Statistics is triggered automatically inside
SQL Server! 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Insert 799 records
into table TestTable </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span>
            <span style="color:blue">TOP</span> 799 <span style="color:blue">IDENTITY<span style="color:gray">(<span style="color:blue">INT<span style="color:gray">,</span> 1<span style="color:gray">,</span> 1<span style="color:gray">)</span> AS</span> n <span style="color:blue">INTO</span> #Nums</span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">FROM </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">master<span style="color:gray">.</span>dbo<span style="color:gray">.<span style="color:green">syscolumns</span> sc1</span></span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">INSERT</span>
            <span style="color:blue">INTO</span> TestTable<span style="color:blue"><span style="color:gray">(</span>Col2<span style="color:gray">,</span> Col3<span style="color:gray">) </span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> 2<span style="color:gray">,</span><span style="color:fuchsia">REPLICATE<span style="color:gray">(<span style="color:red">'x'<span style="color:gray">,</span> 4</span>000)</span><span style="color:blue">FROM</span> #nums</span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">DROP</span>
            <span style="color:blue">TABLE</span> #nums </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
When you now execute the same query again, SQL Server will now spill the Sort operation
to TempDb, because SQL Server will only request a Query Memory Grant of 1024 kilobytes,
which is estimated for just 1 record – the memory grant has the same size as before: 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Check the activity
in TempDb before we execute the sort operation. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> num_of_writes<span style="color:gray">,</span> num_of_bytes_written <span style="color:blue">FROM</span></span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">sys<span style="color:gray">.<span style="color:green">dm_io_virtual_file_stats<span style="color:gray">(<span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'tempdb'<span style="color:gray">),</span> 1<span style="color:gray">) </span></span></span></span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server estimates
now 1 record for the sort operation and requests a memory grant of 1.024kb for the
query. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- This is too less,
because actually we are sorting 800 rows! </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server has
to spill the sort operation into TempDb, which now becomes a physical I/O operation!!! </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">DECLARE</span> @x <span style="color:blue">INT </span></span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> @x <span style="color:gray">=</span> Col2 <span style="color:blue">FROM</span> TestTable </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> Col2 <span style="color:gray">=</span> 2 </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">ORDER</span>
            <span style="color:blue">BY</span> Col3 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Check the activity
in TempDb after the execution of the sort operation. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- There is now
activity in TempDb during the previous SELECT statement. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> num_of_writes<span style="color:gray">,</span> num_of_bytes_written <span style="color:blue">FROM </span></span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">sys<span style="color:gray">.<span style="color:green">dm_io_virtual_file_stats<span style="color:gray">(<span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'tempdb'<span style="color:gray">),</span> 1<span style="color:gray">) </span></span></span></span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
If you check the <strong>Estimated Number of Rows</strong> in the Execution Plan,
they are differing completely from the <strong>Actual Number of Rows</strong>: 
</p>
        <p>
          <img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory5.png" alt="" />
        </p>
        <p>
When you track the query execution time you will also see that the execution time
increased – in my case it increased up to 200ms, which is a huge difference to the
earlier execution time of just 1ms! The DMV <strong>sys.dm_io_virtual_file_stats</strong> will
also report some activity inside TempDb, which is also the evidence that SQL Server
spilled the Sort operation into TempDb! SQL Server Profiler will also show you a Sort
Warning event. 
</p>
        <p>
If you now insert one additional record, and you run the query again, everything is
fine, because SQL Server will trigger the Statistics Update and estimate the Query
Memory Grant correctly: 
</p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Insert 1 records
into table TestTable </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span>
            <span style="color:blue">TOP</span> 1 <span style="color:blue">IDENTITY<span style="color:gray">(<span style="color:blue">INT<span style="color:gray">,</span> 1<span style="color:gray">,</span> 1<span style="color:gray">)</span> AS</span> n <span style="color:blue">INTO</span> #Nums</span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">FROM </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">master<span style="color:gray">.</span>dbo<span style="color:gray">.<span style="color:green">syscolumns</span> sc1</span></span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">INSERT</span>
            <span style="color:blue">INTO</span> TestTable<span style="color:blue"><span style="color:gray">(</span>Col2<span style="color:gray">,</span> Col3<span style="color:gray">) </span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> 2<span style="color:gray">,</span><span style="color:fuchsia">REPLICATE<span style="color:gray">(<span style="color:red">'x'<span style="color:gray">,</span> 2000<span style="color:gray">)</span><span style="color:blue">FROM</span> #nums</span></span></span></span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">DROP</span>
            <span style="color:blue">TABLE</span> #nums </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Check the activity
in TempDb before we execute the sort operation. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> num_of_writes<span style="color:gray">,</span> num_of_bytes_written <span style="color:blue">FROM</span><span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_io_virtual_file_stats<span style="color:gray">(<span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'tempdb'<span style="color:gray">),</span> 1<span style="color:gray">) </span></span></span></span></span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server has
now accurate statistics and estimates 801 rows for the sort operator. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server requests
a memory grant of 6.656kb, which is now enough. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- SQL Server now
spills the sort operation not to TempDb. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Logical reads:
577 </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">DECLARE</span> @x <span style="color:blue">INT </span></span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> @x <span style="color:gray">=</span> Col2 <span style="color:blue">FROM</span> TestTable </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">WHERE</span> Col2 <span style="color:gray">=</span> 2 </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">ORDER</span>
            <span style="color:blue">BY</span> Col3 </span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- Check the activity
in TempDb after the execution of the sort operation. </span>
        </p>
        <p>
          <span style="color:green; font-family:Courier New; font-size:9pt">-- There is now
no activity in TempDb during the previous SELECT statement. </span>
        </p>
        <p>
          <span style="font-family:Courier New; font-size:9pt">
            <span style="color:blue">SELECT</span> num_of_writes<span style="color:gray">,</span> num_of_bytes_written <span style="color:blue">FROM</span><span style="color:green">sys<span style="color:gray">.<span style="color:green">dm_io_virtual_file_stats<span style="color:gray">(<span style="color:fuchsia">DB_ID<span style="color:gray">(<span style="color:red">'tempdb'<span style="color:gray">),</span> 1<span style="color:gray">) </span></span></span></span></span></span></span></span></span>
        </p>
        <p>
          <span style="color:blue; font-family:Courier New; font-size:9pt">GO</span>
        </p>
        <p>
So this is a very basic example which shows you how you can reproduce Sort Warnings
inside SQL Server – not really a magic. Adam Machanic (<a href="http://sqlblog.com/blogs/adam_machanic">http://sqlblog.com/blogs/adam_machanic</a>)
has done last week at the SQLPASS Summit in Seattle a whole session about Query Memory
at a 500 level, where he went into more details on this complicated topic, especially
in combination with Parallel Execution Plans. 
</p>
        <p>
Thanks for reading! 
</p>
        <p>
-Klaus
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=2a24830a-5cf9-4438-96e9-af0a6d7372c3" />
      </body>
      <title>Query Memory Spills</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,2a24830a-5cf9-4438-96e9-af0a6d7372c3.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,2a24830a-5cf9-4438-96e9-af0a6d7372c3.aspx</link>
      <pubDate>Wed, 19 Oct 2011 20:04:35 GMT</pubDate>
      <description>&lt;p&gt;
When you sometimes look at Execution Plans, you can see that the SELECT operator has
sometimes a so-called &lt;strong&gt;Memory Grant&lt;/strong&gt; assigned. This Memory Grant is
specified in kilobytes and is needed for the query execution, when some operators
(like Sort/Hash operators) in the Execution Plans need memory for execution – the
so called &lt;strong&gt;Query Memory&lt;/strong&gt;. 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory1.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
This query memory must be granted by SQL Server before the query is actually executed.
The Query Optimizer uses the underlying Statistics to determine how much Query Memory
must be acquired for a given query. The problem is now, when the Statistics are out-of-date,
and SQL Server underestimates the processed rows. In this case, SQL Server will also
request to less Query Memory for the given query. But when the query actually executes,
the query can't resize its granted Query Memory, and can't just request more. The
query must operate within the granted Query Memory. In this case, SQL Server has to
spill the Sort/Hash-Operation into TempDb, which means that our very fast in-memory
operation becomes a very slow physical On-Disk operation. SQL Server Profiler will
report those Query Memory Spills through the events &lt;strong&gt;Sort Warnings&lt;/strong&gt; and &lt;strong&gt;Hash
Warning&lt;/strong&gt;. 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory2.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
Unfortunately SQL Server 2008 (R2) provides you no events through Extended Events
to track down those Memory Spills. In SQL Server 2012 this will change, and you will
have additional events available inside Extended Events for troubleshooting this problem.
In this posting I will illustrate you with a simple example how you can reproduce
a simple Query Memory Spill because of out-of-date statistics. Let's create a new
database and a simple test table inside it: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SET&lt;/span&gt; &lt;span style="color:blue"&gt;STATISTICS&lt;/span&gt; &lt;span style="color:blue"&gt;IO&lt;/span&gt; &lt;span style="color:blue"&gt;ON &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SET&lt;/span&gt; &lt;span style="color:blue"&gt;STATISTICS&lt;/span&gt; &lt;span style="color:blue"&gt;TIME&lt;/span&gt; &lt;span style="color:blue"&gt;ON &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Create a new
database &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;CREATE&lt;/span&gt; &lt;span style="color:blue"&gt;DATABASE&lt;/span&gt; InsufficientMemoryGrants &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SUE&lt;/span&gt; InsufficientMemoryGrants &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Create a test
table &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;CREATE&lt;/span&gt; &lt;span style="color:blue"&gt;TABLE&lt;/span&gt; TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:gray; font-family:Courier New; font-size:9pt"&gt;( &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; Col1 &lt;span style="color:blue"&gt;INT&lt;/span&gt; &lt;span style="color:blue"&gt;IDENTITY&lt;/span&gt; &lt;span style="color:blue"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:blue"&gt;KEY&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; Col2 &lt;span style="color:blue"&gt;INT&lt;span style="color:gray"&gt;, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt; Col3 &lt;span style="color:blue"&gt;CHAR&lt;span style="color:gray"&gt;(&lt;/span&gt;4000&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:gray; font-family:Courier New; font-size:9pt"&gt;) &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Create a Non-Clustered
Index on column Col2 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;CREATE&lt;/span&gt; &lt;span style="color:blue"&gt;NONCLUSTERED&lt;/span&gt; &lt;span style="color:blue"&gt;INDEX&lt;/span&gt; idxTable1_Column2 &lt;span style="color:blue"&gt;ON&lt;/span&gt; TestTable&lt;span style="color:gray"&gt;(&lt;/span&gt;Col2&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
The table &lt;strong&gt;TestTable&lt;/strong&gt; contains the primary key on the first column,
and the second column is indexed through a Non-Clustered Index. The third column is
a &lt;strong&gt;CHAR(4000)&lt;/strong&gt; column which isn't indexed. We will use that column
afterwards for an &lt;strong&gt;ORDER BY&lt;/strong&gt;, so that the Query Optimizer must generate
an explicit Sort Operator inside the Execution Plan. In the next step I'm just inserting
1500 records, where we have an even data distribution across all the values in the
second column – each value exists once in our table. 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory3.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
With that test data prepared we can now execute a simple query, which must use a separate
Sort operator in the Execution Plan: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;DECLARE&lt;/span&gt; @x &lt;span style="color:blue"&gt;INT &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; @x &lt;span style="color:gray"&gt;=&lt;/span&gt; Col2 &lt;span style="color:blue"&gt;FROM&lt;/span&gt; TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; Col2 &lt;span style="color:gray"&gt;=&lt;/span&gt; 2 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;ORDER&lt;/span&gt; &lt;span style="color:blue"&gt;BY&lt;/span&gt; Col3 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
This query uses the following Execution Plan: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory4.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
When you look into SQL Server Profiler and you have enabled the above mentioned events,
nothing happens. You can also use the DMV &lt;strong&gt;sys.dm_io_virtual_file_stats&lt;/strong&gt; and
the columns &lt;strong&gt;num_of_writes&lt;/strong&gt; and &lt;strong&gt;num_of_bytes_written&lt;/strong&gt; to
find out if there was some activity in TempDb for a given query. This works – of course
only – when you are the only person who currently uses the given SQL Server instance: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Check the activity
in TempDb before we execute the sort operation. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; num_of_writes&lt;span style="color:gray"&gt;,&lt;/span&gt; num_of_bytes_written &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_io_virtual_file_stats&lt;span style="color:gray"&gt;(&lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'tempdb'&lt;span style="color:gray"&gt;),&lt;/span&gt; 1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Select a record
through the previous created Non-Clustered Index from the table. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server retrieves
the record through a Non-Clustered Index Seek operator. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server estimates
for the sort operator 1 record, which also reflects &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- the actual number
of rows. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server requests
a memory grant of 1024kb - the sorting is done inside &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- the memory. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;DECLARE&lt;/span&gt; @x &lt;span style="color:blue"&gt;INT &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; @x &lt;span style="color:gray"&gt;=&lt;/span&gt; Col2 &lt;span style="color:blue"&gt;FROM&lt;/span&gt; TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; Col2 &lt;span style="color:gray"&gt;=&lt;/span&gt; 2 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;ORDER&lt;/span&gt; &lt;span style="color:blue"&gt;BY&lt;/span&gt; Col3 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Check the activity
in TempDb after the execution of the sort operation. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- There was no
activity in TempDb during the previous SELECT statement. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; num_of_writes&lt;span style="color:gray"&gt;,&lt;/span&gt; num_of_bytes_written &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_io_virtual_file_stats&lt;span style="color:gray"&gt;(&lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'tempdb'&lt;span style="color:gray"&gt;),&lt;/span&gt; 1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
Again you will see no activity in TempDb, which means the output from &lt;strong&gt;sys.dm_io_virtual_file_stats&lt;/strong&gt; is
the same before and after executing the query. The query takes on my system around
1ms of execution time. 
&lt;/p&gt;
&lt;p&gt;
Now we have a table with 1500 records, means that our table needs 20% + 500 rows of
data changes so that SQL Server will update the statistics. If you're doing the math,
we need 800 data modifications in that table (500 + 300). So let's just insert 799
additional rows where the value of the second column is 2. We are just changing the
data distribution and SQL Server WILL NOT update the statistics, because one additional
data change is still missing, until Update Statistics is triggered automatically inside
SQL Server! 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Insert 799 records
into table TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; &lt;span style="color:blue"&gt;TOP&lt;/span&gt; 799 &lt;span style="color:blue"&gt;IDENTITY&lt;span style="color:gray"&gt;(&lt;span style="color:blue"&gt;INT&lt;span style="color:gray"&gt;,&lt;/span&gt; 1&lt;span style="color:gray"&gt;,&lt;/span&gt; 1&lt;span style="color:gray"&gt;)&lt;/span&gt; AS&lt;/span&gt; n &lt;span style="color:blue"&gt;INTO&lt;/span&gt; #Nums&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;FROM &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;master&lt;span style="color:gray"&gt;.&lt;/span&gt;dbo&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;syscolumns&lt;/span&gt; sc1&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;INSERT&lt;/span&gt; &lt;span style="color:blue"&gt;INTO&lt;/span&gt; TestTable&lt;span style="color:blue"&gt; &lt;span style="color:gray"&gt;(&lt;/span&gt;Col2&lt;span style="color:gray"&gt;,&lt;/span&gt; Col3&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; 2&lt;span style="color:gray"&gt;,&lt;/span&gt; &lt;span style="color:fuchsia"&gt;REPLICATE&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'x'&lt;span style="color:gray"&gt;,&lt;/span&gt; 4&lt;/span&gt;000)&lt;/span&gt; &lt;span style="color:blue"&gt;FROM&lt;/span&gt; #nums&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;DROP&lt;/span&gt; &lt;span style="color:blue"&gt;TABLE&lt;/span&gt; #nums &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
When you now execute the same query again, SQL Server will now spill the Sort operation
to TempDb, because SQL Server will only request a Query Memory Grant of 1024 kilobytes,
which is estimated for just 1 record – the memory grant has the same size as before: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Check the activity
in TempDb before we execute the sort operation. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; num_of_writes&lt;span style="color:gray"&gt;,&lt;/span&gt; num_of_bytes_written &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_io_virtual_file_stats&lt;span style="color:gray"&gt;(&lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'tempdb'&lt;span style="color:gray"&gt;),&lt;/span&gt; 1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server estimates
now 1 record for the sort operation and requests a memory grant of 1.024kb for the
query. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- This is too less,
because actually we are sorting 800 rows! &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server has
to spill the sort operation into TempDb, which now becomes a physical I/O operation!!! &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;DECLARE&lt;/span&gt; @x &lt;span style="color:blue"&gt;INT &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; @x &lt;span style="color:gray"&gt;=&lt;/span&gt; Col2 &lt;span style="color:blue"&gt;FROM&lt;/span&gt; TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; Col2 &lt;span style="color:gray"&gt;=&lt;/span&gt; 2 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;ORDER&lt;/span&gt; &lt;span style="color:blue"&gt;BY&lt;/span&gt; Col3 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Check the activity
in TempDb after the execution of the sort operation. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- There is now
activity in TempDb during the previous SELECT statement. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; num_of_writes&lt;span style="color:gray"&gt;,&lt;/span&gt; num_of_bytes_written &lt;span style="color:blue"&gt;FROM &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_io_virtual_file_stats&lt;span style="color:gray"&gt;(&lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'tempdb'&lt;span style="color:gray"&gt;),&lt;/span&gt; 1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
If you check the &lt;strong&gt;Estimated Number of Rows&lt;/strong&gt; in the Execution Plan,
they are differing completely from the &lt;strong&gt;Actual Number of Rows&lt;/strong&gt;: 
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.sqlpassion.at/blog/content/binary/101911_2004_QueryMemory5.png" alt="" /&gt; 
&lt;/p&gt;
&lt;p&gt;
When you track the query execution time you will also see that the execution time
increased – in my case it increased up to 200ms, which is a huge difference to the
earlier execution time of just 1ms! The DMV &lt;strong&gt;sys.dm_io_virtual_file_stats&lt;/strong&gt; will
also report some activity inside TempDb, which is also the evidence that SQL Server
spilled the Sort operation into TempDb! SQL Server Profiler will also show you a Sort
Warning event. 
&lt;/p&gt;
&lt;p&gt;
If you now insert one additional record, and you run the query again, everything is
fine, because SQL Server will trigger the Statistics Update and estimate the Query
Memory Grant correctly: 
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Insert 1 records
into table TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; &lt;span style="color:blue"&gt;TOP&lt;/span&gt; 1 &lt;span style="color:blue"&gt;IDENTITY&lt;span style="color:gray"&gt;(&lt;span style="color:blue"&gt;INT&lt;span style="color:gray"&gt;,&lt;/span&gt; 1&lt;span style="color:gray"&gt;,&lt;/span&gt; 1&lt;span style="color:gray"&gt;)&lt;/span&gt; AS&lt;/span&gt; n &lt;span style="color:blue"&gt;INTO&lt;/span&gt; #Nums&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;FROM &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;master&lt;span style="color:gray"&gt;.&lt;/span&gt;dbo&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;syscolumns&lt;/span&gt; sc1&lt;/span&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;INSERT&lt;/span&gt; &lt;span style="color:blue"&gt;INTO&lt;/span&gt; TestTable&lt;span style="color:blue"&gt; &lt;span style="color:gray"&gt;(&lt;/span&gt;Col2&lt;span style="color:gray"&gt;,&lt;/span&gt; Col3&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; 2&lt;span style="color:gray"&gt;,&lt;/span&gt; &lt;span style="color:fuchsia"&gt;REPLICATE&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'x'&lt;span style="color:gray"&gt;,&lt;/span&gt; 2000&lt;span style="color:gray"&gt;)&lt;/span&gt; &lt;span style="color:blue"&gt;FROM&lt;/span&gt; #nums&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;DROP&lt;/span&gt; &lt;span style="color:blue"&gt;TABLE&lt;/span&gt; #nums &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Check the activity
in TempDb before we execute the sort operation. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; num_of_writes&lt;span style="color:gray"&gt;,&lt;/span&gt; num_of_bytes_written &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_io_virtual_file_stats&lt;span style="color:gray"&gt;(&lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'tempdb'&lt;span style="color:gray"&gt;),&lt;/span&gt; 1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server has
now accurate statistics and estimates 801 rows for the sort operator. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server requests
a memory grant of 6.656kb, which is now enough. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- SQL Server now
spills the sort operation not to TempDb. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Logical reads:
577 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;DECLARE&lt;/span&gt; @x &lt;span style="color:blue"&gt;INT &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; @x &lt;span style="color:gray"&gt;=&lt;/span&gt; Col2 &lt;span style="color:blue"&gt;FROM&lt;/span&gt; TestTable &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;WHERE&lt;/span&gt; Col2 &lt;span style="color:gray"&gt;=&lt;/span&gt; 2 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;ORDER&lt;/span&gt; &lt;span style="color:blue"&gt;BY&lt;/span&gt; Col3 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- Check the activity
in TempDb after the execution of the sort operation. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:green; font-family:Courier New; font-size:9pt"&gt;-- There is now
no activity in TempDb during the previous SELECT statement. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Courier New; font-size:9pt"&gt;&lt;span style="color:blue"&gt;SELECT&lt;/span&gt; num_of_writes&lt;span style="color:gray"&gt;,&lt;/span&gt; num_of_bytes_written &lt;span style="color:blue"&gt;FROM&lt;/span&gt; &lt;span style="color:green"&gt;sys&lt;span style="color:gray"&gt;.&lt;span style="color:green"&gt;dm_io_virtual_file_stats&lt;span style="color:gray"&gt;(&lt;span style="color:fuchsia"&gt;DB_ID&lt;span style="color:gray"&gt;(&lt;span style="color:red"&gt;'tempdb'&lt;span style="color:gray"&gt;),&lt;/span&gt; 1&lt;span style="color:gray"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:blue; font-family:Courier New; font-size:9pt"&gt;GO&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
So this is a very basic example which shows you how you can reproduce Sort Warnings
inside SQL Server – not really a magic. Adam Machanic (&lt;a href="http://sqlblog.com/blogs/adam_machanic"&gt;http://sqlblog.com/blogs/adam_machanic&lt;/a&gt;)
has done last week at the SQLPASS Summit in Seattle a whole session about Query Memory
at a 500 level, where he went into more details on this complicated topic, especially
in combination with Parallel Execution Plans. 
&lt;/p&gt;
&lt;p&gt;
Thanks for reading! 
&lt;/p&gt;
&lt;p&gt;
-Klaus
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=2a24830a-5cf9-4438-96e9-af0a6d7372c3" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,2a24830a-5cf9-4438-96e9-af0a6d7372c3.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=7f935d74-c00d-4506-8290-9c813f874b7a</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,7f935d74-c00d-4506-8290-9c813f874b7a.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,7f935d74-c00d-4506-8290-9c813f874b7a.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=7f935d74-c00d-4506-8290-9c813f874b7a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
As I have announced in my "Advanced SQL Server Troubleshooting" session at SQLPASS
today, you can find <a href="http://sqlpassion.at/downloads/sqlpass2011.zip">here</a> the
slides &amp; samples for download. Thanks for attending my session <span style="font-family:Wingdings">J</span></p>
        <p>
-Klaus
</p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=7f935d74-c00d-4506-8290-9c813f874b7a" />
      </body>
      <title>Slides &amp; Samples for my Advanced SQL Server Troubleshooting session at SQLPASS</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,7f935d74-c00d-4506-8290-9c813f874b7a.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,7f935d74-c00d-4506-8290-9c813f874b7a.aspx</link>
      <pubDate>Fri, 14 Oct 2011 05:23:04 GMT</pubDate>
      <description>&lt;p&gt;
As I have announced in my "Advanced SQL Server Troubleshooting" session at SQLPASS
today, you can find &lt;a href="http://sqlpassion.at/downloads/sqlpass2011.zip"&gt;here&lt;/a&gt; the
slides &amp;amp; samples for download. Thanks for attending my session &lt;span style="font-family:Wingdings"&gt;J&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
-Klaus
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=7f935d74-c00d-4506-8290-9c813f874b7a" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,7f935d74-c00d-4506-8290-9c813f874b7a.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=b00dd027-173d-43e0-9465-c08a3e03ff1a</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,b00dd027-173d-43e0-9465-c08a3e03ff1a.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,b00dd027-173d-43e0-9465-c08a3e03ff1a.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b00dd027-173d-43e0-9465-c08a3e03ff1a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <span style="color:black; font-family:Verdana; font-size:10pt">Sie wollen SQL Server
Abfragen um 100% oder gar 1000% beschleunigt haben? Gleichzeitig wollen Sie Hardware–
und Lizenzkosten Ihrer SQL Server Anwendungen und deren Infrastruktur senken? Ein
Wunschdenken? - Keineswegs! </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:black; font-family:Verdana; font-size:10pt">Mit einer gut indizierten
SQL Server Datenbank können Sie Geschwindigkeitsvorteile von mehreren 100% für bestimmte
Abfragen gewinnen. Als positiven Seiteneffekt senken Sie die Hardwareanforderungen
an Ihre SQL Server Infrastruktur und dadurch direkt die Hardware– und Lizenzkosten,
die für SQL Server Installation anfallen. </span>
        </p>
        <p>
        </p>
        <p>
          <span style="color:black; font-family:Verdana; font-size:10pt">Am 18. Jänner 2012
ist es endlich soweit: </span>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">Klaus Aschenbrenner – unabhängigier
SQL Server Experte und internationaler Konferenzsprecher – führt den <strong>SQL Server
Indexing Day</strong> in Wien durch. </span>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">In 1 intensiven Tag vermittelt Ihnen
Klaus Aschenbrenner das notwendige Know-How, um Indizes im SQL Server effektiv einsetzen
zu können – wie oben genannt – Performance Optimierungen von mehreren 100% durchführen
zu können. </span>
        </p>
        <p>
          <span style="color:black; font-family:Verdana; font-size:10pt">In diesem intensiven
Workshop-Tag werden Sie im ersten Schritt den Aufbau von SQL Server Datenbanken und
der verschiedenen zur Verfügung stehenden Indizes näher kennenlernen. Aufbauend auf
diesem Wissen werden Sie eine Reihe von unterschiedlichen Performance Tuning Techniken
näher kennenlernen, die Sie durch den Einsatz des jeweiligen Indexes einsetzen können.
Abgerundet wird der Tag mit einem Ausblick auf die Index-Wartung, und über welche
Fallstricke Sie hier in Produktionsumgebungen stolpern können. </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">
            <strong>Inhalte: </strong>
          </span>
        </p>
        <ul>
          <li>
            <div>
              <span style="font-family:Verdana; font-size:10pt">SQL Server 2008 Database Internals </span>
            </div>
            <ul>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Database Structure </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Table Metadata </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Data Page Details </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Record Storage </span>
              </li>
            </ul>
          </li>
          <li>
            <div>
              <span style="font-family:Verdana; font-size:10pt">Index Architecture </span>
            </div>
            <ul>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Architecture </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Structures </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Clustered vs. Non-Clustered Indexes </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Dependencies </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Clustered Key Problems </span>
              </li>
            </ul>
          </li>
          <li>
            <div>
              <span style="font-family:Verdana; font-size:10pt">Index Tuning </span>
            </div>
            <ul>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Search Arguments </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Access Methods </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Covering Index </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Tipping Point </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Intersection </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Filtered Indexes </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Indexed Views </span>
              </li>
            </ul>
          </li>
          <li>
            <div>
              <span style="font-family:Verdana; font-size:10pt">Index Maintenance </span>
            </div>
            <ul>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Statistics </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Fragmentation </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Rebuild </span>
              </li>
              <li>
                <span style="font-family:Verdana; font-size:10pt">Index Reorganize </span>
              </li>
            </ul>
          </li>
        </ul>
        <p>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">Weitere Informationen zum Event
können Sie sich unter <a href="http://SQLpassion.at/Events.html">http://SQLpassion.at/Events.html</a> ansehen,
bzw. können Sie den dazugehörigen Folder unter <a href="http://SQLPassion.at/IndexingDay.pdf">http://SQLPassion.at/IndexingDay.pdf</a> herunterladen. </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">
            <strong>Veranstaltungsort: </strong>
          </span>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">Hotel &amp; Palais Strudlhof </span>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">Pasteurgasse 1 </span>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">A-1090 Wien </span>
        </p>
        <p>
          <a href="http://www.strudlhof.at">
            <span style="font-family:Verdana; font-size:10pt">http://www.strudlhof.at</span>
          </a>
          <span style="font-family:Verdana; font-size:10pt">
          </span>
        </p>
        <p>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">
            <strong>Inkludierte Leistungen: </strong>
          </span>
        </p>
        <ul>
          <li>
            <span style="font-family:Verdana; font-size:10pt">Workshop von 09:00 - 17:00 </span>
          </li>
          <li>
            <span style="font-family:Verdana; font-size:10pt">2 Kaffeepausen (Vormittag, Nachmittag) </span>
          </li>
          <li>
            <span style="font-family:Verdana; font-size:10pt">Gemeinsames Mittagessen </span>
          </li>
          <li>
            <div style="text-align: justify">
              <span style="font-family:Verdana; font-size:10pt">Early-Bird
Preis bis zum 31.10.2011: € 349,00 exkl Ust. </span>
            </div>
          </li>
          <li>
            <div style="text-align: justify">
              <span style="font-family:Verdana; font-size:10pt">Danach:
€ 399,00 exkl Ust. </span>
            </div>
          </li>
        </ul>
        <p>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">
            <strong>Anmeldung: </strong>
          </span>
        </p>
        <ul>
          <li>
            <span style="font-family:Verdana; font-size:10pt">Anmeldungen werden unter <a href="http://SQLpassion.at/Events.html">http://SQLpassion.at/Events.html</a> entgegengenommen. </span>
          </li>
          <li>
            <span style="font-family:Verdana; font-size:10pt">Ausgestellte Rechungen müssen bis
zum Beginn der Veranstaltung einbezahlt werden, damit eine Teilnahme an der Veranstaltung
gewährleistet werden kann. </span>
          </li>
        </ul>
        <p>
        </p>
        <p>
          <span style="font-family:Verdana; font-size:10pt">-Klaus</span>
        </p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=b00dd027-173d-43e0-9465-c08a3e03ff1a" />
      </body>
      <title>SQL Server Indexing Day, 18. Jänner 2012 in Wien</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,b00dd027-173d-43e0-9465-c08a3e03ff1a.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,b00dd027-173d-43e0-9465-c08a3e03ff1a.aspx</link>
      <pubDate>Tue, 04 Oct 2011 19:19:56 GMT</pubDate>
      <description>&lt;p&gt;
&lt;span style="color:black; font-family:Verdana; font-size:10pt"&gt;Sie wollen SQL Server
Abfragen um 100% oder gar 1000% beschleunigt haben? Gleichzeitig wollen Sie Hardware–
und Lizenzkosten Ihrer SQL Server Anwendungen und deren Infrastruktur senken? Ein
Wunschdenken? - Keineswegs! &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black; font-family:Verdana; font-size:10pt"&gt;Mit einer gut indizierten
SQL Server Datenbank können Sie Geschwindigkeitsvorteile von mehreren 100% für bestimmte
Abfragen gewinnen. Als positiven Seiteneffekt senken Sie die Hardwareanforderungen
an Ihre SQL Server Infrastruktur und dadurch direkt die Hardware– und Lizenzkosten,
die für SQL Server Installation anfallen. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black; font-family:Verdana; font-size:10pt"&gt;Am 18. Jänner 2012
ist es endlich soweit: &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Klaus Aschenbrenner – unabhängigier
SQL Server Experte und internationaler Konferenzsprecher – führt den &lt;strong&gt;SQL Server
Indexing Day&lt;/strong&gt; in Wien durch. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;In 1 intensiven Tag vermittelt Ihnen
Klaus Aschenbrenner das notwendige Know-How, um Indizes im SQL Server effektiv einsetzen
zu können – wie oben genannt – Performance Optimierungen von mehreren 100% durchführen
zu können. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black; font-family:Verdana; font-size:10pt"&gt;In diesem intensiven
Workshop-Tag werden Sie im ersten Schritt den Aufbau von SQL Server Datenbanken und
der verschiedenen zur Verfügung stehenden Indizes näher kennenlernen. Aufbauend auf
diesem Wissen werden Sie eine Reihe von unterschiedlichen Performance Tuning Techniken
näher kennenlernen, die Sie durch den Einsatz des jeweiligen Indexes einsetzen können.
Abgerundet wird der Tag mit einem Ausblick auf die Index-Wartung, und über welche
Fallstricke Sie hier in Produktionsumgebungen stolpern können. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;&lt;strong&gt;Inhalte: &lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;SQL Server 2008 Database Internals &lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Database Structure &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Table Metadata &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Data Page Details &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Record Storage &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Architecture &lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Architecture &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Structures &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Clustered vs. Non-Clustered Indexes &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Dependencies &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Clustered Key Problems &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Tuning &lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Search Arguments &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Access Methods &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Covering Index &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Tipping Point &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Intersection &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Filtered Indexes &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Indexed Views &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Maintenance &lt;/span&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Statistics &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Fragmentation &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Rebuild &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Index Reorganize &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Weitere Informationen zum Event
können Sie sich unter &lt;a href="http://SQLpassion.at/Events.html"&gt;http://SQLpassion.at/Events.html&lt;/a&gt; ansehen,
bzw. können Sie den dazugehörigen Folder unter &lt;a href="http://SQLPassion.at/IndexingDay.pdf"&gt;http://SQLPassion.at/IndexingDay.pdf&lt;/a&gt; herunterladen. &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;&lt;strong&gt;Veranstaltungsort: &lt;/strong&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Hotel &amp;amp; Palais Strudlhof &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Pasteurgasse 1 &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;A-1090 Wien &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.strudlhof.at"&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;http://www.strudlhof.at&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;&lt;strong&gt;Inkludierte Leistungen: &lt;/strong&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Workshop von 09:00 - 17:00 &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;2 Kaffeepausen (Vormittag, Nachmittag) &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Gemeinsames Mittagessen &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div style="text-align: justify"&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;Early-Bird
Preis bis zum 31.10.2011: € 349,00 exkl Ust. &lt;/span&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div style="text-align: justify"&gt;&lt;span style="font-family:Verdana; font-size:10pt"&gt;Danach:
€ 399,00 exkl Ust. &lt;/span&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;&lt;strong&gt;Anmeldung: &lt;/strong&gt; &lt;/span&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Anmeldungen werden unter &lt;a href="http://SQLpassion.at/Events.html"&gt;http://SQLpassion.at/Events.html&lt;/a&gt; entgegengenommen. &lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;Ausgestellte Rechungen müssen bis
zum Beginn der Veranstaltung einbezahlt werden, damit eine Teilnahme an der Veranstaltung
gewährleistet werden kann. &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="font-family:Verdana; font-size:10pt"&gt;-Klaus&lt;/span&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=b00dd027-173d-43e0-9465-c08a3e03ff1a" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,b00dd027-173d-43e0-9465-c08a3e03ff1a.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
    </item>
    <item>
      <trackback:ping>http://www.sqlpassion.at/blog/Trackback.aspx?guid=616d9dcf-409b-4444-8ddd-d69740ccef97</trackback:ping>
      <pingback:server>http://www.sqlpassion.at/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.sqlpassion.at/blog/PermaLink,guid,616d9dcf-409b-4444-8ddd-d69740ccef97.aspx</pingback:target>
      <dc:creator>Klaus Aschenbrenner</dc:creator>
      <wfw:comment>http://www.sqlpassion.at/blog/CommentView,guid,616d9dcf-409b-4444-8ddd-d69740ccef97.aspx</wfw:comment>
      <wfw:commentRss>http://www.sqlpassion.at/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=616d9dcf-409b-4444-8ddd-d69740ccef97</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <span style="color:black; font-size:8pt">
            <span style="font-family:Verdana; background-color:white">As
I have announced in all of my sessions at the SQLbits conferences in Liverpool/UK,
you can find <a href="http://www.csharp.at/Downloads/SQLbits2011Liverpool.zip">here</a> the
Slides &amp; Samples for download. Enjoy it and thanks for attending my sessions. </span>
            <span style="font-family:Wingdings; background-color:white">J</span>
            <span style="font-family:Verdana; background-color:white">
            </span>
          </span>
        </p>
        <p>
          <span style="color:black; font-family:Verdana; font-size:8pt; background-color:white">-Klaus</span>
        </p>
        <img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=616d9dcf-409b-4444-8ddd-d69740ccef97" />
      </body>
      <title>Slides &amp; Samples from my SQLbits sessions</title>
      <guid isPermaLink="false">http://www.sqlpassion.at/blog/PermaLink,guid,616d9dcf-409b-4444-8ddd-d69740ccef97.aspx</guid>
      <link>http://www.sqlpassion.at/blog/PermaLink,guid,616d9dcf-409b-4444-8ddd-d69740ccef97.aspx</link>
      <pubDate>Sun, 02 Oct 2011 18:12:18 GMT</pubDate>
      <description>&lt;p&gt;
&lt;span style="color:black; font-size:8pt"&gt;&lt;span style="font-family:Verdana; background-color:white"&gt;As
I have announced in all of my sessions at the SQLbits conferences in Liverpool/UK,
you can find &lt;a href="http://www.csharp.at/Downloads/SQLbits2011Liverpool.zip"&gt;here&lt;/a&gt; the
Slides &amp;amp; Samples for download. Enjoy it and thanks for attending my sessions. &lt;/span&gt;&lt;span style="font-family:Wingdings; background-color:white"&gt;J&lt;/span&gt;&lt;span style="font-family:Verdana; background-color:white"&gt; &lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;span style="color:black; font-family:Verdana; font-size:8pt; background-color:white"&gt;-Klaus&lt;/span&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.sqlpassion.at/blog/aggbug.ashx?id=616d9dcf-409b-4444-8ddd-d69740ccef97" /&gt;</description>
      <comments>http://www.sqlpassion.at/blog/CommentView,guid,616d9dcf-409b-4444-8ddd-d69740ccef97.aspx</comments>
      <category>.NET German</category>
      <category>Conferences</category>
      <category>SQLServer</category>
      <category>SQLServerPedia</category>
    </item>
  </channel>
</rss>
