问题
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