2012-10-02 25 views
1

我们目前正在开发多租户Web应用程序。 此应用程序将其所有数据存储在1个单一数据库中。Tenant ID上的每个表上的SQL Server分区 - 使用的磁盘空间

租户的数据行始终与租户ID一致。

目前我们正在考虑创建表分区,并将租户ID作为分区键。这是有道理的,因为所有查询中的99.9%将包含租户id作为where子句条件。如果我理解正确,SQL Server查询通过消除不包含分区键的表分区(在本例中为租户ID)来优化所有此类查询。

这一策略的任何意见(严重的缺陷,或不使用文件组等,每个表的最大允许分区...),将不胜感激。

但是我的主要问题是: 我们要计算每个租户的磁盘使用情况。 SQL Server支持报告每个分区的磁盘使用情况(标准报告)。 是否有人知道T-SQL可以让我获得给定租户ID的所有表分区的磁盘使用情况?

回答

6

这是Kendra Little分区的一个很好的入门书。它应该帮助你回答是否分区的问题。 http://www.brentozar.com/archive/2012/03/how-decide-if-should-use-table-partitioning/

一个建议我必须是确保每个查询都打表使用分区消除谓词中。

至于文件组,请记住分区方案将分区映射到文件组。如果你想为每个租户做1个文件组,这可能会变得复杂。

对于SQL Server 2005 - 2008 R2,1,000个分区是表中可能包含的最大分区。到2012年,他们将限制增加到15,000个分区。如果您需要的不止于此,请将分区值空出来,并让范围决定数据将分配到哪个分区。

这里有一个表值函数,你可以使用分区来推导空间使用情况:

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; 

然后你就可以查询像这样的表值函数:

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

这是假设没有排出来的或吊球页面。如果你有这些,并想要显示它们,可以很容易地将它们添加到该功能中。

+0

哇布莱恩,谢谢你花时间! 好文章! –