<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Erin Stellato</title>
	
	<link>http://erinstellato.com</link>
	<description>The SQL Sequel</description>
	<lastBuildDate>Sat, 19 May 2012 15:28:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ErinStellato_TheSqlSequel" /><feedburner:info uri="erinstellato_thesqlsequel" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Presenting for the PASS DBA Virtual Chapter this week</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/ChwPnkolNTU/</link>
		<comments>http://erinstellato.com/2012/05/presenting-for-pass-dba-virtual-chapter-week/#comments</comments>
		<pubDate>Mon, 07 May 2012 16:26:02 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Presenting]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=853</guid>
		<description><![CDATA[SQLRally kicks off this week in Dallas, Texas and to all those presenting and attending, I hope you have a great time!  May is always an extremely busy month for me so I will not be attending SQLRally, but I will be presenting this week via the PASS DBA Virtual Chapter.  If you want to...]]></description>
			<content:encoded><![CDATA[<p><a title="SQLRally" href="http://www.sqlpass.org/sqlrally/2012/dallas/" target="_blank">SQLRally</a> kicks off this week in Dallas, Texas and to all those presenting and attending, I hope you have a great time!  May is always an extremely busy month for me so I will not be attending SQLRally, but I will be presenting this week via the <a title="DBA Virtual Chapter" href="http://dba.sqlpass.org/" target="_blank">PASS DBA Virtual Chapter</a>.  If you want to hear me cover DBCC Commands and what you should consider when running them, then sign up to attend the LiveMeeting this Wednesday at 2 PM EDT/11 AM PDT (abstract below).  If you&#8217;re not traveling on Wednesday, presenting a pre-con or attending a pre-con, I&#8217;d love to see you there.  I presented this session at SQLSaturday in Madison a couple weeks ago, and had great feedback and really enjoyed giving it.  It&#8217;s a 200 level session for DBAs and developers that&#8217;s filled with demos and practical examples.  If you can&#8217;t make it on Wednesday, don&#8217;t worry, I will be at SQLSaturday in <a title="SQLSaturday Chicago" href="http://www.sqlsaturday.com/119/schedule.aspx" target="_blank">Chicago</a> and in <a title="SQLSaturday Philadelphia" href="http://www.sqlsaturday.com/121/schedule.aspx" target="_blank">Philadelphia</a> and will look for you there.  Otherwise, hit the <a title="LiveMeeting registration" href="https://www323.livemeeting.com/lrs/8000181573/Registration.aspx?pageName=s6798gl02wk3xg74" target="_blank">LiveMeeting site</a> to register now (and be entered into the drawing for a $50 Amazon gift card) or just <a title="LiveMeeting attendee link" href="https://www323.livemeeting.com/cc/8000181573/join?id=J93PGC&amp;role=attend" target="_blank">join on Wednesday</a> at 2 PM EDT/11 AM PDT.  See you then!</p>
<p>&nbsp;</p>
<h3>DBCC Commands: The Quick and the Dangerous</h3>
<p>There are many DBCC statements at the disposal of Database Administrators and Developers. Some are used for the greater good; others can wreak havoc in your system. The majority of these commands are informational, but if you’re not careful you can introduce chaos or at worst, lose data you may never find again. In this session we will explore DBCC commands that are useful for the DBA and developer, and cover when to use them and how. Expect demonstrations that provide a practical application of these commands &#8211; both documented and not &#8211; that database professionals can utilize quickly and easily.</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/ChwPnkolNTU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/05/presenting-for-pass-dba-virtual-chapter-week/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/05/presenting-for-pass-dba-virtual-chapter-week/</feedburner:origLink></item>
		<item>
		<title>varchar(max) in an Index</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/j26ufY_kNvs/</link>
		<comments>http://erinstellato.com/2012/05/varchar-max-index/#comments</comments>
		<pubDate>Tue, 01 May 2012 13:00:07 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Indexes]]></category>
		<category><![CDATA[SQLSaturday]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=847</guid>
		<description><![CDATA[There is one more attendee question from SQLSaturday #118 that I want to follow up on, and it is this: “Is there any way to create an index with a varchar(max) column as the leading column?” This question came up during my Statistics presentation, and was at the end as we were winding down.  My...]]></description>
			<content:encoded><![CDATA[<p>There is one more attendee question from <a title="SQLSaturday 118" href="http://www.sqlsaturday.com/118/eventhome.aspx#" target="_blank">SQLSaturday #118</a> that I want to follow up on, and it is this: “Is there any way to create an index with a varchar(max) column as the leading column?”</p>
<p>This question came up during my <a title="Statistics at SQLSaturday 118" href="http://www.sqlsaturday.com/viewsession.aspx?sat=118&amp;sessionid=8067" target="_blank">Statistics</a> presentation, and was at the end as we were winding down.  My reply was, “I have no idea, I’ve never tried it.”</p>
<p>The attendee noted that he had tried to create the index but couldn’t – so it cannot be done – but he was looking to see if there was a creative way to work around it.  During the ensuing conversation he wondered if maybe it couldn’t be the leading column because the index would be too large, and then mentioned that he had ended up making in an included column in the index.  My question was, “Well if it’s an included column what does that do to the size of the index?”</p>
<p>Then I stopped and said something to the effect of, “Hang on, what is the problem you’re trying to solve?  Meaning, I’m guessing you’re trying to put a varchar(max) column in an index because you want to search on it.  Is making it an included column going to help that much?  I suppose you’ll get an index scan instead of a table scan, but is that really the right solution?”</p>
<p>My new favorite question to ask is, “What problem are you trying to solve?”  In this case, I assume that users need to search on the data in the varchar(max) field.  And this can be done in SQL Server a couple different ways.  My first thought was Full Text Search.  Now, configuring FTS is going to take more work than creating an index with an included column, but I would bet that performance and management long-term would be a lot easier.  You could also create a computed column on a substring of the varchar(max) column, and put that in an index.  There are many assumptions you have to handle here, most notably, is the data you want to search always in the same location within the original column?</p>
<p>I’m sure there are other options, but the overall point is this: understand what problem you’re trying to solve, and then figure out what options you have for solving it.  Once you have your options, understand the pros and cons of each, and then make an informed decision.</p>
<p>Circling back to the original question, one of the first things I tried when I was waiting at the Madison airport for my flight home was to create a table with a varchar(max) column and create an index with that as a leading column.  It of course failed, and <a title="CREATE INDEX" href="http://msdn.microsoft.com/en-us/library/ms188783.aspx" target="_blank">Books Online</a> clearly states:</p>
<blockquote><p>Columns that are of the large object (LOB) data types ntext, text, varchar(max), nvarchar(max), varbinary(max), xml, or image cannot be specified as key columns for an index.</p></blockquote>
<p>So there you have it, two presentations at SQLSaturday in Madison, and three blog posts from questions.  SQLSaturdays always reaffirm several things for me.  First, I am truly grateful for the SQL Community – the people, the opportunities, the fun…all of it.  Second, I love presenting, although I tend to think of it as teaching and even said during one of my sessions, “If you have questions please come ask me after class.”  Apparently I was having flashbacks to grad school.  And finally, I will never know enough; there is always so much more to learn.</p>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/j26ufY_kNvs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/05/varchar-max-index/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/05/varchar-max-index/</feedburner:origLink></item>
		<item>
		<title>sysrscols and Disabling Auto Update Statistics</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/GO0bUxf-_R0/</link>
		<comments>http://erinstellato.com/2012/04/sysrscols-disabling-auto-update-statistics/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 18:33:24 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Statistics]]></category>
		<category><![CDATA[sysrscols; rcmodified; auto update statistics]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=841</guid>
		<description><![CDATA[As I mentioned in my last post, one of the sessions I presented last weekend at SQLSaturday #118 was on statistics, and an interesting topic that came up toward the end of the session was the Auto Update Statistics option. I’ve blogged about this option before, and whether or not you leave it enabled for...]]></description>
			<content:encoded><![CDATA[<p>As I mentioned in my <a title="A Consideration When Rebuilding Corrupt Nonclustered Indexes" href="http://erinstellato.com/2012/04/consideration-when-rebuilding-corrupt-nonclustered-index/" target="_blank">last post</a>, one of the sessions I presented last weekend at <a title="SQLSaturday Madison" href="http://www.sqlsaturday.com/118/eventhome.aspx" target="_blank">SQLSaturday #118</a> was on statistics, and an interesting topic that came up toward the end of the session was the Auto Update Statistics option.</p>
<p>I’ve blogged about this option <a title="Statistics and Recompilations Part II" href="http://erinstellato.com/2012/02/statistics-recompilations-part-ii/" target="_blank">before</a>, and whether or not you leave it enabled for a database is not as cut and dried as to whether you leave the Auto Create Statistics option enabled (I’ve yet to personally find a reason to disable Auto Create Statistics).  The Auto Update Statistics option exists for the benefit of performance – when statistics are out of date, the engine will update them for you.  The engine knows when statistics are out of date because it tracks modifications to your data.  The method for tracking modifications <a title="Auto Update Statistics and Auto Create Statistics" href="http://www.sqlskills.com/blogs/kimberly/post/Auto-update-statistics-and-auto-create-statistics-should-you-leave-them-on-andor-turn-them-on.aspx" target="_blank">changed</a> between SQL 2000 and SQL 2005, and where the modifications are tracked changed between SQL 2005 and SQL 2008.  For this post, I’m just going to discuss SQL 2008 and higher.</p>
<p>Data modifications are tracked at the column level in SQL 2008 and higher in the hidden and undocumented sys.sysrscols system table, specifically in the rcmodified column.  During my statistics session last Saturday, one attendee asked if modifications were still tracked if the Auto Update Statistics was disabled for a database.  In short: Yes.</p>
<p>I admit, I didn’t know the answer off the top of my head – but my logic when I answered the question was that the setting exists at the database level and the engine is tracking modifications for tables and indexed views across numerous databases.  I didn’t expect that the engine would check the database Auto Update Statistics option for each modification, that’s just way too much overhead.  But then I wanted to know for sure so I came home and tested it.  The necessary statements are below, and the DAC is utilized (so if you don’t have it enabled, you’ll need to do that first).</p>
<p>Now, as I wrote this up, I wondered why the engine really continued to track it.  I don’t want to assume it is simply overhead, but it makes a lot of sense.  You can flip the Auto Update option at will, and you can also disable automatic updates at the table, index and statistic level.  If the engine had to reset the rcmodified column for a statistic, index, table or all tables in a database every time one of the settings changed, it could take time and would generate some level of overhead.  Ultimately, it’s just less work to continually track them, and presumably the engine is very efficient at tracking that information.</p>
<p>The script below can be used to show that data modifications are still tracked, even if the Auto Update Statistics option is disabled.  Realize that you’re playing with an undocumented system table and the DAC.  You’re off the grid, proceed with caution, and realize that the behavior you’re seeing could change in a future version.  If you want more details about sysrscols, I highly recommend Paul Randal’s post, <a title="How are per column modification counts tracked?" href="http://www.sqlskills.com/BLOGS/PAUL/post/How-are-per-column-modification-counts-tracked.aspx" target="_blank">How are per-column modification counts tracked?</a>  I admit, I used his query for sysrscols, but I did ask for permission first <img src='http://erinstellato.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<pre>

-- create a database for testing
CREATE DATABASE [NCI_Corruption]
ON PRIMARY (
NAME = N'NCI_Corruption',
FILENAME = N'C:\Databases\SQL2008R2\NCI_Corruption.mdf' ,
SIZE = 4096KB ,
FILEGROWTH = 1024KB )
LOG ON (
NAME = N'NCI_Corruption_log',
FILENAME = N'C:\Databases\SQL2008R2\NCI_Corruption_log.ldf' ,
SIZE = 1024KB ,
FILEGROWTH = 1024KB );

ALTER DATABASE [NCI_Corruption] SET RECOVERY SIMPLE;

USE NCI_Corruption;
GO

-- create a table
CREATE TABLE MovieInfoHistory (
MovieName VARCHAR(800),
ReleaseDate SMALLDATETIME,
Rating VARCHAR(5)
);

-- create an index
CREATE NONCLUSTERED INDEX NCI_MovieName ON dbo.MovieInfoHistory (MovieName);

-- connect with the DAC if not already...

-- check rcmodified - it should be 0
SELECT
p.[object_id],
p.[index_id],
rs.[rscolid],
rs.[rcmodified]
FROM sys.sysrscols rs
JOIN sys.partitions p ON rs.[rsid] = p.[partition_id]
WHERE p.[object_id] = OBJECT_ID ('MovieInfoHistory');

-- add some data
INSERT INTO dbo.MovieInfoHistory (
MovieName, ReleaseDate, Rating
)
VALUES
('Caddyshack', '1980-07-25', 'R'),
('Bill &amp; Ted''s Excellent Adventure', '1989-02-17 00:00:00', 'PG'),
('Apollo 13', '1995-05-30 00:00:00', 'PG'),
('The Hunt for Red October', '1990-03-02 00:00:00', 'PG'),
('A Few Good Men', '1994-12-11 00:00:00', 'R'),
('The Natural', '1984-05-11 00:00:00', 'PG'),
('The Truman Show', '1998-06-05 00:00:00', 'PG-13'),
('All The President''s Men', '1976-04-09 00:00:00', 'R'),
('The Right Stuff', '1983-10-21 00:00:00', 'PG-13');

CHECKPOINT;
GO

-- verify that rcmodified has increased
SELECT
p.[object_id],
p.[index_id],
rs.[rscolid],
rs.[rcmodified]
FROM sys.sysrscols rs
JOIN sys.partitions p ON rs.[rsid] = p.[partition_id]
WHERE p.[object_id] = OBJECT_ID ('MovieInfoHistory');

-- turn off auto update stats
ALTER DATABASE NCI_Corruption SET AUTO_UPDATE_STATISTICS OFF;

-- add some more data
INSERT INTO dbo.MovieInfoHistory (
MovieName, ReleaseDate, Rating
)
VALUES
('Miracle', '2004-02-06 00:00:00', 'PG'),
('Walk the Line', '2005-11-18 00:00:00', 'PG-13'),
('Bull Durham', '1988-06-15 00:00:00', 'R'),
('Field of Dreams', '1989-04-21 00:00:00', 'PG'),
('G.I. Jane', '1997-08-22 00:00:00', 'R'),
('St. Elmo''s Fire', '1985-06-28 00:00:00', 'R'),
('Goonies', '1985-06-07 00:00:00', 'TV14'),
('The Shawshank Redemption', '1994-10-14 00:00:00', 'R'),
('The Bad News Bears', '1976-04-07 00:00:00', 'PG');

CHECKPOINT;
GO

-- verify that rcmodified has increased again
SELECT
p.[object_id],
p.[index_id],
rs.[rscolid],
rs.[rcmodified]
FROM sys.sysrscols rs
JOIN sys.partitions p ON rs.[rsid] = p.[partition_id]
WHERE p.[object_id] = OBJECT_ID ('MovieInfoHistory');

-- clean up
USE master;
GO
DROP DATABASE NCI_Corruption;
</pre>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/GO0bUxf-_R0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/04/sysrscols-disabling-auto-update-statistics/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/04/sysrscols-disabling-auto-update-statistics/</feedburner:origLink></item>
		<item>
		<title>A Consideration When Rebuilding a Corrupt NonClustered Index</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/TJxhgEFzuug/</link>
		<comments>http://erinstellato.com/2012/04/consideration-when-rebuilding-corrupt-nonclustered-index/#comments</comments>
		<pubDate>Wed, 25 Apr 2012 13:00:05 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[CHECKDB]]></category>
		<category><![CDATA[SQLSaturday]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=826</guid>
		<description><![CDATA[This past weekend I was in Madison, WI for SQLSaturday #118 and it was a fantastic event.  Jes Borland ( b &#124; t ) and her team did a great job of hosting their first SQLSaturday and I was honored to present twice.  I presented a new session, DBCC Commands: The Quick and the Dangerous,...]]></description>
			<content:encoded><![CDATA[<p>This past weekend I was in Madison, WI for <a title="SQLSaturday 118" href="http://www.sqlsaturday.com/118/eventhome.aspx#" target="_blank">SQLSaturday #118</a> and it was a <a title="Jes' SQLSaturday 118 recap" href="http://blogs.lessthandot.com/index.php/ITProfessionals/ProfessionalDevelopment/sql-saturday-118-wisconsin-they" target="_blank">fantastic event</a>.  Jes Borland ( <a title="Jes' blog" href="http://blogs.lessthandot.com/index.php/All/?disp=authdir&amp;author=420" target="_blank">b</a> | <a title="Jes on Twitter" href="http://twitter.com//grrl_geek" target="_blank">t</a> ) and her team did a great job of hosting their first SQLSaturday and I was honored to present twice.  I presented a new session, DBCC Commands: The Quick and the Dangerous, and then my statistics session, You’re My Density: Making Sense of Statistics.  Both presentations went well, were well attended and had some great questions.  I received good feedback from some attendees as well, which is always appreciated.</p>
<p>There were three things that I wanted to follow up on from my presentations, and I’ll do that in this post and the next two.</p>
<p>The first item was mentioned in the DBCC session.  One of the commands I discuss in the session is DBCC CHECKDB, and I have a demo that shows corruption of a nonclustered index and how you can fix it.  If corruption strikes, you’re lucky if it only strikes in a nonclustered index, as it can be fixed without any data loss.  However, fixing the corruption is not the end of the issue.  You then need to make sure you perform root-cause analysis to understand why you had corruption to begin with (e.g. run checkdisk, look for other errors indicating problems with storage).</p>
<p>In order to fix the corruption you have to create a new copy of the index.  When you normally rebuild an index, the engine uses the existing copy of the index to create the new copy.  In the case of corruption in the index, it cannot do that.  I initially thought that I would have to drop and then create the index, and I didn’t love that option because if I didn’t know the index definition, I had to go look it up.  While it’s definitely possible, I was looking for something that required less work.  Remember, if you’re using SQL 2005 or higher, using sp_helpindex to look at index doesn’t tell you everything, as sp_helpindex doesn’t provide any information about included columns or filters (you need <a title="Kimberly Tripp's sp_helpindex rewrites" href="http://www.sqlskills.com/BLOGS/KIMBERLY/category/sp_helpindex-rewrites.aspx" target="_blank">Kimberly Tripp’s sp_helpindex</a> script for that).</p>
<p>Then I tested disabling the index and rebuilding it, and that worked!  Problem solved, as I didn’t have to figure out the index definition.  So I did a demo showing this when I was talking about the corruption in the nonclustered index, and Luke Jian ( <a title="Luke Jian's blog" href="http://blog.sqlpositive.com/" target="_blank">b</a> | <a title="Luke Jian on Twitter" href="http://www.twitter.com/sensware" target="_blank">t</a> ) mentioned that you had to be careful if you had a unique constraint in your index, as the time between the drop and create (or disable and rebuild) would leave the table vulnerable for data that violated the constraint to be inserted.  It was an excellent point and I’m glad he mentioned it.  Luke went on to say that this had come up during one of the <a title="SQLskills Immersion Events" href="http://www.sqlskills.com/ImmersionEvents.asp" target="_blank">SQLskills Immersion Events</a> he had attended (and he’s attended IE1, IE2 and IE3 might I add!) and another attendee had suggested wrapping the drop and create into a transaction to prevent an invalid insert.  It was a great learning moment for everyone, including me, and I thought it worth a post.</p>
<p>Remember, in this particular example I&#8217;m only working with corruption in the <em>nonclustered</em> index.  Do <strong>not</strong> disable a a clustered index that is corrupt, and do <strong>not</strong> drop a clustered index that is corrupt, as you will lose the entire table.</p>
<pre>

-- create a database for testing
CREATE DATABASE [NCI_Corruption]
ON PRIMARY (
NAME = N'NCI_Corruption',
FILENAME = N'C:\Databases\SQL2008R2\NCI_Corruption.mdf' ,
SIZE = 4096KB ,
FILEGROWTH = 1024KB )
LOG ON (
NAME = N'NCI_Corruption_log',
FILENAME = N'C:\Databases\SQL2008R2\NCI_Corruption_log.ldf' ,
SIZE = 1024KB ,
FILEGROWTH = 1024KB );

ALTER DATABASE [NCI_Corruption] SET RECOVERY SIMPLE;

USE NCI_Corruption;
GO

-- create a table
CREATE TABLE MovieInfoHistory (
MovieName VARCHAR(800),
ReleaseDate SMALLDATETIME,
Rating VARCHAR(5)
);

-- create the NCI
CREATE UNIQUE NONCLUSTERED INDEX NCI_MovieName ON dbo.MovieInfoHistory (MovieName);

-- add some data
INSERT INTO dbo.MovieInfoHistory (
MovieName, ReleaseDate, Rating
)
VALUES
('Caddyshack', '1980-07-25', 'R'),
('Bill &amp; Ted''s Excellent Adventure', '1989-02-17 00:00:00', 'PG'),
('Apollo 13', '1995-05-30 00:00:00', 'PG'),
('The Hunt for Red October', '1990-03-02 00:00:00', 'PG'),
('A Few Good Men', '1994-12-11 00:00:00', 'R'),
('The Natural', '1984-05-11 00:00:00', 'PG'),
('The Truman Show', '1998-06-05 00:00:00', 'PG-13'),
('All The President''s Men', '1976-04-09 00:00:00', 'R'),
('The Right Stuff', '1983-10-21 00:00:00', 'PG-13');

-- find a page in the NCI to corrupt
DBCC IND ('NCI_Corruption', 'dbo.MovieInfoHistory', 2);

-- take the database offline
USE master;
GO
ALTER DATABASE NCI_Corruption SET OFFLINE;

-- corrupt the Nonclustered Index (I tend to use a hex editor)

-- bring the database back online
USE master;
GO
ALTER DATABASE NCI_Corruption SET ONLINE;

USE NCI_Corruption;
GO

-- verify the corruption
DBCC CHECKTABLE ('dbo.MovieInfoHistory');

-- disable and rebuild the index within a transaction
BEGIN TRANSACTION;
ALTER INDEX NCI_MovieName ON dbo.MovieInfoHistory DISABLE;
ALTER INDEX NCI_MovieName ON dbo.MovieInfoHistory REBUILD;
COMMIT;

-- verify the corruption is gone
DBCC CHECKTABLE ('dbo.MovieInfoHistory');

-- clean up
USE master;
GO
DROP DATABASE NCI_Corruption;

&nbsp;
</pre>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/TJxhgEFzuug" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/04/consideration-when-rebuilding-corrupt-nonclustered-index/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/04/consideration-when-rebuilding-corrupt-nonclustered-index/</feedburner:origLink></item>
		<item>
		<title>Sorting Out the Error “Failed to perform data correlation”</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/8WxPEIqAnUo/</link>
		<comments>http://erinstellato.com/2012/03/failed-perfom-data-correlation/#comments</comments>
		<pubDate>Mon, 26 Mar 2012 13:00:54 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[import perfmon data; performance monitor; perfmon; failed to perform data correlation]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=784</guid>
		<description><![CDATA[While working with PerfMon data recently I ran into an interesting error when I tried to view it overlayed against a Trace file.  If you’re not familiar with that process, I recommend Brad McGehee’s article Correlating SQL Server Profiler with Performance Monitor.  I had opened a Trace file and selected a PerfMon file to import. ...]]></description>
			<content:encoded><![CDATA[<p>While working with PerfMon data recently I ran into an interesting error when I tried to view it overlayed against a Trace file.  If you’re not familiar with that process, I recommend Brad McGehee’s article <a title="Correlating SQL Server Profiler with Performance Monitor" href="http://www.simple-talk.com/sql/database-administration/correlating-sql-server-profiler-with-performance-monitor/" target="_blank">Correlating SQL Server Profiler with Performance Monitor</a>.  I had opened a Trace file and selected a PerfMon file to import.  I selected about five counters and soon after the import started, then I got the error message:</p>
<div id="attachment_787" class="wp-caption aligncenter" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/Profiler-Error.jpg"><img class="size-full wp-image-787" title="Profiler Error after attempted import" src="http://erinstellato.com/wp-content/uploads/2012/03/Profiler-Error.jpg" alt="Failed to perform data correlation" width="300" height="171" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Profiler Error</p></div>
<p>And the PerfMon data looked like this in Profiler:</p>
<div id="attachment_789" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/ProfilerandPerfMon_truncated_21.jpg"><img class="size-large wp-image-789 " title="Truncated PerfMon data in Profiler" src="http://erinstellato.com/wp-content/uploads/2012/03/ProfilerandPerfMon_truncated_21-500x353.jpg" alt="Truncated PerfMon data in Profiler" width="500" height="353" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Truncated PerfMon data in Profiler (click to see larger)</p></div>
<p>I hadn’t seen that message before and the output was then somewhat useless since I couldn’t compare the PerfMon data with Trace in that format after 6:30 AM.  I took another set of PerfMon and Trace files and tried to the import again.  Same message.  I decided to dig in and see if I could figure it out.</p>
<p>I loaded a third set of PerfMon and Trace, same thing.  I checked to see if the data cut off at the same time in each trace and it didn’t.</p>
<p>Then I tried to load just one counter at a time.  I started with %Processor Time_Total, I have no idea why I picked that counter first, but when I went to click OK, it was grayed out:</p>
<div id="attachment_790" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/Processor_noOK.jpg"><img class="size-large wp-image-790" title="Nope, cannot select &quot;OK&quot;" src="http://erinstellato.com/wp-content/uploads/2012/03/Processor_noOK-500x469.jpg" alt="Nope, cannot select &quot;OK&quot;" width="500" height="469" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Nope, cannot select &quot;OK&quot;</p></div>
<p>Interesting.  I selected another counter and the OK button became available so I selected OK to import the data and got the error message again.  I started over.  After I selected the %Processor Time_Total counter, I selected another counter, then unselected it.  The OK button was now available:</p>
<div id="attachment_791" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/Processor_withOK.jpg"><img class="size-large wp-image-791" title="OK is now available" src="http://erinstellato.com/wp-content/uploads/2012/03/Processor_withOK-500x469.jpg" alt="OK is now available" width="500" height="469" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">OK is now available</p></div>
<p>I imported the data, and I got the error again.  Then I zoomed in on the PerfMon graph to see the timestamp for when it stopped:</p>
<div id="attachment_793" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/ProfilerandPerfMon_zoomed.jpg"><img class=" wp-image-793 " title="Zoomed in to find the timestamp" src="http://erinstellato.com/wp-content/uploads/2012/03/ProfilerandPerfMon_zoomed-500x300.jpg" alt="Zoomed in to find the timestamp" width="500" height="300" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Zoomed in to find the timestamp (click to see larger)</p></div>
<p>At that point, I knew the issue was with data somewhere between 6:40:05 and 6:40:20.  Next I read the data directly from the PerfMon trace, which I had loaded into a database table using relog.  I found this:</p>
<div id="attachment_794" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/PerfMondata.jpg"><img class="size-large wp-image-794 " title="PerfMon data up close" src="http://erinstellato.com/wp-content/uploads/2012/03/PerfMondata-500x266.jpg" alt="PerfMon data up close" width="500" height="266" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">PerfMon data up close (click to see larger)</p></div>
<p>There were two samples taken at 6:40:10, three milliseconds apart.  I have to conclude that for some reason, that causes the import to fail, because when I checked the other files, I found the same thing: multiple entries for the same second, taken milliseconds apart.</p>
<p>There is a fix for this.  I used the relog utility to split out the original file into two files, excluding the data sampled at 6:40:10, and then merged the files back into one.</p>
<p>&nbsp;</p>
<p style="padding-left: 30px;"><em>separate the file:</em></p>
<p style="padding-left: 30px;">relog PerfMon_20120309.blg -b 03/09/2012 03:35:00 -e 03/09/2012 06:40:10 -o PartI.blg</p>
<p style="padding-left: 30px;">relog PerfMon_20120309.blg -b 03/09/2012 06:40:15 -e 03/09/2012 18:35:00 -o Part2.blg</p>
<p style="padding-left: 30px;"><em>merge files:</em></p>
<p style="padding-left: 30px;">relog Part1.blg Part2.blg -o PerfMon_20120309_Fixed.blg</p>
<p>&nbsp;</p>
<p>Not elegant, but possible.  Once I did that, I could import all the data for % Processor Time_Total:</p>
<div id="attachment_795" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/ProfilerandPerfMon_fixed.jpg"><img class=" wp-image-795 " title="Everything except 6:40:10 in the graph" src="http://erinstellato.com/wp-content/uploads/2012/03/ProfilerandPerfMon_fixed-500x337.jpg" alt="Everything except 6:40:10 in the graph" width="500" height="337" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Everything except 6:40:10 in the graph (click to see larger)</p></div>
<p>Even though I have a way to fix this problem, this is not a solution.  The solution is to not have bad data to begin with.  If I were consistently working with this customer’s data, I would dig in and try to figure out what was causing the bad sampling.  It’s not likely that I will have the opportunity to do that, but should I run into this problem again, at least I have a quick fix, and maybe I will have the time then to figure out what’s really going on.</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/8WxPEIqAnUo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/03/failed-perfom-data-correlation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/03/failed-perfom-data-correlation/</feedburner:origLink></item>
		<item>
		<title>Isolation Levels and the Effects on Select Statements, Part II</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/bbXGdWYZvfc/</link>
		<comments>http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements-part-ii/#comments</comments>
		<pubDate>Thu, 15 Mar 2012 13:00:41 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[SQLSequel]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=746</guid>
		<description><![CDATA[Last week I wrote a post on Isolation Levels and the Effects on Select Statements, and I had a conversation on Twitter with Rob Farley ( b &#124; t ) regarding one of my explanations.  For READ COMMITTED, I had written the following: If data is being modified by a transaction, any subsequent select statement...]]></description>
			<content:encoded><![CDATA[<p>Last week I wrote a post on <a title="Isolation Levels and the Effects on Select Statements" href="http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements/" target="_blank">Isolation Levels and the Effects on Select Statements</a>, and I had a conversation on Twitter with Rob Farley ( <a title="Rob Farley's blog" href="http://sqlblog.com/blogs/rob_farley/default.aspx" target="_blank">b</a> | <a title="Rob on Twitter" href="http://www.twitter/rob_farley" target="_blank">t</a> ) regarding one of my explanations.  For READ COMMITTED, I had written the following:</p>
<blockquote><p>If data is being modified by a transaction, any subsequent select statement that occurs before the modification is complete will read the original copy of the data (not the modified data).</p></blockquote>
<p>Rob asked me to read it again, and I realized that this explanation was not accurate for READ COMMITTED.  In fact, what I described was the SNAPSHOT isolation level.</p>
<p>What I should have said for READ COMMITTED was:</p>
<blockquote><p>If data is being modified by a transaction, any subsequent select statement that occurs before the modification is complete will wait until the transaction commits or rolls back to read the data.</p></blockquote>
<p><em>(I have noted and modified my original post with this information.)</em></p>
<p>To be clear, in a READ COMMITTED isolation level, you will only read committed data.  This is different than in the READ UNCOMMITTED isolation level, where can you read uncommitted, or dirty, data.</p>
<p>Here’s a quick example using the HumanResources.Employees table in the AdventureWorks database.  Let&#8217;s look at the output if I select from the table.  Notice that for EmployeeID 3, the Title is Engineering Manager.</p>
<div id="attachment_753" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/output1.jpg"><img class="size-large wp-image-753" title="Original output from Employees table" src="http://erinstellato.com/wp-content/uploads/2012/03/output1-500x86.jpg" alt="Original output from Employees table" width="500" height="86" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Original output from Employees table</p></div>
<p>In one query window, I run the following:</p>
<pre>

USE AdventureWorks;
GO

BEGIN TRANSACTION;
UPDATE HumanResources.Employee
SET Title = 'Senior Engineering Manager'
WHERE EmployeeID = 3;
</pre>
<p>Notice that I haven&#8217;t committed the data yet.  Also notice that I didn&#8217;t set the isolation level, and that&#8217;s because the isolation level of the UPDATE does not affect what happens when I SELECT.<em></em></p>
<p>Now I open a second query window and run the following:</p>
<pre>

USE AdventureWorks;
GO

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
GO

SELECT * FROM HumanResources.Employee;
</pre>
<p>What happens?  I wait.  And I wait.  And I wait.  This query will continue to wait until I either COMMIT or ROLLBACK my UPDATE statement.  Once I do that, the results will return.  But in this case, let&#8217;s kill the query, and then run the following statements:</p>
<pre>

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
GO

SELECT * FROM HumanResources.Employee;
</pre>
<p>Now I get data back, and notice that the value for EmployeeID 3 is now Senior Engineering Manager, even though that data hasn&#8217;t been committed yet.  Yuck.  A dirty read.</p>
<div id="attachment_754" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/output21.jpg"><img class="size-large wp-image-754" title="Output after a dirty read" src="http://erinstellato.com/wp-content/uploads/2012/03/output21-500x88.jpg" alt="Output after a dirty read" width="500" height="88" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Output after a dirty read</p></div>
<p>Feel free to change the isolation level for the UPDATE statement to prove out that it doesn&#8217;t affect what happens when you SELECT &#8211; and take it a step further by checking out the lock that gets taken with the SELECT in both isolation levels (I use sp_lock &lt;SPID&gt;).  Have fun!</p>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/bbXGdWYZvfc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements-part-ii/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements-part-ii/</feedburner:origLink></item>
		<item>
		<title>Gratitude</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/79DX8IMJoRk/</link>
		<comments>http://erinstellato.com/2012/03/gratitude/#comments</comments>
		<pubDate>Fri, 09 Mar 2012 14:29:27 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Presenting]]></category>
		<category><![CDATA[living life; community; user group]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=742</guid>
		<description><![CDATA[Yesterday afternoon I drove up to Southfield, Michigan to present to the Southeast Michigan SQL Server User Group.  Joe Fleming contacted me and asked if I would present my Baselines session, which I presented at the PASS Summit last fall.  I usually don’t pass up a chance to go to Michigan, and this was the...]]></description>
			<content:encoded><![CDATA[<p>Yesterday afternoon I drove up to Southfield, Michigan to present to the <a title="Southeast Michigan SQL Server User Group" href="http://semssug.sqlpass.org/" target="_blank">Southeast Michigan SQL Server User Group</a>.  <a title="Joe Fleming on Twitter" href="http://www.twitter.com/muadDBA" target="_blank">Joe Fleming</a> contacted me and asked if I would present my Baselines session, which I presented at the PASS Summit last fall.  I usually don’t pass up a chance to go to Michigan, and this was the first time I presented in front of a different user group.  I’ve presented at many SQLSaturdays, but user groups have a different vibe.  It’s a regular meeting for attendees and it is typically only one presentation.  I haven’t presented since the Summit so it was nice to finally speak again.  I’ve missed it!  The group was very diverse in terms of experience and it was a great group (somewhere between 40 and 50 people).  I had a lot of good questions, including some new ones, and one of the attendees from last night emailed me this morning to let me know that the session was helpful for him.  It was fun, and this morning I realized that I have missed it.  Luckily, I’ve been accepted to speak at <a title="SQLSaturday Madison" href="http://www.sqlsaturday.com/118/eventhome.aspx" target="_blank">Madison’s SQLSaturday</a> in April, and I’ve also submitted for <a title="SQLSaturday Chicago" href="http://www.sqlsaturday.com/119/eventhome.aspx" target="_blank">Chicago</a>.  I’m not sure what else will be on the agenda this year, but I hope to be speaking a fair bit.  And Joe, thanks again for the invite.</p>
<p>On a personal note, I was looking forward to this trip because after the meeting I was planning to go to Ann Arbor to see my friend and mentor, <a title="83" href="http://erinstellato.com/2011/03/sb/" target="_blank">Susan</a>.  As I write, I’m in a hotel in Farmington Hills because as I was leaving yesterday, I received a call from one of her graduate students explaining that she was in the hospital.  … … &#8230; I didn’t see that one coming.  She is ok, and should be fine long term, but it was a bit of a wake up for me.  Life is short.  You all know this, right?  You do.  But I’ve been thinking about this all morning, which meant I couldn’t let it go and just needed to say what was on my mind.</p>
<p>In my pocket I carry a glass stone with the quote, “Let us live while we live.” (Phillip Doddridge)  It is a reminder to live in the moment, and to live life fully.  In 50 years I don’t want any regrets about things I wish I would have done.  Last night I thought about driving back home, but I was really tired, and I wanted to try and see Susan today, because you <em>just never know</em>.  She’s probably fine, in all honesty, but what if she’s not?</p>
<p>So today, I encourage you to enjoy <em>your</em> life and the people that are in it.  If there’s something that’s missing, go find it.  If there’s something that you’ve wanted to do but are too afraid, get over that hurdle and go do it.  Life is meant to be lived, to be enjoyed.  It’s not always easy, but without a doubt, it’s all worth it.</p>
<p>Thanks for reading.  Now I’m off to Ann Arbor to see Susan, go to <a title="Zingerman's" href="http://www.zingermansdeli.com/?utm_source=mailorder&amp;utm_medium=zinglink&amp;utm_campaign=zcobbar" target="_blank">Zingerman’s</a>, and pick up some Michigan gear.  Happy Friday all – go tackle the day!</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/79DX8IMJoRk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/03/gratitude/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/03/gratitude/</feedburner:origLink></item>
		<item>
		<title>Isolation Levels and the Effects on Select Statements</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/6T61cbPATSA/</link>
		<comments>http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements/#comments</comments>
		<pubDate>Wed, 07 Mar 2012 14:10:33 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Internals]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=719</guid>
		<description><![CDATA[Database locking is a fundamental concept in SQL Server that every Database Administrator and Database Developer should understand.  SQL Server has a pessimistic locking model because it was built for an OLTP environment and assumes that updates will occur frequently.  For a developer, this is important to understand in terms of concurrency: how many users...]]></description>
			<content:encoded><![CDATA[<p>Database locking is a fundamental concept in SQL Server that every Database Administrator and Database Developer should understand.  SQL Server has a pessimistic locking model because it was built for an OLTP environment and assumes that updates will occur frequently.  For a developer, this is important to understand in terms of <a title="Concurrency Effects" href="http://msdn.microsoft.com/en-us/library/ms190805.aspx" target="_blank">concurrency</a>: how many users can access the same data simultaneously.  In some cases, you may want concurrency to be high (many people can access the same data at the same time); in other cases you may want concurrency to be low (only one person can access the data at any given time).  A developer must know what level of concurrency is needed, the effects that concurrency has in the database (locks) and how concurrency affects user activity and processing.  A DBA must also understand concurrency, the locking that occurs in a database, how locking can lead to blocking and how to troubleshoot blocking issues.</p>
<p>The isolation level for a database connection directly affects the type of lock that is taken for a read operation, and therefore affects concurrency.  I bring this up because I’ve seen people inadvertently create blocking in a database because they do not understand properties for their database connection.  I don’t want to repeat Books Online, but let’s take a minute to review the more common <a title="SET TRANSACTION ISOLATION LEVEL" href="http://msdn.microsoft.com/en-us/library/ms173763%28v=sql.105%29.aspx" target="_blank">isolation levels</a> in SQL Server.</p>
<p><strong>READ COMMITTED</strong></p>
<p>This is the default isolation level in SQL Server.  When you initiate any connection to SQL Server (e.g. from Management Studio), this isolation level will be used.  In a READ COMMITTED isolation level:</p>
<ul style="padding-left: 30px;">
<li>If data is being modified by a transaction, any subsequent select statement that occurs before the modification is complete will wait until the transaction commits or rolls back to read the data. <em>(Note: this statement has been modified since the original post, please see <a title="Isolation Levels and the Effects on Select Statements, Part II" href="http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements-part-II/" target="_blank">Isolation Levels and the Effects on Select Statements, Part II</a> for more details.)</em></li>
<li>Select statements create shared locks which are released as soon as the data is read. If a shared lock exists, data cannot be modified until the lock is released (for more information see <a title="Lock Modes" href="http://msdn.microsoft.com/en-us/library/ms175519.aspx" target="_blank">Lock Modes</a> in BOL).  <em>Under the right circumstances, this can lead to blocking.</em></li>
</ul>
<div id="attachment_731" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/StarWarsline.jpg"><img class="size-large wp-image-731 " title="Lead blocker" src="http://erinstellato.com/wp-content/uploads/2012/03/StarWarsline-500x332.jpg" alt="Lead blocker" width="500" height="332" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Lead blocker</p></div>
<p><strong>READ UNCOMMITTED</strong></p>
<p>This the most optimistic isolation level in SQL Server, and in order to utilize it, the SET TRANSACTION ISOLATION LEVEL statement must be executed when a connection is made.  In a READ UNCOMMITTED isolation level:</p>
<ul style="padding-left: 30px;">
<li>If data is being modified by a transaction, any subsequent select statement that occurs before the modification is complete will read the modified copy of the data. This is known as a dirty read.</li>
</ul>
<p>Note: You can create the same behavior by using the <a title="Table Hints" href="http://msdn.microsoft.com/en-us/library/ms187373.aspx" target="_blank">NOLOCK hint</a> in queries.  That is not something I would recommend, and NOLOCK is another debate for another time.</p>
<div id="attachment_732" class="wp-caption aligncenter" style="width: 387px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/StarWarsread.jpg"><img class="size-large wp-image-732" title="A dirty read" src="http://erinstellato.com/wp-content/uploads/2012/03/StarWarsread-377x500.jpg" alt="A dirty read" width="377" height="500" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">A dirty read</p></div>
<p><strong>SNAPSHOT</strong></p>
<p>This isolation level was added in SQL Server 2005, and is considered a good hybrid of READ COMMITTED and READ UNCOMMITTED as it requires that data that is read during a select statement will be the same value that existed when the transaction started.  In a SNAPSHOT isolation level:</p>
<ul style="padding-left: 30px;">
<li>If an insert, update or delete statement does not commit <em>before</em> the select statement begins, then the output from the select will show the original values.</li>
<li>Locks are not taken when reading data (unless a database is being recovered).</li>
</ul>
<p>This isolation level requires setting the ALLOW_SNAPSHOT_ISOLATION database option to ON.</p>
<p><strong>What to remember</strong></p>
<p>As a DBA, it’s important to recognize that when you open Management Studio (SSMS) and open a query window to a database and start to <em>query</em> that database, you can affect the type of locks being taken.  If you run a select statement which takes 10 minutes to return data, you may block other activity in the database.  If you’re troubleshooting a problem, you might make it worse.  If you’re just looking at data, or writing some reports against production, you might create a problem.</p>
<p><strong>What you can do</strong><span style="text-decoration: underline;"><br />
</span></p>
<p>If you’re writing reports, don’t do it against production.  A good DBA restores backups on a regular basis.  Restore a recent backup of production and write reports against it.  Don’t have the space to restore production?  Utilize a test, development, QA or UA environment and write the reports there.  If the database is not comparable in size and/or data distribution to production, at some point you <em>will</em> need to do performance testing so you can make sure the reports are optimized.  At that time, you really want to find the space to restore that recent production backup, even if it’s only available to you for a couple days of testing.  In six months, you do not want to explain why the reports you wrote are causing performance issues in production.</p>
<p>If you’re just selecting data to troubleshoot or look at data, and are not concerned about dirty reads, you can change the isolation level in SSMS.  You must do this each time you open a new query window by executing</p>
<pre>

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
</pre>
<p>For subsequent queries issued in that session, the isolation level will be READ UNCOMMITTED. Again, realize that this must be set for each new query window you open.</p>
<p>Alternatively, you can change the default isolation for SSMS connections. I don’t recommend doing this for <em>every</em> SSMS installation in your environment.  I would only change this on the SSMS installed on my own machine, to which only I access, so that I am the only person affected if I start to see unexpected results.</p>
<p>Within SSMS, select <strong>Tools</strong> | <strong>Options</strong>. Then select <strong>Query Execution</strong> | <strong>SQL Server</strong> | <strong>Advanced</strong>. In the <strong>SET TRANSACTION ISOLATION LEVEL</strong> drop down, change the value to <strong>READ UNCOMMITTED</strong>. Select <strong>OK</strong>. All new sessions will have an isolation level of READ UNCOMMITTED.</p>
<div id="attachment_730" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/SSMS-concurrency-22.png"><img class="size-large wp-image-730" title="Changing default isolation in SSMS" src="http://erinstellato.com/wp-content/uploads/2012/03/SSMS-concurrency-22-500x287.png" alt="Changing default isolation in SSMS" width="500" height="287" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Changing default isolation in SSMS</p></div>
<p><strong>What about Oracle?</strong></p>
<p>As you may or may not know, the application which I support can also run on Oracle.  There are numerous differences between SQL Server and Oracle, including isolation levels.  Oracle has an optimistic locking model because it assumes that users spend more time reading data than modifying it.  Oracle utilizes two isolation levels to manage data concurrency and consistency: READ COMMITTED and SERIALIZABLE (see <a title="Data Concurrency and Consistency" href="http://docs.oracle.com/cd/B28359_01/server.111/b28318/consist.htm">Data Concurrency and Consistency</a> for more information).</p>
<p>The default isolation level is READ COMMITTED and when you initiate any connection to Oracle (e.g. from SQLPlus), this isolation level will be used.  In the READ COMMITTED isolation level:</p>
<ul>
<li>When a select statement is issued in Oracle, there are no locks taken on the rows being read.</li>
</ul>
<p>This behavior is <em>very</em> different than SQL Server. A select statement in Oracle should never block a data modification, and a data modification should not block a select statement either.  Within the Oracle community, the phrase is simply: Readers don’t block writers and writers don’t block readers.  In a SQL Server database, you can create the same behavior by using the SNAPSHOT isolation level.</p>
<div id="attachment_727" class="wp-caption aligncenter" style="width: 510px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://erinstellato.com/wp-content/uploads/2012/03/StarWarsOracle.jpg"><img class="size-large wp-image-727" title="It's Oracle, no one is bothering anyone else" src="http://erinstellato.com/wp-content/uploads/2012/03/StarWarsOracle-500x335.jpg" alt="It's Oracle, no one is bothering anyone else" width="500" height="335" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">It&#39;s Oracle, no one is bothering anyone else</p></div>
<p>As such, I have seen only two blocking issues in Oracle in all the years I’ve worked with it, but I’ve seen numerous blocking issues in SQL Server.  In Oracle, both issues occurred because the connection was lost during the middle of an update, and the lock taken by the update blocked subsequent updates to that same data.</p>
<p><strong>Additional resources</strong></p>
<p>In this post I wanted to focus on what a DBA should remember when connecting to a production database, as it relates to isolation level.  I have merely touched upon the impact of isolation level, and if you want to read more, I highly recommend Kendra Little’s isolation levels <a title="Brent Ozar PLF Isolation Levels" href="http://BrentOzar.com/go/Isolation" target="_blank">resource page</a> for more information.</p>
<p>&nbsp;</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/6T61cbPATSA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/03/isolation-levels-effects-on-select-statements/</feedburner:origLink></item>
		<item>
		<title>Statistics and Recompilations, Part II</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/23FAogqRigo/</link>
		<comments>http://erinstellato.com/2012/02/statistics-recompilations-part-ii/#comments</comments>
		<pubDate>Wed, 22 Feb 2012 14:00:03 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Customers]]></category>
		<category><![CDATA[SQLSequel]]></category>
		<category><![CDATA[Statistics]]></category>
		<category><![CDATA[Vendors]]></category>
		<category><![CDATA[statistics; recompile; auto update statistics;]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=711</guid>
		<description><![CDATA[I recently blogged about an interesting behavior in SQL Server when the database option, Auto Update Statistics, is disabled…and that post requires a sequel.  The summary is that when you have the Auto Update Statistics option disabled for a database, query plans for tables are not recompiled when their statistics are updated.  There is an...]]></description>
			<content:encoded><![CDATA[<p>I <a title="Statistics and Recompilations" href="http://erinstellato.com/2012/01/statistics-recompilations/">recently blogged</a> about an interesting behavior in SQL Server when the database option, Auto Update Statistics, is disabled…and that post requires a sequel.  The summary is that when you have the Auto Update Statistics option disabled for a database, query plans for tables are not recompiled when their statistics are updated.  There is an <a title="Execution Plan Caching and Reuse" href="http://msdn.microsoft.com/en-us/library/ms181055.aspx">exception</a> for the inserted and deleted tables that are created by DML INSTEAD OF triggers, but overall this database setting can have a significant impact on a system, which I alluded to in my previous post.  In a customer system I found a query that was doing a full table scan and required 32,000 reads, even though the predicate was unique and statistics had been updated that day with 100% sample.  The SQL Server instance had not been restarted since December (about 45 days before my discovery) and the customer had gone live in December.  My theory was that the full scan query plan was created by the optimizer in December, when there was no data in the system.  The query was executed regularly and never dropped out of the plan cache, therefore it was still being used in January even though by that point there were millions of rows in the table.  To test this, I found the query handle for the plan, and then dropped just that plan from cache.  Immediately I searched for a new query plan for that query, and found the index seek I expected.  The 32,000 read query no longer appeared in the trace I was running.</p>
<p>Now I’m faced with the challenge of figuring out what to recommend to our customers going forward.  For many years we have recommended that customers have Auto Update Statistics disabled, and I listed the reasons previously:</p>
<ul>
<li>We do not want statistics updating during production hours if at all possible; we want the customer to manage statistics through a regularly scheduled job.</li>
<li>We want statistics updated with 100% sample because very often the distribution in critical tables is skewed.  With Auto Update Statistics enabled, the statistics do not update with 100% sample unless the table is less than 8 MB in size.</li>
</ul>
<p>We cannot continue to make the same recommendation unless we provide more information about the ramifications (notably query plans are not recompiled by an update of statistics); it would be irresponsible of us to not mention this.  Alternatively, we could change our viewpoint entirely and recommend that customers enable Auto Update Statistics.</p>
<p>After a lot of thought, the recommendation is going to go away completely.  That is, we’re going to tell customers that they can either enable or disable the option, it’s their choice and it depends on how they want to manage statistics.  I feel that we need to provide an explanation to customers about why our recommendation has changed, and I also I believe we need to provide a few suggestions on how to manage statistics.  The challenge here is that so many of our customers do not have a full time DBA.  Very often, the application administrator acts as the DBA.  The application administrator will probably not have the time, nor the inclination, to manage statistics at the detailed level to which a full time Production DBA would.  Is there a set of maintenance and configuration options that we can suggest that will work for the Accidental DBA?</p>
<p>Here are the options I have developed, and please read through the entire rest of the post before adding a comment if you disagree:</p>
<p><span style="text-decoration: underline;">Option 1</span></p>
<ol>
<li>Disable Auto Update Statistics for the database</li>
<li>Create a job to update index and column level statistics with 100% sample on a regular basis (or rebuild indexes + update column statistics with 100% sample on a regular basis)</li>
<li>Clear procedure cache or restart the instance after the update of statistics is complete</li>
</ol>
<p><span style="text-decoration: underline;">Option 2*</span></p>
<ol>
<li>Disable Auto Update Statistics for the database</li>
<li>Before running any update statistics jobs, enable the Auto Update Statistics for the database.</li>
<li>Create a job to update index and column level statistics with 100% sample on a regular basis (or rebuild indexes + update column statistics with 100% sample on a regular basis)</li>
<li>When the job is complete, disable the Auto Update Statistics for the database</li>
</ol>
<p>*Joe Fleming ( <a title="Joe Fleming on Twitter" href="https://twitter.com/#!/muaddba">t</a> ) initially proposed this option in the comments of my original post</p>
<p><span style="text-decoration: underline;">Option 3</span></p>
<ol>
<li>Enable Auto Update Statistics for the database</li>
<li>Create a job to update index and column level statistics with 100% sample on a regular basis (or rebuild indexes + update column statistics with 100% sample on a regular basis)</li>
</ol>
<p>Before you skip straight to the comments to disagree, hear me out.  Remember that the majority of customers are <em>not</em> 24/7 shops, and do not have a full time DBA.  These customers have databases less than 250 GB, and can take the hit of rebuilding every index and updating statistics every week, every other week or once a month.  Is it overkill?  Probably.  But it works for the majority, which is what we have to target.</p>
<p>Do I love the option of clearing query cache?  No, <em>not at all</em>.  That suggestion probably gives many people a heart attack.  I understand.  We can try to mitigate the effect a bit by just clearing the cache for the one database (DBCC FLUSHPROCINDB(&lt;db_id&gt;)).  But yes, clearing the cache will cause every query to be freshly compiled, and this will utilize a lot more CPU, it will cause query duration to go up initially, and it will affect overall performance.  I get that.  But for a system that is not managed by a full time DBA, I will take this hit in order to ensure that the query plans are based on the current set of data.</p>
<p>Now, the ideal option is:</p>
<p><span style="text-decoration: underline;">Option 4</span></p>
<ol>
<li>Enable Auto Update Statistics for the database</li>
<li>Create a job to rebuild indexes and update statistics on a regular basis, dependent upon the level of fragmentation in an index and the need to update statistics because of changes to the data</li>
</ol>
<p>This option is appropriate for any customer with a full time DBA who is comfortable managing fragmentation and statistics through custom scripts and jobs.  For example, many DBAs use Ola Hallengren’s <a title="Ola Hallengren's script" href="http://ola.hallengren.com/sql-server-index-and-statistics-maintenance.html">Index and Statistics Maintenance script</a>, or Michelle Ufford’s <a title="Michelle Ufford's Index Defrag script" href="http://sqlfool.com/2011/06/index-defrag-script-v4-1/">Index Defrag script</a>.  To take things a step further, you can monitor when an automatic update of statistics occurs (use the <a title="Auto Stats Event Class in Trace" href="http://msdn.microsoft.com/en-us/library/ms190721.aspx">Auto Stats Event Class</a> in Trace), and you can capture snapshots of table row counts (<a title="sys.partitions" href="http://msdn.microsoft.com/en-us/library/ms175012.aspx">sys.partitions</a>) and index updates (<a title="sys.dm_db_physical_stats" href="http://msdn.microsoft.com/en-us/library/ms188755.aspx">sys.dm_db_index_usage_stats</a>) to understand what tables have data that changes frequently.  High volume or volatile tables (those with a lot of inserts, updates and deletes) may require a more aggressive approach to managing statistics.</p>
<p>Ultimately, there is no silver bullet…no one perfect answer, unless that answer is “It depends.”  But again, you have to know what “it” depends on.  In this case, whether you should have the Auto Update Statistics option enabled or disabled for a database depends on your ability to manage statistics for a database, and understanding that having it disabled can lead to out of date query plans.</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/23FAogqRigo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/02/statistics-recompilations-part-ii/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/02/statistics-recompilations-part-ii/</feedburner:origLink></item>
		<item>
		<title>Vendor Feedback</title>
		<link>http://feedproxy.google.com/~r/ErinStellato_TheSqlSequel/~3/LcIZwN3rJko/</link>
		<comments>http://erinstellato.com/2012/02/vendor-feedback/#comments</comments>
		<pubDate>Thu, 09 Feb 2012 05:44:56 +0000</pubDate>
		<dc:creator>Erin Stellato</dc:creator>
				<category><![CDATA[Customers]]></category>
		<category><![CDATA[The Community]]></category>
		<category><![CDATA[Vendors]]></category>

		<guid isPermaLink="false">http://erinstellato.com/?p=707</guid>
		<description><![CDATA[I don’t know how many of you receive the SQLskills Insider email (sign up here), but if you know me, you know I’m a fan of SQLskills so of course I’m on the distribution list.  Anyway, in Monday’s email Paul Randal talked about application vendors and how he frequently hears about incorrect configuration recommendations made...]]></description>
			<content:encoded><![CDATA[<p>I don’t know how many of you receive the SQLskills Insider email (sign up <a title="SQLskills Insider sign up" href="http://www.sqlskills.com/JoinCommunity.asp">here</a>), but if you know me, you know I’m a fan of SQLskills so of course I’m on the distribution list.  Anyway, in Monday’s email <a title="Paul on Twitter" href="http://www.twitter.com/paulrandal">Paul Randal</a> talked about application vendors and how he frequently hears about incorrect configuration recommendations made by vendors that utilizes SQL Server as their RDBMS.  One example that Paul gave is the recommendation to shrink the database on a regular basis.  Since I work for a vendor, the topic hit close to home, and my immediate thought was, “Is there anything we’re recommending that is incorrect?”  I don’t think so.  And I say that because I have written a majority of our database documentation and have personally reviewed some of those recommendations with experts within the community.  I do believe we do a good job of not only providing recommendations, but including explanations as to why we have certain recommendations.</p>
<p>However, I am not infallible and if I had recommended something that was not in line with a Microsoft best practice or other well-known recommendation, I would want to know.  And this was Paul’s call to action in the email:</p>
<blockquote><p>Next time you come across some guidance from a vendor that is clearly wrong or misleading, call them on it! Education is the key to getting things like this fixed.</p></blockquote>
<p>I completely agree.  If I am wrong, I want to know.  And if I am wrong and spreading misinformation to thousands of customers, I absolutely must know about it.  But I do have one request: be nice about it.  I have no problem admitting when I’m wrong.  I won’t be happy with myself, but I will admit it and will be appreciative, even if someone is very smug or condescending.  But it doesn’t have to be that way.  There is a civil way to point out when someone is wrong – this is true in life, not just vendor recommendations.  As a DBA, you wouldn’t like me too much if I pointed out that your backups were going to the same set of disks as your database and then said, “What were you thinking?”</p>
<p>So when you do find an error, get your data, present your case, and view the discussion as a partnership.  You’re trying to help the vendor, and hopefully they will recognize that and realize the value in you as a DBA and customer.  I truly enjoy some of the relationships I have developed with customer DBAs on both a personal and professional level.  And on a professional level, that relationship can benefit both parties.  They have a direct line to me and can email questions, I have a direct line to them and can ask them to check something in their database, or try something in their environment if they’re willing.  Is that relationship atypical?  Yes.  Is it possible?  Absolutely.</p>
<img src="http://feeds.feedburner.com/~r/ErinStellato_TheSqlSequel/~4/LcIZwN3rJko" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erinstellato.com/2012/02/vendor-feedback/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://erinstellato.com/2012/02/vendor-feedback/</feedburner:origLink></item>
	</channel>
</rss><!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: enhanced
Object Caching 1441/1553 objects using disk: basic

Served from: erinstellato.com @ 2012-05-19 11:37:09 -->

