<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www2.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 : partition functions</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/partition+functions/default.aspx</link><description>Tags: partition functions</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Geek City: My Big Fat Partitioning Query</title><link>http://www2.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://www2.sqlblog.com/blogs/kalen_delaney/comments/27303.aspx</comments><wfw:commentRss>http://www2.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://www2.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://www2.sqlblog.com/aggbug.aspx?PostID=27303" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/partition+functions/default.aspx">partition functions</category></item><item><title>Geek City: ALTERing a Partition Function</title><link>http://www2.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://www2.sqlblog.com/blogs/kalen_delaney/comments/16050.aspx</comments><wfw:commentRss>http://www2.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://www2.sqlblog.com/blogs/kalen_delaney/archive/2009/08/16/altering-a-partition-function.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=16050" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/partition+functions/default.aspx">partition functions</category></item><item><title>Did You Know? What's a $ Worth?</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2007/10/13/Whats-a-_2400_-worth.aspx</link><pubDate>Sat, 13 Oct 2007 23:29:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:2958</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>4</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/2958.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=2958</wfw:commentRss><description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;No, I'm not talking about US dollars, which are not worth much at all these days. I'm talking about the $ used in a particular construct in SQL Server 2005 to get information about a partition definition. There is a construct called $PARTITION which the BOL actually refers to as a function, but it doesn't act like any other function in the product. What's strange about it is that it gets concatenated to another function, which must be a previously defined partitioning function. My contacts at Microsoft have actually said we should think of $PARTITION more like a special namespace that exists in each database, and contains all of the partition functions we have defined.&lt;/P&gt;
&lt;P&gt;I'm going to define a simple partition function with 3&amp;nbsp;boundary points (4 partitions)&amp;nbsp;and a simple partition scheme that uses the same filegroup for all the partitions. I'll show you the usage of $PARTITION and also show you a pretty nasty bug that was just reported on the public newsgroups that can occur when using $PARTITION.&amp;nbsp; I suggest using a test database for this example. Create one if you don't have one already.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;-- CREATE DATABASE testdb&lt;BR&gt;USE testdb;&lt;BR&gt;GO&lt;BR&gt;CREATE PARTITION FUNCTION myRangePF (int)&lt;BR&gt;AS RANGE LEFT FOR VALUES (2500, 5000, 7500);&lt;BR&gt;GO&lt;BR&gt;CREATE PARTITION SCHEME myRangePS&lt;BR&gt;AS PARTITION myRangePF&lt;BR&gt;ALL TO ([PRIMARY]);&lt;BR&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;As soon as you've created the partition function, you can use $PARTITION, as it doesn't require any actual data. It will tell you which partition any particular value would be in when using the specified function. So&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;SELECT $PARTITION.myRangePF(2500);&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;will tell you that 2500 will be in partition 1. In fact, the main reason I use $PARTITION is to verify my boundary values, and make sure they are in the partition that I expect them to be in.&lt;/P&gt;
&lt;P&gt;However, you can also use $PARTITION on a populated table. Let me create a partitioned table and insert 10000 rows into it. &lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;CREATE TABLE dbo.myRangeTable (c1 INT, c2 CHAR (10))&lt;BR&gt;&amp;nbsp; ON myRangePS (c1)&lt;BR&gt;GO&lt;BR&gt;SET NOCOUNT ON&lt;BR&gt;GO&lt;BR&gt;DECLARE @n INT;&lt;BR&gt;SELECT @n = 1;&lt;BR&gt;WHILE (@n &amp;lt; 10000)&lt;BR&gt;&amp;nbsp;BEGIN&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; INSERT INTO dbo.myRangeTable &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; VALUES (@n, REPLICATE ('a', 10));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SELECT @n = @n + 1;&lt;BR&gt;&amp;nbsp;END;&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;I can now use $PARTITION to determine how many rows are in each partition. &lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;SELECT $PARTITION.myRangePF(c1) Partition_Number, count(*) as row_count&lt;BR&gt;FROM dbo.myRangeTable&lt;BR&gt;GROUP BY $PARTITION.myRangePF(c1);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Here are my results:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;Partition_Number row_count&lt;BR&gt;---------------- -----------&lt;BR&gt;3&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; 2500&lt;BR&gt;1&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;2500&lt;BR&gt;4&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; 2499&lt;BR&gt;2&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; 2500&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Let's suppose I now want to turn this query into a view, so I don't have to type all that messy stuff all the time.&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;CREATE VIEW dbo.PartitionSizes&lt;BR&gt;AS&lt;BR&gt;&amp;nbsp; SELECT $PARTITION.myRangePF(c1) Partition_Number, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count(*) as row_count&lt;BR&gt;&amp;nbsp; FROM dbo.myRangeTable&lt;BR&gt;&amp;nbsp; GROUP BY $PARTITION.myRangePF(c1);&lt;/FONT&gt; 
&lt;P&gt;This works fine. I can select from the view and get the same results I&amp;nbsp;got from the standalone query. 
&lt;P&gt;Now, for the bug. If you're going to try this, make sure you're using Query Analyzer or SSMS from which you can easily cancel a query.&amp;nbsp; If you try to SELECT from this view from another database, the query freezes. 
&lt;P&gt;&lt;FONT face="courier new"&gt;USE tempdb;&lt;BR&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="courier new"&gt;SELECT * FROM testdb.dbo.PartitionSizes;&lt;/FONT&gt; 
&lt;P&gt;You'll have to cancel the query to get control back. It's very interesting, because sysprocesses doesn't show the query is being blocked, but it is not making any progress. The cpu, memusage and physical_io values do not change while the query is frozen. The only interesting thing I can find is that process is holding a database lock on a resource called [PLAN GUIDE] and it's holding a couple of Metadata [MD]&amp;nbsp;locks. But the locks have all been granted and no one is waiting for anything. 
&lt;P&gt;My first thought was that you couldn't access the $PARTITION namespace from another database, which is still no reason the connection should freeze. But in fact you CAN access $PARTITION from another database. I could execute the underlying SELECT statement directly:&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new"&gt;USE tempdb&lt;BR&gt;GO&lt;BR&gt;SELECT testdb.$PARTITION.myRangePF(c1)as Partition_Number, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; count(*) as row_count&lt;BR&gt;FROM testdb.dbo.myRangeTable&lt;BR&gt;GROUP BY testdb.$PARTITION.myRangePF(c1);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;The above works just fine. Accessing the SELECT using $PARTITION through a view in another database doesn't work, and a bug has been filed on it. 
&lt;P&gt;&lt;A title=https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=303784 href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=303784"&gt;https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=303784&lt;/A&gt; 
&lt;P&gt;There actually is a workaround you can use if you want a simpler way to get the rowcounts for every partition in a table. You can use the dynamic management view sys.dm_db_partition_stats to get the same information, without having to use $PARTITION. Although this metadata view has lots of columns, I am only interested in two of them right now. 
&lt;P&gt;&lt;FONT face="Courier New"&gt;USE testdb&lt;BR&gt;GO&lt;BR&gt;CREATE VIEW dbo.PartitionSizes2 AS&lt;BR&gt;&amp;nbsp; SELECT Partition_Number, row_count &lt;BR&gt;&amp;nbsp; FROM sys.dm_db_partition_stats&lt;BR&gt;&amp;nbsp; WHERE object_id = object_id('myRangeTable');&lt;/FONT&gt; 
&lt;P&gt;Now you can select from this view from any database, and get the results you want. 
&lt;P&gt;&lt;FONT face="courier new"&gt;USE tempdb;&lt;BR&gt;GO&lt;/FONT&gt;&lt;BR&gt;&lt;FONT face="courier new"&gt;SELECT * FROM testdb.dbo.PartitionSizes2;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=tahom&gt;Have fun!&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=2958" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/bug/default.aspx">bug</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/partition+functions/default.aspx">partition functions</category></item></channel></rss>