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

<channel>
	<title>Era of Data Limited</title>
	<atom:link href="http://www.eraofdata.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.eraofdata.com</link>
	<description>SQL Server specialists</description>
	<lastBuildDate>Tue, 21 May 2013 20:40:34 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Tracking SQL Server IO performance</title>
		<link>http://www.eraofdata.com/tracking-sql-server-io-performance/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=tracking-sql-server-io-performance</link>
		<comments>http://www.eraofdata.com/tracking-sql-server-io-performance/#comments</comments>
		<pubDate>Thu, 16 May 2013 20:06:32 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/?p=600</guid>
		<description><![CDATA[I&#8217;ve finally got around to this, the third part of my SQL Server and Disk IO series of posts: The sys.dm_io_virtual_file_stats DMV and fn_virtualfilestats function are great tools for extracting granular information about the IO performance of your database(s), right down to &#8230; <a href="http://www.eraofdata.com/tracking-sql-server-io-performance/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve finally got around to this, the third part of my <a title="SQL Server and Disk IO" href="http://www.eraofdata.com/sql-server-and-disk-io/" target="_blank">SQL Server and Disk IO</a> series of posts:<a href="http://www.eraofdata.com/tracking-sql-server-io-performance/"><br />
</a></p>
<p>The sys.dm_io_virtual_file_stats DMV and fn_virtualfilestats function are great tools for extracting granular information about the IO performance of your database(s), right down to the individual file in each database.</p>
<p>It gives details of the number of physical reads/writes, amount of data read/written and how much was spent reading/writing that data. Traditionally, this has been important because IO access is the slowest part of fulfilling any database queries as RAM and CPU access takes nanoseconds or microseconds, whereas typically access to a spinning disk takes several milliseconds. In other words, disk access is thousands of times slower than CPU or RAM access, so improving disk access performance often brings about the biggest bang for the buck, in a manner of speaking.</p>
<p>Lately, with the uptake of SSDs increasing this is starting to become less of an issue, but if like me, some of the systems you administer are still using the ancient technology of spinning disks then getting familiar with this view will help you confirm any IO issues. Incidentally, the forerunner of this DMV was fn_virtualfilestats and goes back to (at least) SQL Server 2000 and still works in the latest SQL Server version (SQL Server 2012, as of writing this post) so this post concentrates on the fn_virtualfilestats function.</p>
<p>I won&#8217;t bore you with details of how to query the function as it is already <a href="http://msdn.microsoft.com/en-GB/library/ms187309.aspx" target="_blank">well documented</a>, and my own query which utilises it is below:</p>
<pre>;WITH sum_table
AS
(
SELECT [dbid]
, [fileid]
, [numberreads]
, [iostallreadms]
, [numberwrites]
, [iostallwritems]
, [bytesread]
, [byteswritten]
, [iostallms]
, [numberreads] + [numberwrites] AS [total_io] FROM :: fn_virtualfilestats(db_id(), null) vf
inner join sys.databASe_files df
on vf.[fileid] = df.[file_id]
where df.[type] &lt;&gt; 1
)
SELECT db_name([dbid]) AS db
, file_name([fileid]) AS [file]
, CASE [numberreads]
WHEN 0 THEN 0
ELSE CAST(ROUND([iostallreadms]/([numberreads] * 1.0), 2) AS NUMERIC(5,2)) END AS [read_latency_ms]
, CASE [numberwrites]
WHEN 0 THEN 0
ELSE CAST (ROUND([iostallwritems]/([numberwrites] * 1.0), 2) AS NUMERIC(5,2)) END AS [write_latency_ms]
, [numberreads] AS [#reads]
, [numberwrites] AS [#writes]
, [total_io]
, CAST (ROUND(([bytesread]/1073741824.0),2) AS NUMERIC (12,2)) AS [gb read]
, CAST (ROUND(([byteswritten]/1073741824.0),2) AS NUMERIC (12,2)) AS [gb written]
, [iostallms] AS [#stalled io]
, CAST (ROUND((([numberreads] * 1.0 ) /[total_io]) * 100,3) AS NUMERIC (6,3)) AS [file_read_pct]
, CAST (ROUND((([numberwrites] * 1.0 ) /[total_io]) * 100,3) AS NUMERIC (6,3)) AS [file_write_pct]
, CAST (ROUND((([numberreads] * 1.0) /(SELECT sum(total_io) FROM sum_table)) * 100,3) AS NUMERIC (6,3)) AS [tot_read_pct_ratio]
, CAST (ROUND(((numberwrites * 1.0) /(SELECT sum(total_io) FROM sum_table)) * 100,3) AS NUMERIC (6,3)) AS [tot_write_pct_ratio]
, CAST (ROUND((([total_io] * 1.0) /(SELECT sum(total_io) FROM sum_table)) * 100,3) AS NUMERIC (6,3)) AS [tot_io_pct_ratio]
, (SELECT CONVERT(NUMERIC(10,2),DATEDIFF(MI, sqlserver_start_time, GETUTCDATE()) / 1440.0) from sys.dm_os_sys_info) as [uptime_days]
FROM sum_table
GROUP BY [dbid], [fileid], [total_io], [numberreads], [iostallreadms], [numberwrites], [iostallwritems], [bytesread], [byteswritten], [iostallms]
ORDER BY [total_io] desc
GO</pre>
<p>I&#8217;ve chosen to use the <code>fn_virtualfilestats</code> function instead of the <code>sys.dm_io_virtual_file_stats</code> DMV so it should still work right back to SQL Server 2000. The main difference between this query and others I&#8217;ve found on the blogosphere is that it excludes the log file (because on an OLTP system it will get hammered and generate a lot of IO anyway), and once I&#8217;ve excluded the log file being an issue (usually from <a title="SQL Server wait stats" href="http://www.eraofdata.com/sql-server-wait-stats/">wait stats</a> and System Monitor (perfmon) data) I&#8217;m usually more interested in how busy my data files are, and if there are any hotspots and it does this by aggregating the IO data and returning the percentage of IO that not only each file does, but the actual ratio of IO that each file does relative to the total IO against <em>all</em> data files within that database. Mike Lewis has tweaked the query so it scans all databases (see the first comment on this post below).</p>
<p>Automating the collection of this data provides a great way of baselining performance and spotting trends (hint hint). The <code>uptime_days</code> column shows how many days the server has been running so you can work out the average daily read/write IO.</p>
<p>If you want information regarding log file performance, simply comment out the<br />
<code>where df.[type] &lt;&gt; 1</code> line.</p>
<p>It&#8217;s been tested in battle and I&#8217;ve found it invaluable for highlighting high contention filegroups and IO subsystem issues. A word of caution, before looking at the output and pointing the finger at the disks/SAN it&#8217;s always worth digging behind the stats. If high latencies/reads are found, the issue can boil down to database design which can be uncovered by investigating the reason for the high number of reads/writes on the relevant filegroup(s), e.g. a lack of indexing on a highly read table will result in a lot of table scans which can account for a substantial amount of IO on the file/filegroup holding that table and adding a well chosen index or two can eliminate the scans, reducing the IO and (hopefully) the latency. If the IO goes down, but the latency does not, you have more ammunition for looking more closely at the IO subsystem provided that factors like, for example, anti-virus filter drivers etc have been investigated. Recently, the output highlighted the slow performance of one particular file in an 18 file database which showed latencies of 89ms. After some digging around I found that this particular file was the primary file and (taking an educated guess) probably had default autogrowth settings when it was originally created, and has probably gone through some shrinkfile operations in a previous life, because this one 120GB file was spread over 4,818 physical fragments on the SAN. Once this was addressed the latency went down to 25ms. Whilst 25ms is not brilliant in itself it&#8217;s still a 70% improvement on its previous performance (and I know there&#8217;s room for further improvement as the partition it&#8217;s on has an sub-optimal allocation unit size, for some strange reason). IMHO physical file fragmentation, even on SANs is a big issue and I&#8217;ll be blogging about that particular issue in an upcoming post.</p>
<p>As I was saying, it pays to do a little digging around behind the numbers before jumping to the most obvious conclusion.</p>
<p>I know there are dozens of variations of queries out there that interrogate <code>fn_virtualfilestats</code> or <code>sys.dm_io_virtual_file_stats</code> but the reason I came up with yet another variation was that, for me, the relativity was difficult to ascertain; on a system that&#8217;s been running for while the IO numbers can be vast and on a system with a lot of data files it can be difficult to spot the troublesome files/filegroups, hence the addition of percentages and percentage ratios. Another inspiration was the Performance Dashboard Reports (which don&#8217;t work on SQL Server 2008 R2 out of the box but I hear that they can be ported back to SQL Server 2008R2 from SQL Server 2012, or you can try <a href="http://blogs.technet.com/b/rob/archive/2009/02/18/performance-dashboard-reports-for-sql-server-2008.aspx" target="_blank">this fix</a>) which do offer percentages for IO, but also includes the IO on the log files which can make it difficult to get a clear picture of IO that was exclusively related to data files.</p>
<p>The main reason for this post was to highlight the presence and significance of this DMV and also to point out that it should not be used in isolation. Other methods for gathering performance related data, like perfmon and <a title="SQL Server wait stats" href="http://www.eraofdata.com/sql-server-wait-stats/">wait stats</a> data are invaluable and all this information combined, together with corroborating evidence like e.g. slow IO warnings in the SQL Server error log will give a more rounded picture of IO performance.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/tracking-sql-server-io-performance/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Impact of Fusion IO based tempdb on reindex duration</title>
		<link>http://www.eraofdata.com/impact-of-fusion-io-based-tempdb-on-reindex-duration/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=impact-of-fusion-io-based-tempdb-on-reindex-duration</link>
		<comments>http://www.eraofdata.com/impact-of-fusion-io-based-tempdb-on-reindex-duration/#comments</comments>
		<pubDate>Mon, 11 Mar 2013 16:01:13 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[fusion io]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[reindexing]]></category>
		<category><![CDATA[tempdb]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/?p=517</guid>
		<description><![CDATA[Do you have tempdb on Fusion IO (or equivalent) technology? Is your reindexing job left on default settings (re-orgs at 5-15% and full rebuilds at @ 30%)? If so, then you might be interested in the findings in this post. &#8230; <a href="http://www.eraofdata.com/impact-of-fusion-io-based-tempdb-on-reindex-duration/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Do you have tempdb on Fusion IO (or equivalent) technology? Is your reindexing job left on default settings (re-orgs at 5-15% and full rebuilds at @ 30%)? If so, then you might be interested in the findings in this post.</p>
<p>The benefits of flash memory as a replacement for spinning drives in order to boost SQL Server performance is well documented. However, I&#8217;m not sure if one particular benefit has been fully exploited. This post covers how we reduced the average duration of our overnight reindex job by 80% with the help of just one Fusion IO card (per node).</p>
<p>A bit of background: in order to give a creaking and <em>very </em>tempdb heavy SQL Server 2008 R2 system a bit of a lift we shifted tempdb onto Fusion IO cards. The system consists of a  2-node cluster running on a SAN. We did indeed see throughput increase, as well as an improvement in concurrency (as we switched on snapshot isolation as well) but some 2 months after the cards were installed another benefit has come to light which has turned perceived wisdom of reorganising versus rebuilding indexes on its head (disclaimer: for our system running on our hardware, at any rate).</p>
<p>I&#8217;ve been DBA-ing for so long now that the good old 5%/30% general advice for reorganising as opposed to rebuilding an index as documented on <a title="Reorganize and Rebuild Indexes" href="http://technet.microsoft.com/en-us/library/ms189858.aspx" target="_blank">BOL</a> is so deeply ingrained that I&#8217;ve hardly given it a second thought and just followed it automatically, only tweaking it when performance analysis showed an issue with these thresholds. For more background info on these thresholds I strongly advise reading <a href="http://www.sqlskills.com/blogs/paul/where-do-the-books-online-index-fragmentation-thresholds-come-from/" target="_blank">Paul Randal&#8217;s post</a> on where these guidelines came from.</p>
<p>With tempdb on a much faster IO subsystem than the application database the SORT_IN_TEMPDB option for the <a title="ALTER INDEX command" href="http://msdn.microsoft.com/en-us/library/ms188388.aspx" target="_blank">ALTER INDEX</a> command suddenly comes into play. After installing the Fusions I tweaked our reindex job to turn the SORT_IN_TEMPDB  option on, made a mental note to follow this up in a few days time, and promptly forgot about it until several weeks later when I wanted to track down indexes that were getting highly fragmented (we use Ola Hallengren&#8217;s excellent <a title="Ola's maintenance script" href="http://ola.hallengren.com/" target="_blank">maintenance script</a> which logs this kind of information (and more) in a table) and noticed some  indexes had huge variations in the time taken to reindex them, with a full rebuild taking a fraction of the time a reorg did, and that&#8217;s when the penny dropped.</p>
<h2>The Fusion IO boost</h2>
<p>I promptly turned off reorgs so now it rebuilds at 10% with every index typically getting fully rebuilt in under 5 minutes (multiple indexes are between 10-14 GB in size). Needless to say, this has had a massive impact on the total reindex time. The reindex job on this system used to take anywhere between 4 to 9 hours which was a real problem as this would often encroach well into the business day.<br />
Since we switched off the reorgs, the reindex has never taken more then 2 hours (and the longest run at 114 minutes included 45 minutes of blocking). The graph below shows the performance improvement very er&#8230;graphically:</p>
<div id="attachment_556" class="wp-caption aligncenter" style="width: 815px"><a href="http://www.eraofdata.com/wp-content/uploads/2013/03/reindexingPerf.gif"><img class=" wp-image-556   " title="Reindexing duration decrease" alt="reindexingPerf" src="http://www.eraofdata.com/wp-content/uploads/2013/03/reindexingPerf.gif" width="805" height="378" /></a><p class="wp-caption-text">Fig. 1: Reindexing duration decrease</p></div>
<p>Purdy, ain&#8217;t it? As we can see, February 16th was the first night the reindex job used the rebuild option in place of reorgs, and the drop off in the run time could not be more dramatic. For the two weeks from 1st February &#8211; 14th February (inclusive) the average duration was 361 minutes, or 6 hours. After the SORT_IN_TEMPDB tweak on the 16th, the average (from the 16th up until today (March 11th) has been just 78 minutes.<br />
Incidentally, the Fusion IO cards in question are 785GB ioDrive2 Mono MLC PCIe Solid State Storage Cards, and yes, technically MS don&#8217;t support this tempdb configuration on a pre SQL 2012 cluster, but lots of people are doing it.</p>
<h2>The benefits</h2>
<p>For us, modifying the reindex job to drop the reorgs in favour of rebuilds on this particular system was a no-brainer. The reindexing finishing in a quarter of the time taken previously on a consistent basis every night has eliminated the uncertainty and inconvenience caused when the original approach caused the index to collide with subsequent maintenance jobs or encroach into the working day of the system.<br />
Furthermore, the database was in simple recovery so we didn&#8217;t have to worry about transaction log backups (although a reorg can have a greater impact on transaction log backups).</p>
<p>This is either a benefit that&#8217;s so obvious that no-one has bothered blogging about it, or it&#8217;s something that&#8217;s gone under the radar thus far (I&#8217;m obviously hoping it&#8217;s the latter). I&#8217;ve seen posts hint at it by mentioning index creation is faster etc, and I&#8217;ve even read a MS whitepaper analysing tempdb on Fusion IO on a SQL 2008R2 system (which did a reindexing test with the SORT_IN_TEMPB option on, but left the reindexing thresholds on defaults) but no-one, as far as I can tell, has gone the whole hog with regard to adapting their approach to reindexing and just rebuilding indexes in favour of the reorg option to fully exploit their investment in Fusion IO cards (or they just kept quiet about it, whereas I couldn&#8217;t help blabbing about it!); I can think of a number of scenarios and previous systems where the improvement in reindex job performance alone would justify this investment.</p>
<h2>Are reorgs redundant?</h2>
<p>If you have your tempdb on Fusion IO or similar technology, with the application database(s) on a slower IO subsystem with the reindexing strategy left on original settings its an option well worth exploring. </p>
<p>The things to look out for are the bandwidth from host to SAN as on this system we do briefly get close to maxing it out during the reindex now as it reads in the index pages and writes out the rebuilt index. Personally, I&#8217;d rather fully exploit our infrastructure than have it burbling along at the fraction of its capacity, which is what it used to be like when the most of the indexes were being reorganised.</p>
<p>Another consideration is the latency and throughput difference between the storage subsystem the application dbs are stored on and the Fusion IO cards; against spinning disk SAN based systems there&#8217;s no competition, the Fusion IOs will outperfrom the SAN in every category, but if you have e.g. SSDs already in the SAN the difference may not be that substantial, so the switch may not bring about such a dramatic boost. On this particular system, in our environment, there was a huge disparity between SAN performance and the Fusions which has made the switch so beneficial for us.</p>
<p>If alternative HA strategies like log-shopping have been implemented the impact will have to be measured as the costs may outweigh the benefits (thanks Paul!).</p>
<p>A final thing to bear in mind is that if you are fortunate enough to have some older/smaller Fusions lying around (perhaps you&#8217;ve had to swap them out as the application dbs have got bigger) it&#8217;s a great way of recycling these cards on other systems to give them a new lease of life.</p>
<p>So are reorgs redundant? If you have access to this kind of technology, it&#8217;s easy enough to prove on your system.</p>
<h2>In summary</h2>
<p>&#8220;It depends&#8221;, and &#8220;your mileage may vary&#8221; have become well worn cliches, but they are so true. Every system is different and there are a number of factors to consider, as (I hope) the post outlines, but the potential benefits warrant exploring this if you have not already done so.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/impact-of-fusion-io-based-tempdb-on-reindex-duration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A simple way to get the default SQL Server data and log path (finally!)</title>
		<link>http://www.eraofdata.com/a-simple-way-to-get-the-default-sql-server-data-and-log-path-finally/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-simple-way-to-get-the-default-sql-server-data-and-log-path-finally</link>
		<comments>http://www.eraofdata.com/a-simple-way-to-get-the-default-sql-server-data-and-log-path-finally/#comments</comments>
		<pubDate>Mon, 04 Mar 2013 13:38:58 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[data file path]]></category>
		<category><![CDATA[defaults]]></category>
		<category><![CDATA[log file path]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/?p=534</guid>
		<description><![CDATA[For things like automated SQL Server build scripts (and probably many other reasons) finding the root data and log file paths is essential. Prior to SQL Server 2012 there were all sorts of options ranging from e.g. running sp_helpfile against &#8230; <a href="http://www.eraofdata.com/a-simple-way-to-get-the-default-sql-server-data-and-log-path-finally/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>For things like automated SQL Server build scripts (and probably many other reasons) finding the root data and log file paths is essential.<br />
Prior to SQL Server 2012 there were all sorts of options ranging from e.g. running sp_helpfile against the master database (which is not foolproof) or constructing a string to establish the right registry key to search (which can be a pain for named instance) and then running an undocumented extended stored procedure called xp_instance_regread to get this information.</p>
<p>Fortunately, this has all now changed. Gone are the calls to undocumented extended procs or other home-brewed solutions because now (for those of us working on SQL Server 2012 onward), we can just run a straight t-sql function:<br />
<code><br />
SELECT SERVERPROPERTY('INSTANCEDEFAULTDATAPATH') as [Default_data_path], SERVERPROPERTY('INSTANCEDEFAULTLOGPATH') as [Default_log_path];<br />
</code><br />
I found this entirely by chance whilst tracing SSMS in order to update a server build script.<br />
The <a title="SERVERPROPERTY on BOL" href="http://msdn.microsoft.com/en-us/library/ms174396.aspx" target="_blank">SERVERPROPERTY</a> function has been around for a while and provides really useful information about that SQL Server instance, but for some reason the SQL Server 2012 documentation has not been updated to reflect these two new additions to this function, which is a bit of a shame so I&#8217;ve decided to plug it in this post, as well as submitting a <a href="https://connect.microsoft.com/SQLServer/feedback/details/780571/bol-documentation-for-serverproperty-function-is-incomplete" target="_blank">connect</a> bug on this, as I&#8217;m hoping this is just an oversight and it&#8217;s not been deliberately left as an undocumented command.</p>
<p>Incidentally, if you&#8217;re wondering how to change the default data path or the default log path, connect to the server in SSMS, right click on the server in Object Explorer and select Properties. On the Server Properties dialog box look for Database Settings in the object list and make the necessary  modifications under Database default locations.</p>
<p>(EDIT: I did get a response the same day I logged the connect bug and this post, but it got short shrift and closed as a &#8220;Won&#8217;t fix&#8221; which I cannot understand, so if more people vote on it maybe they&#8217;ll change their mind&#8230;)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/a-simple-way-to-get-the-default-sql-server-data-and-log-path-finally/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Error code lookup tool from Microsoft</title>
		<link>http://www.eraofdata.com/error-code-lookup-tool-from-microsoft/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=error-code-lookup-tool-from-microsoft</link>
		<comments>http://www.eraofdata.com/error-code-lookup-tool-from-microsoft/#comments</comments>
		<pubDate>Mon, 11 Feb 2013 21:46:02 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[err.exe]]></category>
		<category><![CDATA[troubleshooting sql server]]></category>
		<category><![CDATA[windows errors]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/?p=498</guid>
		<description><![CDATA[When I worked in PSS for MS there were a lot of cool internal tools we could use to help us in our day to day work. Over the years some of these have been made public &#8211; the most &#8230; <a href="http://www.eraofdata.com/error-code-lookup-tool-from-microsoft/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>When I worked in PSS for MS there were a lot of cool internal tools we could use to help us in our day to day work.</p>
<p>Over the years some of these have been made public &#8211; the most famous of which is <a title="PSSDIAG" href="http://diagmanager.codeplex.com/" target="_blank">PSSDIAG </a>on codeplex, which was released with some fanfare (at least within the SQL community).</p>
<p>However, there&#8217;s one which is (arguably) even more useful as it doesn&#8217;t just apply to SQL Server. It&#8217;s called err.exe and was originally produced by the MS Exchange team. Essentially all it is is a command line tool to which the relevant error code is passed and it returns all the info it can find on it. Err.exe will look up just about <em>any</em> MS error code. It will dig out the full error message and which application/OS libraries it came from. It&#8217;s saved me from a lot of digging around and head-scratching in the past.</p>
<p><a title="Err" href="http://www.microsoft.com/en-us/download/details.aspx?id=985" target="_blank">Download</a> it. Extract it. Add the folder you&#8217;ve extracted it into to your path, and you&#8217;re done.</p>
<p>To use it, open a command prompt type &#8220;err &lt;error code&gt;&#8221; and hit return as per the following screenshot:</p>
<p>&nbsp;</p>
<div id="attachment_501" class="wp-caption aligncenter" style="width: 548px"><a href="http://www.eraofdata.com/wp-content/uploads/2013/02/err2.gif"><img class=" wp-image-501  " alt="Output of Err" src="http://www.eraofdata.com/wp-content/uploads/2013/02/err2.gif" width="538" height="210" /></a><p class="wp-caption-text">Output of Err for 0x8009030c error code</p></div>
<p>I&#8217;ve searched for the 0x8009030c error (the dreaded &#8220;SSPI handshake failed with error code 0x8009030c&#8221; message) and the real beauty of this little tool is that it will accept either a decimal or hexadecimal value and it will show you the error message and which application header file it found the message in along with any additional information available in the header as the above example shows.</p>
<p>The next example shows a search for decimal code 170456 and the multiple places this error can be returned from:</p>
<div id="attachment_499" class="wp-caption aligncenter" style="width: 612px"><a href="http://www.eraofdata.com/wp-content/uploads/2013/02/err.gif"><img class="size-full wp-image-499" alt="Output of checking for 170456 error" src="http://www.eraofdata.com/wp-content/uploads/2013/02/err.gif" width="602" height="199" /></a><p class="wp-caption-text">Output of check 170456 error</p></div>
<p>I&#8217;ve found it extremely useful when looking up error codes in the SQL Server error log and the Windows event logs, and I&#8217;m sure it&#8217;ll save y&#8217;all time too&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/error-code-lookup-tool-from-microsoft/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making the SQL Server error log easier to view</title>
		<link>http://www.eraofdata.com/making-the-sql-server-error-log-easier-to-view/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=making-the-sql-server-error-log-easier-to-view</link>
		<comments>http://www.eraofdata.com/making-the-sql-server-error-log-easier-to-view/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 23:59:33 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[errorlog]]></category>
		<category><![CDATA[sql error log file extension]]></category>
		<category><![CDATA[SQL Server error log]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/blog/?p=351</guid>
		<description><![CDATA[The SQL Server Error log At some point every dba will have had to look at the current SQL Server error log using their favourite text editor. However, as the default error log file is literally just called errorlog (with &#8230; <a href="http://www.eraofdata.com/making-the-sql-server-error-log-easier-to-view/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h2>The SQL Server Error log</h2>
<p>At some point every dba will have had to look at the current SQL Server error log using their favourite text editor.</p>
<p>However, as the default error log file is literally just called errorlog (with no file extension), there&#8217;s the awkward process of selecting the application with which to open the file every time you need to view it, with no option to associate errorlog with your favourite text editor thanks to the lack of file extension. If it&#8217;s a 3am callout and the server is down, you can&#8217;t use Management Studio to view and filter the log so your only resort is to manually load the file and anything that makes this easier is always helpful.</p>
<p>Like all good solutions, the answer is deceptively simple and I use it whenever I build a SQL Server instance (and it also has an added benefit I&#8217;ll describe later); change the default error log filename to have an .txt or .log extension. It&#8217;s an old trick I learnt from my Sybase days and is still very much relevant to the latest and greatest versions of SQL Server (2008 R2, as of the time of writing).</p>
<p>It&#8217;s achieved by editing the command line in SQL Server Configuration Manager (SSCM) and editing the default error log location hard-coded in that command line to something more user-friendly. Double-click the SQL Server instance you want to edit in SSCM, under the SQL Server Services folder to bring up the properties, click on the Advanced tab and the command line can be edited under Startup Parameters. <em>Before you do anything</em>, <strong>save</strong> the current parameters to a text file.</p>
<p>The default SQL Server command line has 3 basic components: the name and location of the master database primary data file, the name and location of the master database transaction log file, and the name and location of the error log. These are represented by the -d (data file) -l (log file) and -e (error file) parameters in the command line. There are other command line options like -E for large page extents and -T for trace flags, as well as options for starting in single user mode and specifying named instances etc etc but they&#8217;re all well outside the scope of this post (I&#8217;m not mentioning them to show off what I know about the command line, but just to highlight the most likely additional parameters you may come across on any of your servers that you want to make this modification on).</p>
<p>I know most dbas are terrified of playing around with the SQL Server command line, but all we&#8217;re interested in is modifying the -e parameter, which by default will be something like &#8216;-eC:Program FilesMicrosoft SQL ServerMSSQL10_50.MSSQLSERVERMSSQLLogERRORLOG;&#8217;. All we&#8217;re interested in is modifying the bit between -e and the semi-colon. Simply adding .LOG or .TXT (see Fig. 1) will make your life so much easier when you have to peruse the log file contents of either the current log or rolled-over logs as you can bypass SSMS and just use your preferred text editor.</p>
<p><img alt="Figure 1: The SSCM Console" src="http://www.eraofdata.com/data/pics/errorlog.jpg" width="594" height="435" align="bottom" /></p>
<p>Inevitably, a restart will be required for the change to take effect, so don&#8217;t do this on production systems until you&#8217;ve tested on development and staging systems first.</p>
<p>I also prefix the name of the host/instance to the error log name as it makes it so much easier to identify the server concerned if you copy log files down to your desktop machine (as I tend to do quite often).</p>
<p>That added benefit? Not only can you alter the filename of the error log, but you can also alter the path, which means you can keep the SQL Server error logs, SQL Server Agent error logs and default trace files in a separate location, as it is this folder that you specify for the error log that dictates where these other files get written to.</p>
<p><strong>Disclaimer:</strong> Do this entirely at your own risk. I&#8217;ve carried these instructions out on production systems on places I have worked out and am comfortable with making these changes. Test them on development/staging servers first if you&#8217;re doing this for the first time or are unsure about making changes.</p>
<p>There&#8217;s also a <a href="https://connect.microsoft.com/SQLServer/feedback/details/786500/add-instance-name-and-a-default-extension-to-the-error-log" target="_blank">Connect enhancement request</a> to give the error log an extension by default as well as to add the instance name to the name of the log, so feel free to vote for it on the Microsoft Connect site.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/making-the-sql-server-error-log-easier-to-view/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working out how long a SQL Server backup/restore will take</title>
		<link>http://www.eraofdata.com/working-out-how-long-a-sql-server-backuprestore-will-take/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=working-out-how-long-a-sql-server-backuprestore-will-take</link>
		<comments>http://www.eraofdata.com/working-out-how-long-a-sql-server-backuprestore-will-take/#comments</comments>
		<pubDate>Wed, 03 Aug 2011 22:44:04 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[backup completion]]></category>
		<category><![CDATA[sys.dm_exec_requests percent_complete]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/blog/?p=331</guid>
		<description><![CDATA[Whilst messing around with SQL Server backup performance testing today I remembered a little-mentioned column in the sys.dm_exec_requests output called percent_complete. This is a rather useful column which reports the progress of certain operations and was introduced in SQL Server &#8230; <a href="http://www.eraofdata.com/working-out-how-long-a-sql-server-backuprestore-will-take/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Whilst messing around with SQL Server backup performance testing today I remembered a little-mentioned column in the <code>sys.dm_exec_requests</code> output called <code>percent_complete</code>. This is a rather useful column which reports the progress of <a href="http://msdn.microsoft.com/en-us/library/ms177648.aspx" target="_new">certain operations</a> and was introduced in SQL Server 2005.</p>
<p>Combined with the output of another column in this DMV called <code>estimated_completion_time</code> we can create a query which neatly displays when a backup or restore operation started, how long SQL Server expects it to take and therefore when it will complete, with a percentage completion column thrown in for good measure.</p>
<p>Here&#8217;s the query I put together whilst waiting for my backup performance tests to complete:</p>
<p><code><br />
select<br />
session_id,<br />
convert(nvarchar(22),db_name(database_id)) as [database],<br />
case command<br />
when 'BACKUP DATABASE' then 'DB'<br />
when 'RESTORE DATABASE' then 'DB RESTORE'<br />
when 'RESTORE VERIFYON' then 'VERIFYING'<br />
when 'RESTORE HEADERON' then 'VERIFYING HEADER'<br />
else 'LOG' end as [type],<br />
start_time as [started],<br />
dateadd(mi,estimated_completion_time/60000,getdate()) as [finishing],<br />
datediff(mi, start_time, (dateadd(mi,estimated_completion_time/60000,getdate()))) - wait_time/60000 as [mins left],<br />
datediff(mi, start_time, (dateadd(mi,estimated_completion_time/60000,getdate()))) as [total wait mins (est)],<br />
convert(varchar(5),cast((percent_complete) as decimal (4,1))) as [% complete],<br />
getdate() as [current time]<br />
from sys.dm_exec_requests<br />
where command in ('BACKUP DATABASE','BACKUP LOG','RESTORE DATABASE','RESTORE VERIFYON','RESTORE HEADERON')<br />
</code></p>
<p>This will return the following:</p>
<p><img src="http://www.eraofdata.com/data/pics/backup.gif" alt="Figure 1: Backup Progress script output" width="830" height="42" align="bottom" /><br />
The database name has been converted to varchar so the output of the query looks ok when result output is set to text mode, otherwise the database name gets padded with blank characters up to the width of the <code>sysname</code> datatype.<br />
It comes in rather useful when running a backup or restore operation where the <code>WITH STATS</code> option has not been used &#8211; I&#8217;m actually finding that this script is preferrable to the output the <code>WITH STATS</code> option provides, as it can be run on demand and the estimate completion time will get updated with the latest predicted time whenever it is run.<br />
Just bear in mind that if instant file initialisation is off the first few minutes of a new restore will be spent initialising the database files so the predicted end time will be wildly pessimistic. Once the file initialisation is complete the predicted end time will return more accurate information.<br />
I have also found that during a large restore the end time is not accurate for the first 5 minutes or so.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/working-out-how-long-a-sql-server-backuprestore-will-take/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SQL Server wait stats</title>
		<link>http://www.eraofdata.com/sql-server-wait-stats/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sql-server-wait-stats</link>
		<comments>http://www.eraofdata.com/sql-server-wait-stats/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 18:36:33 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[DBCC SQLPERF]]></category>
		<category><![CDATA[disk IO]]></category>
		<category><![CDATA[PAGEIOLATCH_SH]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[wait types]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/blog/?p=247</guid>
		<description><![CDATA[The single biggest clue to the source of a performance problem will be from something referred to as the wait stats. What are waitstats? In short wait stats are statistics gathered on what resources SQL Server is waiting on internally &#8230; <a href="http://www.eraofdata.com/sql-server-wait-stats/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>The single biggest clue to the source of a performance problem will be from something referred to as the wait stats.</p>
<h2>What are waitstats?</h2>
<p>In short wait stats are statistics gathered on what resources SQL Server is waiting on internally whilst executing queries.</p>
<h2>Why are they useful?</h2>
<p>They can often provide very quick and objective evidence of a performance bottleneck by showing cumulative wait times that SQL Server spent on getting access to the CPU, memory or disk access as well as numerous other internal resources.<br />
This post is <em>only</em> going to concentrate on IO related waits.</p>
<p>Gathering this information on at least a daily basis can provide invaluable data on a system&#8217;s performance over time and can reveal sudden changes in behaviour caused by e.g. a recent change to an application. Speaking from personal experience, using historically captured wait stats and contrasting them with sudden changes to the topmost wait types is an invaluable way of proving that recent application changes were the trigger for a change in behaviour.</p>
<h2>How do I gather these wait stats?</h2>
<p>That&#8217;s fairly straightforward &#8211; it&#8217;s a T-SQL statement. First, the SQL Server &#8216;version independent&#8217; method:<br />
<code><br />
DBCC SQLPERF (WAITSTATS)<br />
</code></p>
<p>The sample output from my local SQL Server 2005 Express installation is below:</p>
<pre style="font-family: courier;">Wait Type                        Requests      Wait Time     Signal Wait Time
-------------------------------- ------------- ------------- ----------------
MISCELLANEOUS                    0             0             0
PAGEIOLATCH_NL                   0             0             0
PAGEIOLATCH_KP                   0             0             0
PAGEIOLATCH_SH                   178           327           0
PAGEIOLATCH_UP                   16            436           0
PAGEIOLATCH_EX                   14            0             0
PAGEIOLATCH_DT                   0             0             0
IO_COMPLETION                    173           1279          0
ASYNC_IO_COMPLETION              1             1294          0
CHKPT                            1             202           0
BACKUPIO                         0             0             0
DISKIO_SUSPEND                   0             0             0
IMPPROV_IOWAIT                   0             0             0
WRITELOG                         29            639           15</pre>
<p>From SQL Server 2005, the wait stats data has been split into two separate dynamic management views (DMVs) <span style="font-family: courier; color: green;">sys.dm_latch_wait_stats</span> and <span style="font-family: courier; color: green;">sys.dm_os_wait_stats</span>. The latch wait stats are counters for internal waits within the SQL Server database engine and the OS wait stats accumulate data on waits for external resources such as CPU, disk and memory.</p>
<p>As we&#8217;re concentrating on IO waits, its the <span style="font-family: courier; color: green;">sys.dm_os_wait_stats</span> we&#8217;re interested in.</p>
<p>The following query will grab the IO wait types output:<br />
<code><br />
select * from sys.dm_os_wait_stats<br />
where<br />
wait_type like 'PAGEIO%' or<br />
wait_type like '%IO_COMPLETION' or<br />
wait_type like 'DISKIO%' or<br />
wait_type like 'BACKUPIO%'or<br />
wait_type like 'WRITE%'<br />
order by wait_time_ms<br />
</code></p>
<pre style="font-family: courier;">wait_type                                                    waiting_tasks_count  wait_time_ms         max_wait_time_ms     signal_wait_time_ms
------------------------------------------------------------ -------------------- -------------------- -------------------- --------------------
PAGEIOLATCH_SH                                               20892941             110133998            17895                332331
PAGEIOLATCH_EX                                               392948               7270457              2395                 10353
IO_COMPLETION                                                719058               1061552              916                  6929
PAGEIOLATCH_UP                                               4332                 81307                3635                 1243
BACKUPIO                                                     3998                 16393                240                  18
ASYNC_IO_COMPLETION                                          133                  14771                805                  0
PAGEIOLATCH_DT                                               0                    0                    0                    0
PAGEIOLATCH_NL                                               0                    0                    0                    0
PAGEIOLATCH_KP                                               0                    0                    0                    0
DISKIO_SUSPEND                                               0                    0                    0                    0</pre>
<p>Incidentally, these queries are only meant to show how to grab the data, if you hunt around on the web you&#8217;ll find some elegant queries for processing this data.</p>
<p><a href="http://support.microsoft.com/kb/822101">This KB</a> from MS discusses these wait types (and more).</p>
<p>SQL Server 2008 R2 has even more granular wait-types to isolate IO related waits, but the above query has been limited to allow it to work from SQL Server 2005.</p>
<p><span style="font-family: courier; color: black;">wait_time_ms</span> is the total accumulated wait time (since that SQL Server instance was last restarted) spent on accessing that resource.<br />
<span style="font-family: courier; color: black;">max_wait_time_ms</span> is the peak wait time for one of these requests.<br />
<span style="font-family: courier; color: black;">signal_wait_time_ms</span> signal wait time is how long was spent waiting to get access to the runnable queue for that resource, and can indicate CPU pressure if this is high.</p>
<p>If these IO related wait types are high in the list of overall waits (see the Waits and Queues article from Microsoft lower down), then you have an IO issue.<br />
This is either down to the performance of the IO subsytem, or the physical design of the database. The design issues could be due to the file/filegroup layout of the database concerned, but also related to the layout of tempdb (in a previous role it never ceased to amaze me how much thought went into the layout of an application database at various customer sites, whilst tempdb was left e.g. at it&#8217;s 8MB starting size with (just one) data file and log file sharing the same drives and/or sharing application database drives).</p>
<p>Take a close look at the particular wait type concerned. If the <a title="WRITELOG" href="http://sqlcat.com/sqlcat/b/technicalnotes/archive/2008/12/09/diagnosing-transaction-log-performance-issues-and-limits-of-the-log-manager.aspx" target="_blank">WRITELOG</a> wait type is dominant, you know it&#8217;s the log drive if this is backed up by <strong>sys.dm_io_virtual_file_stats</strong>. If it&#8217;s BACKUPIO, we can infer that it&#8217;s the backup drive(s).<br />
A word of caution, don&#8217;t talk the numbers at face value.  For example, if the PAGEIOLATCH_SH wait type is high in the list, we know it&#8217;s the data drive(s), but that does not necessarily mean there is an issue with the disk subsystem, merely that a lot of IO requests are being issued and this could point to database design issues &#8211; if some of the tables had better indexes the query optimizer can come up with a more efficient query plan and retrieve the same data with far fewer IOs. Needless to say (almost), but corroborating evidence from the DMVs or perfmon should always be gathered whenever possible.</p>
<p>These are just a few examples, if you gather this data regularly a clear picture can be built up of what performance issues are affecting your systems, and by picking upon trends you can get advance warning of impending issues.</p>
<p>For further information on wait types and what all the output columns mean, there is an excellent <a href="http://download.microsoft.com/download/4/7/a/47a548b9-249e-484c-abd7-29f31282b04d/Performance_Tuning_Waits_Queues.doc">Waits and Queues</a> document on the Microsoft website which goes through them and is highly recommended reading.</p>
<p>Thomas Kejser also has an excellent <a title="Bottleneck Analysis Script" href="http://blog.kejser.org/2013/04/11/bottleneck-diagnosis-on-sql-server-new-scripts/" target="_blank">bottleneck analysis</a> script.</p>
<p>The most telling output can be from identifying IO stalls.<br />
SQL Server 2000 had <a href="http://msdn.microsoft.com/en-us/library/ms187309.aspx">fn_virtual_filestats</a> and this has now been incorporated into <span style="font-family: courier; color: green;">sys.dm_io_virtual_file_stats</span> which is coming up in the next post&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/sql-server-wait-stats/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Misaligned disk partition offsets and SQL Server Performance</title>
		<link>http://www.eraofdata.com/misaligned-disk-partition-offsets-and-sql-server-performance/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=misaligned-disk-partition-offsets-and-sql-server-performance</link>
		<comments>http://www.eraofdata.com/misaligned-disk-partition-offsets-and-sql-server-performance/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 20:07:07 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[partition alignment]]></category>
		<category><![CDATA[Partition offsets]]></category>
		<category><![CDATA[SQL Server IO performance]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/blog/?p=221</guid>
		<description><![CDATA[I&#8217;m starting off this series of posts with a discussion about partition offsets. Diving off at the deep end a bit perhaps, but if your disk setup is not based on firm foundations, you&#8217;re setting yourself up for one of &#8230; <a href="http://www.eraofdata.com/misaligned-disk-partition-offsets-and-sql-server-performance/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m starting off this series of posts with a discussion about partition offsets. Diving off at the deep end a bit perhaps, but if your disk setup is not based on firm foundations, you&#8217;re setting yourself up for one of the most common and easily-avoidable performance issues right from the off, and a IO performance hit of 20-30%.</p>
<p>The partition offset issue is relevant to any disk partitions created <em>prior</em> to Windows Server 2008. What this means is that whilst your OS may be Windows Server 2008, if the disk you are using was migrated from an older OS the chances are that it may still be exposed to the problem.<br />
Also, certain OEM built machines may be exposed to this problem even on Windows Server 2008 as they often include hidden partitions used for e.g. server recovery date.</p>
<h2>Partition offset</h2>
<p>Without going into too great a level of detail on how a disk is structured both physically and logically, the partition offset is basically where Windows will start writing its first bytes to disk once the partition concerned is first used.<br />
When a disk partition is created in Windows Server 2003 and before, the first 63 sectors are reserved for the MBR as well as disk vendor proprietary information. That means Windows Server 2003 and before (hereon referred to as just Windows) will write its first bytes of data on the 64th sector.</p>
<h2>What&#8217;s the big deal?</h2>
<p>These 63 sectors are invariably 512 bytes (worth checking with your SAN team/disk vendor however as some SANs may use larger sector size but present the sectors as logical 512 bytes sectors to Windows). Therefore the 64th sector will begin at a 31.5KB sector boundary. What this means is that if this is a SQL Server disk, SQL Server will write its first data page on a 31.5K sector boundary, and every <em>n</em>th page will be written across these boundaries.<br />
The big deal therefore is that each of these <em>n</em>th IO operations will result in an additional IO to read or write the data that was on the page that crossed that boundary (the actual value of <em>n</em> will depend on cluster (sector) size and stripe unit size).<br />
What this means in real (performance) terms is that a properly aligned system will yield a 20-30% performance improvement in IO latency (and therefore query execution time). All this for free, without having to analyse SQL Server configuration, indexing strategy, query plans etc etc.</p>
<h2>How do I check my offset?</h2>
<p>Checking the offset can be done via a wmi console (wmic) command.</p>
<table border="0">
<tbody>
<tr>
<td><span style="font-size: small; background-color: #000000; font-family: &amp;quot; courier new&amp;quot;; color: #ffffff;"> wmic /node: &lt;name of server to check&gt; partition get BlockSize, StartingOffset, Name, Index</span></td>
</tr>
</tbody>
</table>
<p>The above command will show output similar to the following (if the <code>wmic</code> command is being executed locally, there&#8217;s no need for the /node parameter):</p>
<table border="0">
<tbody>
<tr>
<td bgcolor="black"><span style="font-size: small; color: #ffffff;"><br />
C:WINDOWSsystem32&gt;</span><span style="font-size: small; background-color: #000000; font-family: &amp;quot; courier new&amp;quot;; color: #ffff00;">wmic /node:myDbServer partition get BlockSize, StartingOffset, Name, Index<br />
<span style="font-size: small; color: #ffffff;"><br />
BlockSize Index Name StartingOffset<br />
512 0 Disk #0, Partition #0 32256<br />
512 0 Disk #1, Partition #0 32768<br />
512 0 Disk #2, Partition #0 32768<br />
512 0 Disk #3, Partition #0 32256<br />
512 0 Disk #4, Partition #0 32256<br />
512 0 Disk #5, Partition #0 1048576<br />
512 0 Disk #6, Partition #0 1048576<br />
</span></span></td>
</tr>
</tbody>
</table>
<p>There will be one line of output for each disk and each disk will be identified by its disk number.<br />
Use the Disk Administrator to identify how these drive letters map to your drive letters.<br />
Surprisingly enough, the StartingOffset column is the key column, and will show the starting offset in bytes.<br />
Disks 1 and 2 have 64 sector offset which lines up with e.g. legacy controllers on local disks.<br />
Drives on default values will show a value of 32256, such as disks 0, 3 and 4 in the output above. Divide that by the 512 byte sectors and you&#8217;ll get that dreaded value of 63.<br />
Disks 5 and 6 have a 1MB offset which should line up with most modern disk, SAN cache and cluster size scenarios.<br />
What the above output shows is that, depending on the age of the system, there can be a myriad of offsets used which were correct according to how the sytem was configured at the time. Disks 1 and 2 were altered from the default, so at some point in this system&#8217;s history someone looked into the issue of partition misalignment and tweaked it for this drive.<br />
So why are disks 3 and 4 on misaligned defaults? Well, have you ever had disks recut to (usually) increase storage. That usually involves blowing away partitions and recreating them. If partition offsetting was not carried out when the partition was created for whatever reason, this is what you can end up with. The newest disks 5 and 6 were created with the latest information to hand, hence the higher offset, but as this slightly contrived example shows (it&#8217;s based on real world systems) it pays to be vigilant and review systems that were previously correctly set up.</p>
<h2>How do I fix it?</h2>
<p>On paper, the fix is very simple; adjust the partition offset. The <code>diskpart</code> command line utility is used to reset the offset.<br />
Move the offset along from the default misaligned 31.5K offset to an offset that works with your cluster size and stripe unit size; 64K, or a multiple of 64K usually works on most systems, but where a SAN is involved, it gets more complicated as stripe unit sizes will vary from vendor to vendor and rig to rig, so you&#8217;ll have to get your SAN engineer/vendor involved.<br />
Windows Server 2008 defaults to 1024K offset.</p>
<p>Ideally, the offset needs to start at a point where the IO requests that SQL Server issues (which will be a multiple of 8K, depending on the IO request type being fulfilled), the cluster size, and any caching involved at disk controller/SAN level all line up, thus avoiding additional IO requests.<br />
The downside, of course, is the partition will have to be recreated, so downtime will be involved on standalone servers that have no HA solution implemented.</p>
<p>Realigning the partition offset involves blowing away the disk partition in question, so if you&#8217;re not familiar with <code>diskpart</code>, leave it to your relevant storage/Windows team to reset the partition. If you really want to do this yourself, you&#8217;ll find step-by-step instructions in the SQLCAT team&#8217;s <em>Disk Partition Alignment Best Practices</em> article linked to at the bottom of this post.</p>
<p>The resulting 20-30% improvement in latency times have been verified by the SQLCAT team who have published them in that paper on partition alignment mentioned above, and is highly recommended reading for anyone with an interest in this subject.</p>
<h5>Links</h5>
<p>If you only read one further article on partition offsets, make it this one!<br />
<a href="http://msdn.microsoft.com/en-us/library/dd758814.aspx" target="_blank">Disk Partition Alignment Best Practices for SQL Server</a></p>
<p><a href="http://technet.microsoft.com/en-us/library/cc966500.aspx" target="_blank">SQL Server 2000 I/O Basics</a></p>
<p><a href="http://support.microsoft.com/kb/929491" target="_blank">Disk performance may be slower than expected when you use multiple disks in Windows Server 2003, in Windows XP, and in Windows 2000</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/misaligned-disk-partition-offsets-and-sql-server-performance/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SQL Server and Disk IO</title>
		<link>http://www.eraofdata.com/sql-server-and-disk-io/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sql-server-and-disk-io</link>
		<comments>http://www.eraofdata.com/sql-server-and-disk-io/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 20:07:00 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Disk performance]]></category>
		<category><![CDATA[IO]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/blog/?p=211</guid>
		<description><![CDATA[Many aspects of a database system&#8217;s configuration will affect the performance of queries running on that DBMS. However, there is one single component that has the greatest impact on DBMS performance, and that, of course, is disk (IO) access. It&#8217;s &#8230; <a href="http://www.eraofdata.com/sql-server-and-disk-io/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Many aspects of a database system&#8217;s configuration will affect the performance of queries running on that DBMS. However, there is one single component that has the greatest impact on DBMS performance, and that, of course, is disk (IO) access.</p>
<p>It&#8217;s a broad topic and all aspects of it are pretty well covered in various blogs and technical articles, but there&#8217;s not much out there that gathers it all together. The intention of this series of posts is to try consolidate some of this information and focus in on some of the functions and procedures that can be used to monitor, troubleshoot and configure SQL Server disk configuration and most, importantly, disk performance. It won&#8217;t be exhaustive and cover every conceivable option, but will be based on experience gained whilst working at Sybase and Microsoft and sprinkling of &#8216;real world&#8217; database administration experience.</p>
<p>I&#8217;ve split the topic up into smaller sub-topics in order to make it more manageable:</p>
<p>1. <a href="http://www.eraofdata.com/misaligned-disk-partition-offsets-and-sql-server-performance">Partition offsets</a><br />
2. <a href="http://www.eraofdata.com/sql-server-wait-stats/">Wait Stats</a><br />
3. <a title="Tracking SQL Server IO performance" href="http://www.eraofdata.com/tracking-sql-server-io-performance/" target="_blank">Tracking SQL Server IO performance</a><br />
4. Physical Fragmentation<br />
5. System Monitor (Perfmon)<br />
6. Tempdb</p>
<p>Kinda ambitious, I know, but I don&#8217;t blog often and it gives me something to aim for!</p>
<p>There are plenty of excellent articles which cover IO in some depth, so I&#8217;m going to try my best to avoid regurgitation and try keep things DBA-centric.  (I highly recommend reading the links at the end of the relevant posts to anyone wanting a deeper understanding of IO issues, from configuration to monitoring and troubleshooting).</p>
<p>Until solid state disk prices come down and become ubiquitous, disk access is still a painfully slow (relatively speaking) mechanical process. An IO (read or write) request is issued by SQL Server which is passed onto the OS. The OS then passes this onto your disk controller or HBA and eventually this data request translates into a mechanical arm sitting above a spinning disk which will read or write the data that SQL Server requested.</p>
<p>What this means in performance terms is that disk access will be measured in milliseconds.</p>
<p>Access times to the other major components of a DBMS that directly affect performance such as CPU and RAM can be measured in microseconds or nanoseconds.</p>
<p>As you can see, it&#8217;s an order of magnitude difference.</p>
<p>This single factor alone highlights why reviewing a SQL Server database installation&#8217;s disk configuration can be such a valuable and rewarding exercise.  In fact, I begin many of my SQL Server troubleshooting exercises by eliminating IO performance first.</p>
<p>Prior to SQL Server 2000 SP4 it was difficult to identify IO performance issues without a lot of digging around. The biggest clue SQL Server would give would be the occasional mysterious 17883 (or even 17884) errors, and these were not always guaranteed to be IO related, although IO was usually heavily implicated. SP4 for SQL Server 2000 introduced those &#8216;slow IO&#8217; messages which most DBAs will be familiar with and was a step in the right direction.</p>
<p>SQL Server 2005 introduced various DMVs which would give much greater insight into IO performance, and SQL Server 2008 built on this with the Performance DataWarehouse. These posts are going to cover methods that can be applied from SQL Server 2000 onwards, so will not delve deeply into features and properties only available in later versions, but focus instead on functions and features available across the last three versions of SQL Server as I know there&#8217;s still a lot of SQL Server 2000 installations out there.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/sql-server-and-disk-io/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The SQL Server default trace</title>
		<link>http://www.eraofdata.com/the-sql-server-default-trace/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-sql-server-default-trace</link>
		<comments>http://www.eraofdata.com/the-sql-server-default-trace/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 23:15:42 +0000</pubDate>
		<dc:creator>Ajmer Dhariwal</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Default Trace]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[SQL Profiler]]></category>
		<category><![CDATA[SQL Trace]]></category>

		<guid isPermaLink="false">http://www.eraofdata.com/blog/?p=161</guid>
		<description><![CDATA[The SQL Server default trace is useful! The default SQL Server trace in SQL Server 2005 onwards is a background trace that runs continuously and records event information that, despite the adverse comments on the web about its value, can &#8230; <a href="http://www.eraofdata.com/the-sql-server-default-trace/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h2>The SQL Server default trace <em>is</em> useful!</h2>
<p>The default SQL Server trace in SQL Server 2005 onwards is a background trace that runs continuously and records event information that, despite the adverse comments on the web about its value, can be useful in troubleshooting problems. Not only that, but it&#8217;s there out-of-the box so you don&#8217;t have to do put any effort into enabling or managing it.</p>
<p>This blog post intends to show that, in the right hands, the default SQL Server trace in SQL Server 2005 and SQL Server 2008 can yield very useful information.</p>
<h2>What is the default trace?</h2>
<p>A default installation of SQL Server 2005/2008 results in a lightweight server-side trace running continuously in the background.<br />
The trace records a handful of events to a trace file which can be loaded up and reviewed in SQL Profiler, just the same as any other trace file.<br />
By default, five trace files are kept in the same folder as the SQL Server error log. Each file has a size limit of 20MB before it rolls over to the next file. After the fifth file is filled, the default trace rolls over to the first file, and so on.<br />
To confirm if the trace is enabled, run the following query:<br />
<code><br />
sp_configure 'default trace enabled'<br />
</code></p>
<p>A <code>run_value</code> of 1 indicates the default trace is enabled and should be active.</p>
<p>If the trace is enabled, the following query will list the details:</p>
<p><code><br />
select * from sys.traces where is_default = 1<br />
</code></p>
<p>Amongst the output will be confirmation that the trace is running (<code>is_shutdown</code> will be set to 0 if it is running, otherwise it will be 1). The <code>path</code> column will show the full path and name of the current default trace output file.</p>
<h2>Interrogating the default trace</h2>
<p>Getting information out of the default trace file is much the same as getting information out of any other SQL Profiler trace file. There are multiple options, from simply loading the file in SQL Profiler, interrogating it directly via T-SQL statements, or by loading it into a table.</p>
<p>I&#8217;ve used all three methods in the past. The method you use depends on your own preferences and immediate requirements.</p>
<p>The examples in this blog will interrogate the trace files directly, as that&#8217;s the quickest way to get up and running and view the contents of the trace.<br />
With more experience, the trace file can be regularly polled via e.g. a stored procedure that can be incorporated into standard health-checks to automatically retrieve events of any interest; you decide what those interesting events are. More on that later.</p>
<p>The queries I will demonstrate in this post reference a system table called <span style="font-family: courier; color: green;">sys.trace_events</span>. This is used to get the graphical name of the events I&#8217;m interested in (otherwise we will only see the numeric event id, as that is what the default trace records).</p>
<p>This table, introduced in SQL Server 2005 holds details of the all the eventclass ids a SQL trace uses, so you can use this to identify which eventclass id corresponds to which event, which is how I established eventclass 20 is a login failed event (the actual event is Audit login failed).</p>
<h2>First things first</h2>
<p>The first thing to do is isolate the trace file in question.<br />
Assuming the default trace is enabled and running the following query will return the current trace file and its location:<br />
<code><br />
select path from sys.traces where is_default = 1<br />
</code></p>
<p>If the current trace does not overlap with the time of the error you are trying to track down, go to the location of that trace file and identify which of the preceding trace files is from the correct time period. As a precautionary next step, make a copy of the trace file, so you have a permanent record, and also to prevent the file being overwritten during a subsequent rollover.</p>
<h2>Example 1: Finding out who filled up tempdb (or any other database for that matter&#8230;)</h2>
<p>So, let&#8217;s get started. A common scenario for a dba is getting called out overnight because somebody, or some thing has maxed out all the space in e.g. tempdb.<br />
Using the <code>fn_trace_gettable</code> function to interrogate the trace file directly we can get some useful information about the cause. Assume there was an 1105 error just before 21:00 last night (&#8220;Could not allocate space for object &#8221; in database &#8216;tempdb&#8217;&#8221;).</p>
<p>To find this out it&#8217;s just a question of confirming when the exact time the database full error occurred and filtering the trace from that period for events in that database. Deceptively simple isn&#8217;t it? The query below does just that.</p>
<p><code><br />
select te.name as [event],e.textdata, e.applicationname, convert (varchar(20), object_name(e.objectid)) as object, e.spid, e.duration/1000 as [duration (ms)], e.starttime, e.endtime, e.databasename, e.filename, e.loginname, e.hostname, e.clientprocessid<br />
from fn_trace_gettable('C:Program FilesMicrosoft SQL ServerMSSQL.1MSSQLLOGlog_326.trc', default) e<br />
inner join sys.trace_events te on e.eventclass=te.trace_event_id<br />
where databasename = 'tempdb'<br />
and e.starttime between '2009-09-24 20:30' and '2009-09-24 21:00'<br />
order by e.starttime<br />
</code></p>
<h2>Query 1: Who maxed out tempdb (or any other database)?</h2>
<p>The query tracks all events in tempdb that occurred in tempdb for about half an hour before the tempdb full error.</p>
<p><img alt="Fig. 1: Tempdb events" src="http://www.eraofdata.com/data/pics/200909_1.jpg" width="546" height="100" align="bottom" /></p>
<h5>Fig. 1: Events leading to tempdb full</h5>
<p>Most of the events causing this type of issue will be object creation and autogrow as can be seen above. What we will also have is what was causing them; <em> applicationname , loginname, spid, hostname and clientprocessid </em>. These should all be enough to identify who or what was responsible for the tempdb issue (see fig. 1).</p>
<p>Sometimes, the objectname column will have the names of the tables being created, and the spid column will allow you to narrow down the trace even further in case tracing events half an hour before the database full problem occurred presents too much or too little data.</p>
<p>Needless to say, but I&#8217;ll say it anyway, change the databasename column to the name of the database you&#8217;re interested if you&#8217;re looking for events leading to the same issue in another database.<br />
Also, the trace can be filtered on object creation (trace_event_id = 46) or data or log file autogrow (trace_event_id = 92 or 93) events</p>
<p>Without this information you have nothing to go on, unless you happened to be logged in at the server at the time the issue was occurring and realised that there was a long running transaction running against tempdb which was going to cause it to fill up.<br />
You might also notice that for the autogrow events the Duration column records how long the autogrow took &#8211; very useful in identifying potential IO performance isues (or impractical file growth settings).<br />
The <em>object</em> column returns the name of the object being referenced/created. If this query is not run against the trace file on the server that the error occurred on, the chances are this column will contain NULLs, so you can select just the raw objectid instead to view the values and then manually retrieve the object names from the affected server.<br />
Incidentally, the <code>fn_trace_gettable</code> function is also the function used to load a trace file into a database table.</p>
<h2>Example 2: Isolating login failures</h2>
<p>OK, so the default trace has some use, but what else can it do?</p>
<p>Suppose you get the occasional login failure on a system, you&#8217;re not too worried as that&#8217;s inevitable sometimes, but from time to time the login failure is for sa and the ip address logged in the error log doesn&#8217;t correspond to any workstation belonging to a dba who should have access. You should be worried now.</p>
<p><code><br />
select e.name as eventclass, t.textdata, t.hostname, t.ntusername, t.ntdomainname, t.clientprocessid, t.applicationname, t.loginname, t.spid, t.starttime, t.error from fn_trace_gettable('c:program filesmicrosoft sql servermssql.1mssqlloglog_329.trc', default) t<br />
inner join sys.trace_events e on t.eventclass = e.trace_event_id where eventclass=20<br />
</code></p>
<h2>Query 2: Isolating where a login failure came from</h2>
<p><img alt="Fig. 2: Login failures" src="http://www.eraofdata.com/data/pics/200909_2.jpg" width="546" height="64" align="bottom" /></p>
<h5>Fig 2: Isolating login failures</h5>
<p>The query references the trace file from the period of the login failure and retrieves the columns containing all the information that should be needed to pin down where any login failure recorded in that file came from. I&#8217;ve already covered how to use this information in another blog posting covering <a href="http://www.eraofdata.com/blog/sql-18456-login-failures/" target="_new">how to identify the source of login failures</a>.</p>
<h2>Example 3: Identifying performance issues</h2>
<p>So we&#8217;ve seen some practical applications like pinning down login failures and database or log growth issues which makes the default trace pay for itself in some ways. But wait, there&#8217;s more.</p>
<p>The bane of most dbas lives&#8217; are application teams who will describe a performance problem they have: great, you say, what&#8217;s the application and SQL Server database, I&#8217;ll log on and take a look? Oh, it happened last week, some time in the afternoon the application team will reply. That&#8217;s OK, you (want to) say, I&#8217;ll just step into my time machine and go back a few days, or get in touch with my sixth-sense and carry out some sort of mind-meld with SQL Server and try and find out why it was mis-behaving a few days ago. <span style="font-size: xx-small;">[Disclaimer] Before you go any further I would like to make clear that none of this will be possible via the default trace. It can do quite a few things, but time-travel and mind-melds are slightly out of scope.</span></p>
<p>The default trace does offer some hope here. Because by default 5 trace files are kept (including the current trace files) there is a chance that the older trace files may cover the time period in question.</p>
<p>The default trace will capture some common performance affecting events, namely:</p>
<ul>
<li>Missing Column Statistics</li>
<li>Hash Warning</li>
<li>Sort Warnings</li>
<li>Missing Join Predicate</li>
</ul>
<p>So, if you still have the trace file from the period in question, a query like the following will pick out all the those events:</p>
<p><code><br />
select v.name as [Event Class], TextData, SPID, Duration, StartTime, EndTime, DatabaseName, ObjectName, ClientProcessID,<br />
ApplicationName, LoginName, SessionLoginName, NTUserName<br />
from fn_trace_gettable('C:log_180.trc', DEFAULT) trc<br />
inner join sys.trace_events v on<br />
trc.EventClass = v.trace_event_id<br />
where<br />
v.name in ('Missing Column Statistics','Hash Warning','Sort Warnings','Missing Join Predicate')<br />
and StartTime between '2009-09-05 14:00' and '2009-09-06 16:00'<br />
</code></p>
<h5>Query 3: Isolating who made table DDL changes</h5>
<h2>Example 4: Finding performance problem events</h2>
<p>Let&#8217;s start by clarifiying that this is not going to tell us what the query was that generated these warnings. At the end of the day, the default trace is designed to be a low-impact trace that will not cause any performance or load issues so what it gathers is therefore restricted.<br />
What we do have, however are details of when all these errors occcured, the PID of the offending client process, together with the hostname, application name and login name.</p>
<p>Armed with that information, we can then go back into that trace and zoom in on a particular spid or application. By narrowing down the spid or application, but expanding the events we&#8217;re looking at we can find out a bit more about the problem. I use a combination of the time period, spid and clientprocessid to narrow down (see my <a href="http://www.eraofdata.com/blog/sql-18456-login-failures/" target="_new">January 2009 blog</a> on login failures on how to use this handy column to track down exactly what application is connecting).</p>
<p><code><br />
select v.name as [event class], textdata, spid, duration, starttime, endtime, databasename, objectname, clientprocessid,<br />
hostname, applicationname, loginname, sessionloginname, ntusername<br />
from fn_trace_gettable('c:log_180.trc', default) trc<br />
inner join sys.trace_events v on<br />
trc.eventclass = v.trace_event_id<br />
where<br />
starttime between '2009-09-05 14:00' and '2009-09-06 16:00'<br />
and spid = 57 and clientprocessid = 2044<br />
</code></p>
<h4>Query 4: Narrowing down performance problems</h4>
<p><img alt="Fig. 3: Performance problem events" src="http://www.eraofdata.com/data/pics/200909_3.jpg" width="546" height="170" align="bottom" /></p>
<h5>Fig 3: Performance problem events</h5>
<p>I&#8217;ve replaced figure 3 with the output of an identical query (but using different time range parameters) trace from a server where the output allowed us to identify what query in a large batch job that was running overnight needed tuning. The output showed what time the query ran, the relevant details of the client application and the names of some of the tables/indexes that were affected .</p>
<h2>Example 5: Finding out who made changes</h2>
<p>Perhaps one of the most useful aspects of the default trace is the fact that it records changes made to objects and server configuration changes</p>
<p>Suppose someone added or removed a column from a table? The following query highlights who did it:</p>
<p><code><br />
select e.name as eventclass, t.textdata, t.objectid, t.objectname, t.databasename, t.hostname, t.ntusername, t.ntdomainname, t.clientprocessid, t.applicationname, t.loginname, t.spid, t.starttime, t.error from fn_trace_gettable('C:Program FilesMicrosoft SQL ServerMSSQL.1MSSQLLOGlog_339.trc', default) t<br />
inner join sys.trace_events e on t.eventclass = e.trace_event_id<br />
where eventclass=164<br />
</code></p>
<h2>Query 5: Isolating who made table DDL changes</h2>
<p>Eventclass 164 is the Object:Altered event, and the above query should show what application and login made the changes.</p>
<p>If the change concerned was e.g. a server configuration change like e.g. the <code>max server memory</code> setting, the following code will isolate the culprit:</p>
<p><code><br />
select e.name as eventclass, t.textdata, t.hostname, t.ntusername, t.ntdomainname, t.clientprocessid, t.applicationname, t.loginname, t.spid, t.starttime, t.error from fn_trace_gettable('C:Program FilesMicrosoft SQL ServerMSSQL.1MSSQLLOGlog_339.trc', default) t<br />
inner join sys.trace_events e on t.eventclass = e.trace_event_id where eventclass=22<br />
</code></p>
<h2>Query 5a: Isolating who made server configuration changes</h2>
<p>Eventclass 22 is the ErrorLog event, so of course the changes can also be seen in the error log, but the error log won&#8217;t give you the details of who made the change.</p>
<h2>Disabling the default trace</h2>
<p>The chances are, most SQL Server 2005 (and beyond) systems are running this trace in the background without anyone even being aware of them, which in itself highlights what low impact these traces have. However, if CPU or disk resources are scarce the default trace can be disabled.<br />
To disable the default trace, run the following commands:</p>
<p><code><br />
sp_configure 'default trace', 0<br />
go<br />
reconfigure with override<br />
go<br />
</code></p>
<h2>And finally&#8230;</h2>
<p>This post was not intended to show ever possible piece of information that can be extracted from the default trace, but merely to highlight some of the things that can be found without too much effort.<br />
Have a look at your own trace files as everyone installation and every application running against SQL Server is different &#8211; it&#8217;s a great way of pro-actively finding potential issues.</p>
<p>So go and explore&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eraofdata.com/the-sql-server-default-trace/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.479 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2013-05-21 21:47:56 -->

<!-- Compression = gzip -->