{"id":10298,"date":"2020-10-16T09:14:47","date_gmt":"2020-10-15T23:14:47","guid":{"rendered":"https:\/\/database.guide\/?p=10298"},"modified":"2020-10-20T10:28:58","modified_gmt":"2020-10-20T00:28:58","slug":"create-a-partitioned-table-in-sql-server-t-sql","status":"publish","type":"post","link":"https:\/\/database.guide\/create-a-partitioned-table-in-sql-server-t-sql\/","title":{"rendered":"Create a Partitioned Table in SQL Server (T-SQL)"},"content":{"rendered":"\n<p><a href=\"https:\/\/database.guide\/what-is-sql-server\/\">SQL Server<\/a> supports partitioned tables and indexes. When a partitioned table or index is partitioned, its data is divided into units that can be spread across more than one filegroup.<\/p>\n\n\n\n<p>Therefore, to create a partitioned table in SQL Server, you first need to create the filegroup\/s that will hold each partition. You also need to create a partition function and a partition scheme. <\/p>\n\n\n\n<p>So it goes like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Create filegroup\/s<\/li><li>Create a partition function<\/li><li>Create a partition scheme<\/li><li>Create the partitioned table<\/li><\/ol>\n\n\n\n<p>Below is an example of using these steps to create a table with four partitions.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Create Filegroups<\/h2>\n\n\n\n<p>First, we add four filegroups to the database called <strong>Test<\/strong>, and then specify the physical file for each of those filegroups.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ALTER DATABASE Test\nADD FILEGROUP MoviesFg1;\nGO  \nALTER DATABASE Test  \nADD FILEGROUP MoviesFg2;  \nGO  \nALTER DATABASE Test  \nADD FILEGROUP MoviesFg3;  \nGO  \nALTER DATABASE Test  \nADD FILEGROUP MoviesFg4;   \n\nALTER DATABASE Test   \nADD FILE   \n(  \n    NAME = MoviesFg1dat,  \n    FILENAME = '\/var\/opt\/mssql\/data\/MoviesFg1dat.ndf',  \n    SIZE = 5MB,  \n    MAXSIZE = 100MB,  \n    FILEGROWTH = 5MB  \n)  \nTO FILEGROUP MoviesFg1;  \nALTER DATABASE Test   \nADD FILE   \n(  \n    NAME = MoviesFg2dat,  \n    FILENAME = '\/var\/opt\/mssql\/data\/MoviesFg2dat.ndf',  \n    SIZE = 5MB,  \n    MAXSIZE = 100MB,  \n    FILEGROWTH = 5MB  \n)  \nTO FILEGROUP MoviesFg2;  \nGO  \nALTER DATABASE Test   \nADD FILE   \n(  \n    NAME = MoviesFg3dat,  \n    FILENAME = '\/var\/opt\/mssql\/data\/MoviesFg3dat.ndf',  \n    SIZE = 5MB,  \n    MAXSIZE = 100MB,  \n    FILEGROWTH = 5MB  \n)  \nTO FILEGROUP MoviesFg3;  \nGO  \nALTER DATABASE Test   \nADD FILE   \n(  \n    NAME = MoviesFg4dat,  \n    FILENAME = '\/var\/opt\/mssql\/data\/MoviesFg4dat.ndf',  \n    SIZE = 5MB,  \n    MAXSIZE = 100MB,  \n    FILEGROWTH = 5MB  \n)  \nTO FILEGROUP MoviesFg4;  \nGO  <\/code><\/pre>\n\n\n\n<p>You&#8217;ll need to change this code, depending on your requirements. You&#8217;ll also need to change the file paths to suit your environment. For example, if you&#8217;re on Windows, your path might look more like <code>D:\\mssql\\data\\MoviesFg4dat.ndf<\/code>. <\/p>\n\n\n\n<p>Also, if you need more partitions add more filegroups here. Conversely, if you need less partitions, specify less filegroups here.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create a Partition Function<\/h2>\n\n\n\n<p>Next we create a partition function called <strong>MoviesPartitionFunction<\/strong> that will partition the table into four partitions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE PARTITION FUNCTION MoviesPartitionFunction (int)  \n    AS RANGE LEFT FOR VALUES (1, 100, 1000);\nGO<\/code><\/pre>\n\n\n\n<p>The <strong>int<\/strong> part specifies the data type of the column used for partitioning.<\/p>\n\n\n\n<p>All data types are valid for use as partitioning columns, except&nbsp;<strong>text<\/strong>,&nbsp;<strong>ntext<\/strong>,&nbsp;<strong>image<\/strong>,&nbsp;<strong>xml<\/strong>,&nbsp;<strong>timestamp<\/strong>,&nbsp;<strong>varchar(max)<\/strong>,&nbsp;<strong>nvarchar(max)<\/strong>,&nbsp;<strong>varbinary(max)<\/strong>, alias data types, or CLR user-defined data types.<\/p>\n\n\n\n<p>Here, I use three boundary values (1, <code>100<\/code>, and <code>1000<\/code>) to specify four partitions. These boundary values must either match or be implicitly convertible to the data type specified in parentheses after the partition function&#8217;s name.<\/p>\n\n\n\n<p>Given these boundary values, and the fact that I specified a <code>RANGE LEFT<\/code> partition, the four partitions will hold values as specified in the following table.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Partition<\/th><th>Values<\/th><\/tr><\/thead><tbody><tr><td>1<\/td><td>&lt;=\u00a0<code>1<\/code><\/td><\/tr><tr><td>2<\/td><td>>\u00a0<code>1<\/code>\u00a0AND\u00a0&lt;=\u00a0<code>100<\/code><\/td><\/tr><tr><td>3<\/td><td>>\u00a0<code>100<\/code>\u00a0AND\u00a0&lt;=<code>1000<\/code><\/td><\/tr><tr><td>4<\/td><td>>\u00a0<code>1000<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>If I had specified a <code>RANGE RIGHT<\/code> partition, the breakdown would be slightly different, as outlined in the following table.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Partition<\/th><th>Values<\/th><\/tr><\/thead><tbody><tr><td>1<\/td><td><strong>&lt;\u00a0<code>1<\/code><\/strong><\/td><\/tr><tr><td>2<\/td><td><strong>>=\u00a0<code>1<\/code>\u00a0<\/strong>AND<strong>\u00a0&lt;\u00a0<code>100<\/code><\/strong><\/td><\/tr><tr><td>3<\/td><td><strong>>=\u00a0<code>100<\/code>\u00a0<\/strong>AND<strong>\u00a0&lt;\u00a0<code>1000<\/code><\/strong><\/td><\/tr><tr><td>4<\/td><td><strong>>=\u00a0<code>1000<\/code><\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The same concept applies if the partitioning column uses other data types, such as date\/time values.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create a Partition Scheme<\/h2>\n\n\n\n<p>Next we need to create a partition scheme.<\/p>\n\n\n\n<p>A partition scheme maps the partitions of a partitioned table or index to the new filegroups.<\/p>\n\n\n\n<p>In our case, the code will look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE PARTITION SCHEME MoviesPartitionScheme  \n    AS PARTITION MoviesPartitionFunction  \n    TO (MoviesFg1, MoviesFg2, MoviesFg3, MoviesFg4);  \nGO<\/code><\/pre>\n\n\n\n<p>Notice that we reference the partition function that we created in the previous step. We also reference the filegroups that we created in the first step.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create the Partitioned Table<\/h2>\n\n\n\n<p>Finally we can create the partitioned table.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE Movies (\n    MovieId int IDENTITY PRIMARY KEY, \n    MovieName varchar(60)\n    )  \n    ON MoviesPartitionScheme (MovieId);  \nGO<\/code><\/pre>\n\n\n\n<p>The only difference between this and creating an unpartitioned table is that when creating a partitioned table, we use the <code>ON<\/code> argument to specify a partition scheme to use. In our case, we specify the partition scheme we created in the previous step, and specify the <strong>MovieId<\/strong> column as the partitioning column.<\/p>\n\n\n\n<p>You&#8217;ll notice that the <strong>MovieId<\/strong> column has a data type of <strong>int<\/strong>, which matches the boundary values that we specified when creating the partition function.<\/p>\n\n\n\n<p>Note that if you use a <a href=\"https:\/\/database.guide\/what-is-a-computed-column-in-sql-server\/\" title=\"What is a Computed Column in SQL Server?\">computed column<\/a> in a partition function, it must be explicitly marked <code>PERSISTED<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Check the Partition Function<\/h2>\n\n\n\n<p>You can use the <code>sys.partition_functions<\/code> view to return all partition functions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT * FROM sys.partition_functions;<\/code><\/pre>\n\n\n\n<p>Result (using vertical output):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | MoviesPartitionFunction\nfunction_id &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 65536\ntype&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | R&nbsp;\ntype_desc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | RANGE\nfanout&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 4\nboundary_value_on_right | 0\nis_system &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0\ncreate_date &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2020-10-10 05:37:41.330\nmodify_date &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2020-10-10 05:37:41.330<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Check the Partition Scheme<\/h2>\n\n\n\n<p>You can use <code>sys.partition_schemes<\/code> to check the partition scheme.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT * FROM sys.partition_schemes;<\/code><\/pre>\n\n\n\n<p>Result (using vertical output):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | MoviesPartitionScheme\ndata_space_id | 65601\ntype&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | PS\ntype_desc &nbsp; &nbsp; | PARTITION_SCHEME\nis_default&nbsp; &nbsp; | 0\nis_system &nbsp; &nbsp; | 0\nfunction_id &nbsp; | 65536<\/pre>\n\n\n\n<p>Alternatively, you could use the following query to return other details, such as the schema, table, index, etc.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT \n    object_schema_name(i.object_id) AS &#91;Schema],\n    object_name(i.object_id) AS &#91;Object],\n    i.name AS &#91;Index],\n    s.name AS &#91;Partition Scheme]\n    FROM sys.indexes i\n    INNER JOIN sys.partition_schemes s ON i.data_space_id = s.data_space_id;<\/code><\/pre>\n\n\n\n<p>Result (using vertical output):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Schema &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | dbo\nObject &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Movies\nIndex&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | PK__Movies__4BD2941A0ED85ACA\nPartition Scheme | MoviesPartitionScheme<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Check the Partitioned Table<\/h2>\n\n\n\n<p>You can run the <code>sys.dm_db_partition_stats<\/code> view to return page and row-count information for every partition in the current database.<\/p>\n\n\n\n<p>But running that before inserting any data into the table will result in most statistics being zero.<\/p>\n\n\n\n<p>So I&#8217;m going to insert data first.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>INSERT INTO Movies\nSELECT name FROM OtherDb.dbo.Movies;<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">(4079 rows affected)<\/pre>\n\n\n\n<p>We can see that 4,079 rows were inserted.<\/p>\n\n\n\n<p>Now let&#8217;s query the <code>sys.dm_db_partition_stats<\/code> view.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT *\nFROM sys.dm_db_partition_stats\nWHERE object_id = OBJECT_ID('dbo.Movies');<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+-------------------+-------------+------------+--------------------+--------------------------+--------------------------+------------------------------+-----------------------+---------------------------+--------------------------------+------------------------------------+-------------------+-----------------------+-------------+\n| partition_id&nbsp; &nbsp; &nbsp; | object_id &nbsp; | index_id &nbsp; | partition_number &nbsp; | in_row_data_page_count &nbsp; | in_row_used_page_count &nbsp; | in_row_reserved_page_count &nbsp; | lob_used_page_count &nbsp; | lob_reserved_page_count &nbsp; | row_overflow_used_page_count &nbsp; | row_overflow_reserved_page_count &nbsp; | used_page_count &nbsp; | reserved_page_count &nbsp; | row_count &nbsp; |\n|-------------------+-------------+------------+--------------------+--------------------------+--------------------------+------------------------------+-----------------------+---------------------------+--------------------------------+------------------------------------+-------------------+-----------------------+-------------|\n| 72057594048413696 | 2030630277&nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 9&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 9 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |\n| 72057594048479232 | 2030630277&nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 9&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 9 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 99&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |\n| 72057594048544768 | 2030630277&nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 5&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 25 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 25&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 900 &nbsp; &nbsp; &nbsp; &nbsp; |\n| 72057594048610304 | 2030630277&nbsp; | 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 33 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 12&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 33&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 3079&nbsp; &nbsp; &nbsp; &nbsp; |\n+-------------------+-------------+------------+--------------------+--------------------------+--------------------------+------------------------------+-----------------------+---------------------------+--------------------------------+------------------------------------+-------------------+-----------------------+-------------+<\/pre>\n\n\n\n<p>This view returns a lot of columns, so let&#8217;s narrow the columns down to just a couple.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT \n    partition_number,\n    row_count\nFROM sys.dm_db_partition_stats\nWHERE object_id = OBJECT_ID('dbo.Movies');<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+--------------------+-------------+\n| partition_number &nbsp; | row_count &nbsp; |\n|--------------------+-------------|\n| 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |\n| 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 99&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |\n| 3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 900 &nbsp; &nbsp; &nbsp; &nbsp; |\n| 4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 3079&nbsp; &nbsp; &nbsp; &nbsp; |\n+--------------------+-------------+<\/pre>\n\n\n\n<p>We can see how the rows are allocated across the partitions. They&#8217;re allocated exactly as we specified in the partition function. The rows total 4,079, which is exactly how many rows we inserted.<\/p>\n\n\n\n<p>However, it&#8217;s worth noting that the Microsoft documentation actually <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/system-dynamic-management-views\/sys-dm-db-partition-stats-transact-sql?view=sql-server-ver15\" target=\"_blank\" rel=\"noreferrer noopener\" title=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/system-dynamic-management-views\/sys-dm-db-partition-stats-transact-sql?view=sql-server-ver15\">states<\/a> that this column is just an <em>approximate<\/em> count of the rows in each partition.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Best Practice<\/h2>\n\n\n\n<p>Microsoft <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/statements\/alter-partition-function-transact-sql?view=sql-server-ver15#best-practices\" target=\"_blank\" rel=\"noreferrer noopener\" title=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/statements\/alter-partition-function-transact-sql?view=sql-server-ver15#best-practices\">recommends<\/a> that we always keep empty partitions at both ends of the partition range. <\/p>\n\n\n\n<p>This is in case you need to either split or merge the partitions in the future.<\/p>\n\n\n\n<p>The reason for this recommendation is to guarantee that the partition split and the partition merge don&#8217;t incur any unexpected data movement.<\/p>\n\n\n\n<p>Therefore, given the data in my example, I could change the partition function to look something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE PARTITION FUNCTION MoviesPartitionFunction (int)  \n    AS RANGE LEFT FOR VALUES (-1, 100, 10000);\nGO<\/code><\/pre>\n\n\n\n<p>Or if I anticipate more than 10,000 rows, I could use a larger number (or create more partitions).<\/p>\n\n\n\n<p>If I were to recreate all the steps again, to create my partitioned table, my partition stats would look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT \n    partition_number,\n    row_count\nFROM sys.dm_db_partition_stats\nWHERE object_id = OBJECT_ID('dbo.Movies');<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+--------------------+-------------+\n| partition_number &nbsp; | row_count &nbsp; |\n|--------------------+-------------|\n| 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |\n| 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 100 &nbsp; &nbsp; &nbsp; &nbsp; |\n| 3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 3979&nbsp; &nbsp; &nbsp; &nbsp; |\n| 4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |\n+--------------------+-------------+<\/pre>\n\n\n\n<p>Now my data is concentrated into the middle two partitions, and the partitions at both ends are empty.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>SQL Server supports partitioned tables and indexes. When a partitioned table or index is partitioned, its data is divided into units that can be spread across more than one filegroup. Therefore, to create a partitioned table in SQL Server, you first need to create the filegroup\/s that will hold each partition. You also need to &#8230; <a title=\"Create a Partitioned Table in SQL Server (T-SQL)\" class=\"read-more\" href=\"https:\/\/database.guide\/create-a-partitioned-table-in-sql-server-t-sql\/\" aria-label=\"Read more about Create a Partitioned Table in SQL Server (T-SQL)\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[10,77,105,61,26],"class_list":["post-10298","post","type-post","status-publish","format-standard","hentry","category-sql-server","tag-how-to","tag-mssql","tag-partitioning","tag-t-sql","tag-tables"],"_links":{"self":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/10298","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/comments?post=10298"}],"version-history":[{"count":14,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/10298\/revisions"}],"predecessor-version":[{"id":10390,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/10298\/revisions\/10390"}],"wp:attachment":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/media?parent=10298"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/categories?post=10298"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/tags?post=10298"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}