SQL Server Partition per table on Tenant ID - disk space used

放肆的年华 提交于 2019-12-06 13:19:08

问题


We are currently developing a Multi Tenant web application. This application stores all it's data in 1 single database.

Datarows for a tenant are always with the tenant id.

At the moment we are considering creating table partitions, with the tenant id as partitioning key. This makes sense because 99.9% of all queries will include the tenant id as a where clause criterium. If I understand correctly, SQL Server query optimize all such queries by eliminating the table partitions that not contain the partition key (in my case the tenant id).

Any comments on this strategy (serious drawbacks, do or do not use filegroups etc, maximum allowed partitions per table...) would be appreciated.

But my main question is this: We want to calculate the disk usage per tenant. SQL Server supports reporting on disk usage per partition (standard report). does anybody know of T-SQL that would allow me to get the disk usage of all table partitions for a given tenant ID?


回答1:


Here's a good primer on partitioning by Kendra Little. It should help you answer the question of whether or not to partition. http://www.brentozar.com/archive/2012/03/how-decide-if-should-use-table-partitioning/

One recommendation I have is to make sure that every query hitting the table uses partition elimination in the predicate.

As for file groups, keep in mind that the partition scheme maps the partition to the filegroup. This could get complicated if you wanted to do 1 file group per tenant.

With SQL Server 2005 - 2008 R2, 1,000 partitions are the maximum that a table may contain. With 2012, they increased the limit to 15,000 partitions. If you need more than that, space the partition values out and let the range determine which partition the data will go.

Here's a table valued function you can use to derive space usage by partition:

CREATE FUNCTION tvfPartitionAllocationDetails (@schema_name sysname, @table_name sysname) 
RETURNS TABLE 
AS 
RETURN

select  f.data_space_id,
        f.NAME AS file_group_name,
        SCHEMA_NAME(t.schema_id) AS table_schema,
        t.name AS table_name,
        [HOBT?] = CASE pst.index_id WHEN 0 THEN 'HEAP' WHEN 1 THEN 'B-TREE' END,
        p.partition_number,
        ps.name AS partition_scheme_name,
        pf.name AS partition_function_name,
        partition_function_range = CASE pf.boundary_value_on_right WHEN 1 THEN 'RIGHT' WHEN 0 THEN 'LEFT' END,
        left_prv.value AS left_range,
        right_prv.value AS right_value,
        ISNULL(STR(CAST(left_prv.value AS BIGINT)), '-INF')
        + CASE WHEN pf.boundary_value_on_right = 0 THEN ' < '
               ELSE ' <= '
          END + 'X' + CASE WHEN pf.boundary_value_on_right = 0 THEN ' <= '
                           ELSE ' < '
                      END + ISNULL(STR(CAST(right_prv.value AS BIGINT)), 'INF') AS range_desc
        ,SUM(used_page_count) * 8 [TableSpaceUsed(KB)]
        ,(SELECT SUM(ISNULL(used_page_count,0)) * 8 FROM sys.dm_db_partition_stats  WHERE object_id = p.OBJECT_ID AND partition_number = p.partition_number AND index_id > 1) [NCIndexSpaceUsed(KB)]
        ,SUM(used_page_count) used_page_count
        ,row_count
from sys.dm_db_partition_stats pst
INNER JOIN sys.partitions p ON pst.partition_id = p.partition_id
JOIN    sys.tables t
        ON p.object_id = t.object_id
JOIN    sys.indexes i
        ON p.object_id = i.object_id
        AND p.index_id = i.index_id
JOIN    sys.allocation_units au
        ON p.hobt_id = au.container_id
JOIN    sys.filegroups f
        ON au.data_space_id = f.data_space_id
LEFT JOIN    sys.partition_schemes ps
        ON ps.data_space_id = i.data_space_id
LEFT JOIN    sys.partition_functions pf
        ON ps.function_id = pf.function_id
LEFT JOIN sys.partition_range_values left_prv
        ON left_prv.function_id = ps.function_id
           AND left_prv.boundary_id + 1 = p.partition_number
LEFT JOIN sys.partition_range_values right_prv
        ON right_prv.function_id = ps.function_id
           AND right_prv.boundary_id = p.partition_number
where pst.object_id = object_id(quotename(@schema_name) + '.' + quotename(@table_name)) 
    AND used_page_count > 0 
    AND pst.index_id IN (0,1)/*Remove Nonclustered index counts*/

GROUP BY f.data_space_id,
        f.NAME,
        t.schema_id,
        t.name,
        p.partition_number,
        ps.name,
        pf.name,
        pf.boundary_value_on_right,
        left_prv.value,
        right_prv.value,
        ISNULL(STR(CAST(left_prv.value AS BIGINT)), '-INF')
        + CASE WHEN pf.boundary_value_on_right = 0 THEN ' < '
               ELSE ' <= '
          END + 'X' + CASE WHEN pf.boundary_value_on_right = 0 THEN ' <= '
                           ELSE ' < '
                      END + ISNULL(STR(CAST(right_prv.value AS BIGINT)), 'INF') ,
        row_count,
        p.OBJECT_ID,
        pst.index_id;

Then you can query the table valued function like so:

SELECT * FROM dbo.tvfPartitionAllocationDetails('dbo','mytablename');

This assumes no out of row or lob pages. If you have those, and want to display them, they can easily be added to the function.



来源:https://stackoverflow.com/questions/12688086/sql-server-partition-per-table-on-tenant-id-disk-space-used

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!