<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Kalen Delaney : metadata</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx</link><description>Tags: metadata</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Did You Know? Turning Off Locking</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2012/05/07/turning-off-locking.aspx</link><pubDate>Mon, 07 May 2012 23:35:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:43250</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>12</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/43250.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=43250</wfw:commentRss><description>Back when the lock manager was rewritten for SQL Server 7, and row level locking was added to the product, the procedure sp_indexoption gave us the ability to turn OFF either row or page locks or both, for one particular index, or for a table and all...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2012/05/07/turning-off-locking.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=43250" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/locking/default.aspx">locking</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category></item><item><title>Geek City: Plan Caching Internals</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2010/08/23/plan-caching-internals.aspx</link><pubDate>Mon, 23 Aug 2010 17:04:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:28191</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/28191.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=28191</wfw:commentRss><description>This Friday is the last of my summer seminars. On August 27, I am presenting on plan caching, plan reuse and recompile and plan cache metadata. This is one of my favorite topics to talk about, because a lot of the information is not very widely known,...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2010/08/23/plan-caching-internals.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=28191" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/plan+cache/default.aspx">plan cache</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/query+plans/default.aspx">query plans</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/seminars/default.aspx">seminars</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/training/default.aspx">training</category></item><item><title>Geek City: My Big Fat Partitioning Query</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2010/07/26/my-big-fat-partitioning-query.aspx</link><pubDate>Mon, 26 Jul 2010 15:45:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:27303</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>4</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/27303.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=27303</wfw:commentRss><description>When SQL Server first introduced table and index partitioning in SQL 2005, it was the same version that all the metadata changed. So I decided that I could learn a lot about metadata and a lot about the organization and storage of partitions if I tried...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2010/07/26/my-big-fat-partitioning-query.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=27303" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/partition+functions/default.aspx">partition functions</category></item><item><title>Geek City: Exploring the Transaction Log Structure</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2009/12/21/exploring-the-transaction-log-structure.aspx</link><pubDate>Tue, 22 Dec 2009 00:48:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:20158</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/20158.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=20158</wfw:commentRss><description>As I mentioned last October, my PASS preconference seminar was a whole day about the transaction log . I told the attendees all kinds of things about the structure of the log, and told them about one of the best tools for exploring the structure: the...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2009/12/21/exploring-the-transaction-log-structure.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=20158" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/DBCC+LOGINFO/default.aspx">DBCC LOGINFO</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/internals/default.aspx">internals</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/transaction+log/default.aspx">transaction log</category></item><item><title>Geek City: How Many Rows?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2009/12/07/how-many-rows.aspx</link><pubDate>Mon, 07 Dec 2009 17:59:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:19568</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>6</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/19568.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=19568</wfw:commentRss><description>In my last post, I told you I'd post something technical before I left for Sweden. I almost made it. I wrote this in the Seattle airport, but wasn't able to post it until I got to Stockholm. For as long as I've been working with SQL Server, I've been...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2009/12/07/how-many-rows.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=19568" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/rowcount/default.aspx">rowcount</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/Transactions/default.aspx">Transactions</category></item><item><title>Geek City: What do you intend with that lock?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2009/09/11/what-do-you-intend-with-that-lock.aspx</link><pubDate>Fri, 11 Sep 2009 17:56:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:16724</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>3</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/16724.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=16724</wfw:commentRss><description>Way back in the olden days, prior to SQL Server 7, I already knew that the lock manager was one of the most complex and resource intensive parts of SQL Server. Keeping track of every lock held, who was waiting for that lock, who could be granted the lock,...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2009/09/11/what-do-you-intend-with-that-lock.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=16724" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/locking/default.aspx">locking</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category></item><item><title>Geek City: ALTERing a Partition Function</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2009/08/16/altering-a-partition-function.aspx</link><pubDate>Sun, 16 Aug 2009 20:31:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:16050</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>13</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/16050.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=16050</wfw:commentRss><description>Finally, a real geeky post. I received two questions in as many weeks about what really happens to existing partitions when you alter the underlying partition function. The big question being… does altering a partition function cause any data movement?...(&lt;a href="http://sqlblog.com/blogs/kalen_delaney/archive/2009/08/16/altering-a-partition-function.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=16050" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/partition+functions/default.aspx">partition functions</category></item><item><title>Geek City: Two Compression Questions and Parameter Metadata</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2009/03/10/two-compression-questions-and-parameter-metadata.aspx</link><pubDate>Tue, 10 Mar 2009 17:46:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:12539</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>3</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/12539.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=12539</wfw:commentRss><description>&lt;P&gt;I am teaching the SQL 2008 version of my course for the first time this week. My life is still is disarray and spare time is practically non-existent.&amp;nbsp; During the evenings after I class I am trying to get caught up on several projects that I fell way behind on&amp;nbsp;over the last month when most of my time was spent in the hospital. Blogging has been put on the back burner, but I thought I could share some of the questions that came up in class on the first day.&amp;nbsp; I usually try to track down answers to open questions, and then share them with the students the next day.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;I&gt;1. Why can't the stored procedure sp_estimate_data_compression_savings be available on SQL Server 2008 Standard Edition, instead of just Enterprise, Developer and Evaluation? We realize that compression is an Enterprise only feature, but if non-Enterprise users could see how much space they would save, it might help them determine whether Enterprise Edition is worth while?&lt;/I&gt;&lt;/FONT&gt; &lt;/P&gt;
&lt;P&gt;(OK, here's a really geeky part... speaking of Enterprise, my #1 son sent me &lt;A href="http://www.traileraddict.com/trailer/star-trek-xi/feature-trailer"&gt;this link&lt;/A&gt; yesterday. ) &lt;/P&gt;
&lt;P&gt;Now I'm not saying that Microsoft should be obnoxious about this and say "See what you could save if you upgraded to Enterprise",&amp;nbsp; and do that whether the user wants to know or not. It would be on request, when the user ran this procedure. &lt;/P&gt;
&lt;P&gt;I also understand that the procedure actually applies compression to a sample of pages to compute the savings potential. And it was confirmed last night when I started researching this question that Enterprise features are just turned on and off through a switch so it actually would be easy enough to just not do the check for Enterprise Edition within this stored procedure. Microsoft is looking at possibly making this change, but it looks like it might not happen before the next major release.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;I&gt;2. Since page compression is applied on a page by page basis, what's the point of compressing a read-only table? Each page would be compressed, perhaps into a small amount of space, but if no new rows were added, the empty space on each page wouldn't get used and we would still have the same number of pages in the table.&lt;/I&gt;&lt;/FONT&gt; &lt;/P&gt;
&lt;P&gt;Although it is true that compression is applied on each page individually, you need to rebuild the table or index in order to compress it, with ALTER TABLE or ALTER INDEX.&amp;nbsp; And rebuilding a table or index moves the data to all new pages. So as the table is being rebuilt, when a page gets full, it is compressed, but then more rows can be added, and when are sufficient number are added, it gets recompressed, and keeps getting recompressed as more rows are added, until there is no chance of any more more rows being added. So during the rebuild process the table really isn't read-only, as the original data is being inserted into the a new copy of the table. You could end up with far few pages.&lt;/P&gt;
&lt;P&gt;This is pretty easy to test out, by just compressing a relatively full table of your own into a test table (so no one will update it) and then compressing it. It should take less space. &lt;/P&gt;
&lt;P&gt;There are lots of compression scripts, plus a lot more detail about how compression works, in my new book, which is scheduled for release TOMORROW!!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;I&gt;3. Where is the metadata that contains the default values of SQL Server stored procedure parameters?&lt;/I&gt;&lt;/FONT&gt; &lt;/P&gt;
&lt;P&gt;Uh, the answer appears to be 'None of the above'. There is no metadata, either system views or system tables (viewable using the DAC) that contains this information. &lt;/P&gt;
&lt;P&gt;You can read this Connect request for more details (and even vote for it if you like): &lt;/P&gt;
&lt;P&gt;&lt;A title=https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=234143 href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=234143"&gt;https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=234143&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;It does seem strange that this information is not available and it's hard to believe SQL Server parses the procedure definition every time it wants to know the default.&amp;nbsp; It turns out that even if all you want to know is whether or not a default exists is not easy to find. (You might want to know that to be able to determine if a parameter is optional.)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So now you know.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=12539" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/compression/default.aspx">compression</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category></item><item><title>Geek City: Clearing a Single Plan From Cache in SQL Server 2008</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/10/31/clearing-a-single-plan-from-cache-in-sql-server-2008.aspx</link><pubDate>Fri, 31 Oct 2008 23:43:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:9787</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>4</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/9787.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=9787</wfw:commentRss><description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I just today found out about something that was in plain sight in the Books Online... but the documentation is so vast, I haven't discovered everything yet. &lt;/P&gt;
&lt;P&gt;I blogged about &lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2007/09/29/geek-city-clearing-a-single-plan-from-cache.aspx" target=_blank&gt;clearing a single plan from cache in SQL Server 2005&lt;/A&gt; a while back, and mentioned a rumor that there would be a new way to do this in SQL Server 2008. And then just today, someone posted a comment on that blog post, asking about the new 2008 method. &lt;/P&gt;
&lt;P&gt;One of my contacts on the SQL Server team at Microsoft just sent me an email telling me about new features related to plan caching, as I am starting to work on updating that chapter for my 2008 book. He mentioned that DBCC now takes parameters, and one of the parameters is a plan handle!&lt;/P&gt;&lt;PRE&gt;DBCC FREEPROCCACHE [ ( { plan_handle | sql_handle | pool_name } ) ] [ WITH NO_INFOMSGS ]&lt;/PRE&gt;
&lt;P&gt;There is full example in the Books Online, so I won't repeat it here. If you don't have a local copy of BOL handy, you can read about the new option to DBCC FREEPROCCACHE online here:&lt;/P&gt;
&lt;P&gt;&lt;A title=http://msdn.microsoft.com/en-us/library/ms174283.aspx href="http://msdn.microsoft.com/en-us/library/ms174283.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms174283.aspx&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=9787" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/plan+cache/default.aspx">plan cache</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category></item><item><title>Geek City: Reducing Cache Bloat and a Metadata Bug</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/10/29/reducing-cache-bloat-and-a-metadata-bug.aspx</link><pubDate>Wed, 29 Oct 2008 23:43:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:9714</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/9714.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=9714</wfw:commentRss><description>&lt;P&gt;I've been running some tests with the new SQL Server 2008 configuration option 'optimize for ad hoc workloads' which is intended to reduce cache bloat due to holding onto plans for single use ad hoc queries. This option will allow a new type of cached object to be stored, which isn't the only plan, but merely a stub. There will be a corresponding new &lt;EM&gt;cacheobjtype&lt;/EM&gt; value called "Compiled Plan Stub". &lt;/P&gt;
&lt;P&gt;There are several ways of looking at the contents of cache. In SQL 2000, we had a pseudo table called &lt;EM&gt;master.dbo.syscacheobjects&lt;/EM&gt;, and we can still access this object in SQL 2005 and 2008 by referencing the compatibility view &lt;EM&gt;sys.syscacheobjects&lt;/EM&gt; (from any database). However, when I look at this view, I don't see "Compiled Plan Stub", but rather "Compiled Plan Stu ". &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityReducingCacheBloatandaMetadataBu_E2B9/stu.png"&gt;&lt;IMG style="BORDER-RIGHT:0px;BORDER-TOP:0px;BORDER-LEFT:0px;BORDER-BOTTOM:0px;" height=219 alt=stu src="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityReducingCacheBloatandaMetadataBu_E2B9/stu_thumb.png" width=403 border=0&gt;&lt;/A&gt; 
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So I checked the definition of &lt;EM&gt;syscacheobjects&lt;/EM&gt;, using the function &lt;EM&gt;object_definition&lt;/EM&gt;:&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas size=2&gt;USE master;&lt;BR&gt;SELECT OBJECT_DEFINITION(object_id('syscacheobjects'));&lt;/FONT&gt; 
&lt;P&gt;and I saw that &lt;EM&gt;syscacheobjects&lt;/EM&gt; was derived from a column in &lt;EM&gt;sys.dm_exec_cached_plans&lt;/EM&gt;, and converted to an nvarchar(17). Unfortunately, "Compiled Plan Stub" is 18 characters long. &lt;/P&gt;
&lt;P&gt;I'll be talking about this new cached object type in my &lt;A href="http://www.sqlknowhow.com/events/insidesql3.aspx" target=_blank&gt;3-day seminar in London next week&lt;/A&gt;, and I'll post more information about using the 'optimize for ad hoc workloads' at a later time. &lt;/P&gt;
&lt;P&gt;But normally, I wouldn't have run into this problem, because I have created my own view based on the new SQL 2005 metadata, including &lt;EM&gt;sys.dm_exec_cached_plans&lt;/EM&gt;. Usually, I use my own view, which converts to a longer string, so I wouldn't have seen the string truncation. But I was testing this on a new instance, where I hadn't created my own view yet. &lt;/P&gt;
&lt;P&gt;I am including my view definition, which is what I have been using since the SQL Server 2005 came out, to inspect the plan cache. In fact, I usually add a where clause to restrict the output only to Compiled Plans. Note that the view name starting with &lt;EM&gt;sp_&lt;/EM&gt; means we can access the view from any database:&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas size=1&gt;-- Create a view to show most of the same information as &lt;BR&gt;--&amp;nbsp;&amp;nbsp; SQL Server 2000's syscacheobjects &lt;BR&gt;&lt;/FONT&gt;&lt;FONT face=Consolas size=1&gt;USE master&lt;BR&gt;GO&lt;BR&gt;CREATE VIEW sp_cacheobjects(bucketid, cacheobjtype, objtype, objid, dbid, dbidexec, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uid, refcounts, usecounts, pagesused, setopts, langid, dateformat, status, lasttime, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; maxexectime, avgexectime, lastreads,lastwrites, sqlbytes, sql) &lt;BR&gt;AS&lt;BR&gt;SELECT &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Consolas size=1&gt;pvt.bucketid, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(nvarchar(20), pvt.cacheobjtype) as cacheobjtype, pvt.objtype, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(int, pvt.objectid)as object_id, CONVERT(smallint, pvt.dbid) as dbid,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(smallint, pvt.dbid_execute) as execute_dbid, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(smallint, pvt.user_id) as user_id, pvt.refcounts, pvt.usecounts, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pvt.size_in_bytes / 8192 as size_in_bytes,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(int, pvt.set_options) as setopts, CONVERT(smallint, pvt.language_id) as langid,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(smallint, pvt.date_format) as date_format, CONVERT(int, pvt.status) as status,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(bigint, 0), CONVERT(bigint, 0), CONVERT(bigint, 0), CONVERT(bigint, 0), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(bigint, 0),CONVERT(int, LEN(CONVERT(nvarchar(max), fgs.text)) * 2), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONVERT(nvarchar(3900), fgs.text)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas size=1&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM (SELECT ecp.*, epa.attribute, epa.value&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FROM sys.dm_exec_cached_plans ecp &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OUTER APPLY sys.dm_exec_plan_attributes(ecp.plan_handle) epa) as ecpa&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIVOT (MAX(ecpa.value) for ecpa.attribute &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IN ("set_options", "objectid", "dbid", "dbid_execute", &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "user_id", "language_id", "date_format", "status")) as pvt&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; OUTER APPLY sys.dm_exec_sql_text(pvt.plan_handle) fgs&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas size=1&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This view shows the full cached object type:&lt;/P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityReducingCacheBloatandaMetadataBu_E2B9/stub.png"&gt;&lt;IMG style="BORDER-RIGHT:0px;BORDER-TOP:0px;BORDER-LEFT:0px;BORDER-BOTTOM:0px;" height=226 alt=stub src="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityReducingCacheBloatandaMetadataBu_E2B9/stub_thumb.png" width=528 border=0&gt;&lt;/A&gt; 
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Consolas size=1&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=9714" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/plan+cache/default.aspx">plan cache</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/seminars/default.aspx">seminars</category></item><item><title>Did You Know: How Compatible are the Compatibility Views?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/09/14/how-compatible-are-the-compatibility-views.aspx</link><pubDate>Mon, 15 Sep 2008 01:51:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8900</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/8900.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=8900</wfw:commentRss><description>&lt;P&gt;You're probably aware that the metadata interface changed completely in SQL Server 2005, and we no longer have direct access to the system tables. Instead, Microsoft provided us with two sets of views: the catalog views and the compatibility&amp;nbsp; views. &lt;/P&gt;
&lt;P&gt;The catalog views are the preferred interface going forward, as they are fully documented and the naming conventions are much more user friendly. There are also no bitstrings, like the status fields that need to be decoded. Each attribute stored in the view is available in a separate column.&lt;/P&gt;
&lt;P&gt;The compatibility views are there to let you use the same code that you used in SQL Server 2000, hopefully temporarily, while you convert your code to the new metadata using the catalog views. The compatibility views have the same names as the system tables in SQL Server 2000, and the column names are the same. &lt;/P&gt;
&lt;P&gt;You might think that writing a query against the compatibility views would then allow you to continue to write metadata queries that work with either SQL 2000 or SQL 2005. This might be true to some extent, but we might have to define what we mean by 'work'. Another change that happened in SQL 2005 was the separation of users and schemas.&amp;nbsp; Users can have permissions granted to them, including permissions to create objects, but the objects exist in containers called schemas. &lt;/P&gt;
&lt;P&gt;In SQL 2000, users and schemas are treated interchangeably. If you create a user &lt;STRONG&gt;sue,&lt;/STRONG&gt; SQL Server automatically creates a schema &lt;STRONG&gt;sue&lt;/STRONG&gt; which is the user &lt;STRONG&gt;sue&lt;/STRONG&gt;'s default schema. When the user &lt;STRONG&gt;sue&lt;/STRONG&gt; selects from an unqualified object &lt;STRONG&gt;t1&lt;/STRONG&gt;, SQL Server 2000 assumes she is selecting from an object &lt;STRONG&gt;sue.t1&lt;/STRONG&gt;. (If there is no object &lt;STRONG&gt;sue.t1&lt;/STRONG&gt;, SQL Server then looks for &lt;STRONG&gt;dbo.t1&lt;/STRONG&gt;.)&lt;/P&gt;
&lt;P&gt;In SQL 2005, a user &lt;STRONG&gt;sue&lt;/STRONG&gt; can have any schema as her default schema and there may or may not be a schema named &lt;STRONG&gt;sue&lt;/STRONG&gt;.&amp;nbsp; When accessing an object that is not in&amp;nbsp; your default schema or in the &lt;STRONG&gt;dbo&lt;/STRONG&gt; schema, you must qualify the object with the schema name, not the owner&amp;nbsp; name.&lt;/P&gt;
&lt;P&gt;So what's my point here? &lt;/P&gt;
&lt;P&gt;If you're looking up information about objects in aSQL 2005 database, would you rather know the owner of your objects or the schema they are contained in? I suggest that it is more often the case that you want to know the schema, so that you can then access the objects you are exploring.&amp;nbsp; And here's where the incompatibility of the compatibility views comes in. &lt;/P&gt;
&lt;P&gt;In SQL 2000, the following code will give you the owner and name of all your user tables, and you can then use the information returned to access the objects. I wrote this query this morning in answer to a newsgroup posting asking for information about getting owner and object information from both SQL 2000 and 2005.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;SELECT u.name as [user],&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; o.NAME as [object] &lt;BR&gt;FROM&amp;nbsp; sysobjects o&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN sysusers u&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ON o.uid = u.uid&lt;BR&gt;WHERE&amp;nbsp;&amp;nbsp; type = 'U';&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In SQL 2005, the same code will give you the owner name, but that is NOT the name needed to access the objects. Here's an example that uses a test database, and creates a login &lt;STRONG&gt;sue&lt;/STRONG&gt;, a user &lt;STRONG&gt;sue&lt;/STRONG&gt;, and a schema called &lt;STRONG&gt;sue_schema&lt;/STRONG&gt;. The user &lt;STRONG&gt;sue&lt;/STRONG&gt; is given permission to create tables and to alter the &lt;STRONG&gt;sue_schema&lt;/STRONG&gt; schema.&amp;nbsp; The user &lt;STRONG&gt;sue&lt;/STRONG&gt; then creates a table called &lt;STRONG&gt;sue_table&lt;/STRONG&gt;.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;USE testdb;&lt;BR&gt;GO&lt;BR&gt;CREATE LOGIN sue&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WITH PASSWORD = 'sue_password';&lt;BR&gt;CREATE USER sue FOR LOGIN sue;&lt;BR&gt;GO &lt;BR&gt;CREATE SCHEMA sue_schema;&lt;BR&gt;GO&lt;BR&gt;GRANT CREATE TABLE TO sue;&lt;BR&gt;GO&lt;BR&gt;GRANT ALTER ON schema::sue_schema TO sue;&lt;BR&gt;GO&lt;BR&gt;EXECUTE AS user='sue';&lt;BR&gt;GO&lt;BR&gt;CREATE TABLE sue_schema.sue_table (a int);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;We can run the metadata query above, and add a filter to look for sue-type objects:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;SELECT u.name as [user],&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; o.name as [object] &lt;BR&gt;FROM&amp;nbsp; sysobjects o&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN sysusers u&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ON o.uid = u.uid&lt;BR&gt;WHERE&amp;nbsp;&amp;nbsp; type = 'U' AND o.name like '%sue%';&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I get these results:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;user&amp;nbsp;&amp;nbsp;&amp;nbsp; object&lt;BR&gt;------- ---------&lt;BR&gt;sue&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sue_table&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;However, for table access, this information is not helpful. I cannot execute the following statement, even as &lt;STRONG&gt;dbo&lt;/STRONG&gt; with full privileges:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;REVERT; -- so I no longer execute as user 'sue'&lt;BR&gt;SELECT * FROM sue.sue_table;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So is the metadata query really compatible? It may be compatible in the facts it gives back, but in function, it is not. For SQL Server 2005, the query does not tell us what we need to know in order to access object. Instead, we'll need a catalog view sys.schemas, which has no equivalent in SQL 2000.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=1&gt;SELECT s.name as [user],&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; o.name as [object] &lt;BR&gt;FROM&amp;nbsp; sysobjects o&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; INNER JOIN sys.schemas s&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ON o.uid = s.schema_id&lt;BR&gt;&amp;nbsp; WHERE&amp;nbsp;&amp;nbsp; type = 'U' AND o.name like '%sue%';&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So because of the split between users and schemas, we can't really write one query that gives us information about how to access objects in both SQL 2000 and SQL 2005.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8900" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category></item><item><title>Geek City: System Objects</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/08/10/geek-city-system-objects.aspx</link><pubDate>Mon, 11 Aug 2008 05:11:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8316</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>3</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/8316.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=8316</wfw:commentRss><description>&lt;P&gt;As you might know, metadata is one of my favorite topics, and I've written quite a bit about metadata and system objects. A very frequent question is: What exactly IS a system object?&lt;/P&gt;
&lt;P&gt;There are quite a few different definitions you could use. You could say a system object is one that was installed with your SQL Server installation. &lt;/P&gt;
&lt;P&gt;You could say it is one that starts with a special prefix, like 'sys' for objects if you're using SQL Server 2000 or earlier, or one in the sys schema if you're using SQL Server 2005. &lt;/P&gt;
&lt;P&gt;You could say a system object is one that has an object id of less than 100. &lt;/P&gt;
&lt;P&gt;In the old SQL 2000 Enterprise Manager, you could look at a list of objects in a database, and there was a column called 'type' with a value of either 'system' or 'user'.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;The objectproperty function has an argument called 'IsSystemTable', that will show you which tables are system tables, but won't do anything for other system objects. &lt;/P&gt;
&lt;P&gt;The &lt;EM&gt;objectproperty&lt;/EM&gt; function also has an argument called 'IsMSShipped', which corresponds to a column in the SQL 2005 metadata view &lt;EM&gt;sys.objects&lt;/EM&gt; called 'is_ms_shipped'. &lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;SELECT *&lt;BR&gt;FROM sys.objects&lt;BR&gt;WHERE &lt;/FONT&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;OBJECTPROPERTY(object_id, 'IsMSShipped') = 1;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;But just because something is shipped by Microsoft, is it really a system object? There is an undocumented procedure called &lt;EM&gt;sp_MS_marksystemobject&lt;/EM&gt;, that would change the properties of any object you created so that its 'is_ms_shipped' property would also show a value of 1. Does that make it a system object, just because you marked it as such?&lt;/P&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;CREATE TABLE tiny&lt;BR&gt;(col1 int);&lt;BR&gt;GO&lt;BR&gt;EXEC sp_MS_marksystemobject 'tiny';&lt;BR&gt;GO&lt;BR&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;SELECT *&lt;BR&gt;FROM sys.objects&lt;BR&gt;WHERE &lt;/FONT&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;OBJECTPROPERTY(object_id, 'IsMSShipped') = 1;&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;
&lt;P&gt;I usually think of system objects as ones that have special behavior. Procedures in the master database, that start with sp_ are special, in that you can access them from anywhere. It turns out that you can create views and tables in master, with names starting with sp_, and they will also be accessible from any database, without fully qualifying the name.&lt;/P&gt;
&lt;P&gt;System tables have always had special behavior, in that you couldn't update them without setting a configuration option for the whole server. Once you set 'allow updates' to 1, you could update system tables, in versions before SQL 2005. Metadata changed completely in SQL 2005, and I thought for a long time that the 'allow updates' configuration option&amp;nbsp; didn't do anything anymore. But I just recently found out that is not true. There is something special that 'allow updates' allows. &lt;/P&gt;
&lt;P&gt;If you run the following, you will be given an error message:&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;sp_configure 'allow updates', 1;&lt;BR&gt;reconfigure;&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;Configuration option 'allow updates' changed from 0 to 1. Run the RECONFIGURE statement to install.&lt;BR&gt;Msg 5808, Level 16, State 1, Line 2&lt;BR&gt;Ad hoc update to system catalogs is not supported.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So it tells you to RECONFIGURE, but when you do, you still get an error. However, if you run RECONFIGURE WITH OVERRIDE, you get&amp;nbsp; no error:&lt;/P&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;sp_configure 'allow updates', 1;&lt;BR&gt;reconfigure with override;&lt;/FONT&gt; 
&lt;P&gt;It turns out that you if you set 'allow updates' to 1, any procedure that you create in the master database will automatically be marked as 'is_ms_shipped'. You can observe this either with the &lt;EM&gt;OBJECTPROPERTY&lt;/EM&gt; function or the &lt;EM&gt;is_ms_shipped&lt;/EM&gt; column in &lt;EM&gt;sys.objects&lt;/EM&gt;. This doesn't seem to work for tables or views, and it doesn't give the procedure any special behavior, but it changes a internal status bit to make the object seem like something special.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;USE master;&lt;BR&gt;GO&lt;BR&gt;CREATE PROC today&lt;BR&gt;AS SELECT getdate();&lt;BR&gt;GO&lt;BR&gt;SELECT *&lt;BR&gt;FROM sys.objects&lt;BR&gt;WHERE &lt;/FONT&gt;&lt;FONT color=#0000ff size=2 face="Courier New"&gt;is_ms_shipped =&amp;nbsp; 1 AND name LIKE 't%';&lt;/FONT&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8316" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category></item><item><title>Geek City: Why I still need Sysprocesses</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/06/29/why-i-still-need-sysprocesses.aspx</link><pubDate>Mon, 30 Jun 2008 03:48:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7566</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>20</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/7566.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=7566</wfw:commentRss><description>&lt;P&gt;I've said many times that my favorite new feature in SQL Server 2005 is the new metadata, in particular the new Dynamic Management Objects. When I have to do troubleshooting on a SQL Server 2000 system, it is worse than painful, not to have my favorite tools like &lt;EM&gt;sys.dm_tran_locks&lt;/EM&gt;, &lt;EM&gt;sys.dm_exec_cached_plans&lt;/EM&gt; and&lt;BR&gt;&lt;EM&gt;sys.dm_exec_query_plan&lt;/EM&gt;. By now, on the eve of the release of the version AFTER SQL Server 2005, my transition to the new metadata is almost complete. &lt;/P&gt;
&lt;P&gt;With one notable exception...&lt;/P&gt;
&lt;P&gt;I have always used &lt;EM&gt;sysprocesses&lt;/EM&gt; constantly for troubleshooting information. Although most of the useful information that allows me to see what sessions are using lots of memory, or performing lots of I/O, can found in &lt;EM&gt;sys.dm_exec_sessions&lt;/EM&gt;, there is one piece of information that isn't there. &lt;EM&gt;Sysprocesses&lt;/EM&gt; contains a columns called &lt;EM&gt;open_tran&lt;/EM&gt; which reflects the transaction&amp;nbsp; nesting of each session. If a session issues four BEGIN TRAN commands, with no COMMITs or ROLLBACKs, their session will have an &lt;EM&gt;open_tran&lt;/EM&gt; value in &lt;EM&gt;sysprocesses&lt;/EM&gt; of 4. Any &lt;EM&gt;open_tran&lt;/EM&gt; value greater than 0 might mean that a transaction is holding locks and blocking other processes, or it might be keeping the transaction log from being cleared. If you ever notice &lt;EM&gt;open_tran&lt;/EM&gt; values in higher than 2 or 3, it's a pretty good indication that a developer doesn't know much about SQL Server transaction management. I use this value all the time, and once had to troubleshoot a system where dozens of connections had open_tran values in the 20s and 30s! (For more details about nesting transactions, see my &lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2007/08/13/did-you-know-nesting-transactions.aspx" target=_blank&gt;earlier post&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;So imagine my surprise when I discovered that the &lt;EM&gt;sys.dm_exec_sessions&lt;/EM&gt; view, which is supposed to 'replace' &lt;EM&gt;sysprocesses&lt;/EM&gt; in SQL Server 2005, has no column to provide this information!&amp;nbsp; Another view, &lt;EM&gt;sys.dm_exec_requests&lt;/EM&gt;, has a column called &lt;EM&gt;open_transaction_count&lt;/EM&gt;, which you might think would be the same thing. And it actually is the same information, but the &lt;EM&gt;sys.dm_exec_requests&lt;/EM&gt; view only returns rows for sessions that are currently active, i.e. currently running a query. The need for examining the &lt;EM&gt;open_tran&lt;/EM&gt; value is greatest when looking at those sessions that aren't doing anything, but are just sitting there with an open transaction. Those are the processes that you need to troubleshoot. I had felt that the omission of &lt;EM&gt;open_tran&lt;/EM&gt; (or &lt;EM&gt;open_transaction_count&lt;/EM&gt;) from &lt;EM&gt;sys.dm_exec_sessions&lt;/EM&gt; was just an oversight, and it would be 'fixed' in the next release. But it appears I am to be disappointed. I just checked &lt;EM&gt;sys.dm_exec_sessions&lt;/EM&gt; in RC0, and there is still no &lt;EM&gt;open_transaction_count&lt;/EM&gt; column.&lt;/P&gt;
&lt;P&gt;So long live &lt;EM&gt;sysprocesses&lt;/EM&gt;!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7566" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/DMVs/default.aspx">DMVs</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/Transactions/default.aspx">Transactions</category></item><item><title>Geek City: What's Worse Than a Table Scan?</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/05/25/whats-worse-than-a-table-scan.aspx</link><pubDate>Sun, 25 May 2008 20:59:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:6970</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>10</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/6970.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=6970</wfw:commentRss><description>&lt;P&gt;I have frequently heard SQL Server developers and DBAs gasp when a query plan is indicating that SQL Server is performing a table scan, thinking that is the worst thing that could ever happen to a query. The truth is, it's far from the worst thing and in addition, not all table scans are created equal. &lt;/P&gt;
&lt;P&gt;One thing that is far worse that a table scan is to execute a query plan that uses a nonclustered index, and having that plan look up every single row in a table! Although that is a horrible thing to behold, it is not the topic of this post.&lt;/P&gt;
&lt;P&gt;Today, I'm going to show you that two different table scans on the same data in a heap can give very different performance.&lt;/P&gt;
&lt;P&gt;The behavior has to do with a technique that SQL Server uses when a row in a heap is increased in size so it no longer fits in the original page. This usually occurs when a variable length column is updated to take more space.&amp;nbsp; If SQL Server just moved the row to another page, any nonclustered indexes would have to be updated to indicate the new page address.&amp;nbsp; (Remember, if the underlying table is a heap, nonclustered indexes point to the data row using a actual address.) Since there can be up to 249 nonclustered indexes on a single table, that could potentially be a LOT of work. So instead, when a row in a heap has to move, SQL Server leaves behind a forwarding pointer in place of the row that has moved. The nonclustered indexes continue to point to the old location, and then SQL Server just needs one more page lookup to find the new location. For just a few lookups, this expense is minimal and more than made up for my the savings of not having to update all the nonclustered indexes every time a row moves. &lt;/P&gt;
&lt;P&gt;However, what happens when there are LOTS of forwarding pointers?&lt;/P&gt;
&lt;P&gt;The metadata function &lt;EM&gt;sys.dm_db_index_physical_stats&lt;/EM&gt; has a column that indicates how many forwarded records are in any table. For tables with clustered indexes, this will always be 0. &lt;/P&gt;
&lt;P&gt;Let's look at an example. I'll make a copy of the &lt;EM&gt;Person.Address&lt;/EM&gt; table in the &lt;EM&gt;AdventureWorks&lt;/EM&gt; database, and add a new varchar column to it. Initially, the column takes no space.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;USE AdventureWorks;&lt;BR&gt;GO&lt;BR&gt;IF EXISTS (SELECT 1 FROM sys.tables&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE name = 'Address2' AND schema_id =1)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DROP TABLE dbo.Address2;&lt;BR&gt;GO&lt;BR&gt;SELECT *, convert (varchar(500), 'comments') AS comments &lt;BR&gt;&amp;nbsp;&amp;nbsp; INTO Address2 &lt;BR&gt;FROM Person.Address;&lt;BR&gt;GO&lt;BR&gt;-- note that the pages are almost full and there are no forwarded records&lt;BR&gt;SELECT index_type_desc, page_count, avg_page_space_used_in_percent,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; avg_record_size_in_bytes,forwarded_record_count&lt;BR&gt;FROM sys.dm_db_index_physical_stats(db_id('AdventureWorks'), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;object_id('Address2'),null, null, 'detailed');&lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Now I'll increase the length of all the new columns and check the physical stats again:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;UPDATE Address2&lt;BR&gt;SET comments = replicate('a', 500);&lt;BR&gt;GO&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;SELECT index_type_desc, page_count, avg_page_space_used_in_percent,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; avg_record_size_in_bytes,forwarded_record_count&lt;BR&gt;FROM sys.dm_db_index_physical_stats(db_id('AdventureWorks'), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;object_id('Address2'),null, null, 'detailed');&lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The output shows me I have 1763 pages in the table and 15961 forwarded records.&lt;/P&gt;
&lt;P&gt;Let's see what happens when we read every row in the table:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;SET STATISTICS IO ON;&lt;BR&gt;SELECT * FROM Address2;&lt;BR&gt;SET STATISTICS IO OFF;&lt;/FONT&gt; 
&lt;P&gt;The logical I/O value tells us that instead of just reading through every page, for a total of 1763 reads, SQL Server jumps out of sequence and follows the forwarding pointer for every forwarded record. So the number of logical reads is the sum of the number of pages plus the number of forwarded records:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;1763&amp;nbsp; +&amp;nbsp; 15961= 17724&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;I was discussing this behavior with my friend and colleague Tibor Karaszi and he proposed an explanation for this behavior. He related it to the same behavior that Itzik Ben-Gan has described for why SQL Server will always follow page pointers when scanning a clustered index if consistent reads are desired. The alternative would be to just read the pages in disk order, or page number order, which can be determined by examining the IAM structures for the object. For clustered tables, we need to follow the page pointers instead of the IAMs&amp;nbsp; to make sure that if a row is moved due to an update while the scan is occurring, that we don't read the same row twice (if the row is moved to a higher page number) or skip the row altogether (if the row is moved to a lower page number.)&lt;/P&gt;
&lt;P&gt;But what about a heap? Are there potential problems scanning a heap while updates are occurring? Could we potentially read the same row twice or skip a row, since there is no 'ordered list' to read? Tibor suggested the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;I believe that forwarding pointers take care of just that. Because of forwarding pointers, the "root" location for a row is stable. So, even if the row moves during a scan, the "root location"(forwarding stub) is at the same position. We have concluded that the scan uses the forwarding pointers when reading the rows. This means that a scan is not sensitive to row movements during the scan. It cannot "skip" rows that are there, or read the same row twice. &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So a few forwarding pointers are not a bad thing, but having lots of them can increase the work done during scans or partial scans by a considerable amount. &lt;/P&gt;
&lt;P&gt;So how do you get rid of forwarding pointers? There are 3 ways:&lt;/P&gt;
&lt;P&gt;1. If the row is updated, so that its size decreases, AND if there is still room on the page where the row came from, it will be moved back. This is not dependable, so it isn't really recommended as a solution.&amp;nbsp; When I updated my Address2 table, many of the forwarded records were moved, but not all:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;UPDATE Address2&lt;BR&gt;SET comments = '';&lt;BR&gt;GO &lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;SELECT index_type_desc, page_count, avg_page_space_used_in_percent,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; avg_record_size_in_bytes,forwarded_record_count&lt;BR&gt;FROM sys.dm_db_index_physical_stats(db_id('AdventureWorks'), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Courier New" size=2&gt;object_id('Address2'),null, null, 'detailed');&lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;My results showed that I am still left with 1080 forwarded records. This is a great improvement over 15961, but it's still more forwarded records than there are pages in the table.&lt;/P&gt;
&lt;P&gt;2. Forwarded records will be cleaned up when you shrink the data file. This is definitely NOT recommended as a solution; I am only mentioning it for completeness. SQL Server does so much moving of data and updating nonclustered index pointers when shrinking a file, that updating the forwarded records is not very much extra work at all. &lt;/P&gt;
&lt;P&gt;3. Since forwarded records only exist in heaps, the best solution is to make the table not a heap. Build a clustered index, and all the forwarded records will go away. If you really don't want the clustered index, you can then drop it.&lt;/P&gt;
&lt;P&gt;Hopefully, this information will be useful to you.&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=6970" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/allocation+structures/default.aspx">allocation structures</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/forwarding+pointers/default.aspx">forwarding pointers</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/pages/default.aspx">pages</category></item><item><title>Did You Know? My DVD is in Production!</title><link>http://sqlblog.com/blogs/kalen_delaney/archive/2008/02/08/my-dvd-is-in-production.aspx</link><pubDate>Fri, 08 Feb 2008 22:15:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:4987</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/kalen_delaney/comments/4987.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=4987</wfw:commentRss><description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The editing for Lesson 1 is done and the production run of &lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2007/12/15/geek-city-sql-server-internals-course-coming-soon-on-dvd.aspx" target=_blank&gt;my DVD&lt;/A&gt; has started. We're expecting shipping to start in about 2 weeks. &lt;/P&gt;
&lt;P&gt;In addition, we've extended the &lt;A class="" href="http://sqlblog.com/blogs/kalen_delaney/archive/2008/01/24/did-you-know-my-dvd-is-now-orderable.aspx" target=_blank&gt;pre-order price&lt;/A&gt; for another 5 days, so any orders that come in before Valentine's Day will get the special reduced price.&lt;/P&gt;
&lt;P&gt;Because this is taking a bit longer than we hoped, we are going to make the edited DVD available online. If you've pre-ordered, you'll be able to view the online version for free. I'll post the URL as soon as it's ready.&lt;/P&gt;
&lt;P&gt;For now, check out &lt;A href="http://dvd.kalendelaney.com/"&gt;http://DVD.KalenDelaney.com&lt;/A&gt;&lt;FONT color=#ff00ff&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff&gt;&lt;FONT color=#000000&gt;P.S.&lt;/FONT&gt;&amp;nbsp;&lt;FONT color=#000000&gt;Lesson 2 has already been recorded, and is now being edited.&lt;/FONT&gt; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=4987" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/Inside+SQL+Server/default.aspx">Inside SQL Server</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/seminars/default.aspx">seminars</category><category domain="http://sqlblog.com/blogs/kalen_delaney/archive/tags/training/default.aspx">training</category></item></channel></rss>