web-dev-qa-db-fra.com

Somme des longueurs de données ne correspondant pas la taille de la table de SYS.Allocation_units

J'avais l'impression que si je pouvais résumer la DATALENGTH() de tous les champs pour tous les enregistrements d'une table dans laquelle j'aurais la taille totale de la table. Suis-je trompé?

SELECT 
SUM(DATALENGTH(Field1)) + 
SUM(DATALENGTH(Field2)) + 
SUM(DATALENGTH(Field3)) TotalSizeInBytes
FROM SomeTable
WHERE X, Y, and Z are true

J'ai utilisé cette requête ci-dessous (que je suis arrivé en ligne pour obtenir des tailles de table, des index clusters uniquement afin qu'il n'inclut pas les index NC) pour obtenir la taille d'une table particulière dans ma base de données. À des fins de facturation (nous facturons nos départements par la quantité d'espace qu'ils utilisent) Je dois savoir combien d'espace chaque service utilisé dans ce tableau. J'ai une requête qui identifie chaque groupe dans la table. J'ai juste besoin de comprendre combien d'espace chaque groupe prend chaque groupe.

L'espace par rangée peut balancer sauvagement en raison de VARCHAR(MAX) champs de la table, donc je ne peux donc pas simplement prendre une taille moyenne * le rapport entre les rangées d'un département. Lorsque j'utilise l'approche DATALENGTH() décrite ci-dessus, je n'obtiens que 85% de l'espace total utilisé dans la requête ci-dessous. Les pensées?

SELECT 
s.Name AS SchemaName,
t.NAME AS TableName,
p.rows AS RowCounts,
(SUM(a.total_pages) * 8)/1024 AS TotalSpaceMB, 
(SUM(a.used_pages) * 8)/1024 AS UsedSpaceMB, 
((SUM(a.total_pages) - SUM(a.used_pages)) * 8)/1024 AS UnusedSpaceMB
FROM 
    sys.tables t with (nolock)
INNER JOIN 
    sys.schemas s with (nolock) ON s.schema_id = t.schema_id
INNER JOIN      
    sys.indexes i with (nolock) ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p with (nolock) ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a with (nolock) ON p.partition_id = a.container_id
WHERE 
    t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
    AND i.type_desc = 'Clustered'
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    TotalSpaceMB desc

Il a été suggéré de créer un indice filtré pour chaque département ou de partitionner la table afin que je puisse directement interroger l'espace utilisé par index. Les index filtrés pourraient être créés par programme (et reculé à nouveau pendant une fenêtre de maintenance ou lorsque je dois effectuer la facturation périodique), au lieu d'utiliser l'espace tout le temps (les partitions seraient meilleures à cet égard).

J'aime cette suggestion et je le ferais généralement. Mais pour être honnête, j'utilise le "chaque département" comme exemple pour expliquer pourquoi j'ai besoin de cela, mais pour être honnête, ce n'est pas vraiment pourquoi. En raison de raisons de confidentialité, je ne peux pas expliquer la raison exacte pour laquelle j'ai besoin de ces données, mais elle est analogue aux différents départements.

En ce qui concerne les indices non clusters sur ce tableau: si je peux obtenir la taille des index NC, ce serait génial. Toutefois, les index NC représentent <1% de la taille de l'indice en cluster. Nous ne comprenons donc pas ceux. Cependant, comment allons-nous inclure les index de NC de toute façon? Je ne peux même pas avoir une taille précise pour l'index en cluster :)

11
Chris Woods

Peut-être que c'est une réponse grunge, mais c'est ce que je ferais.

Ainsi, la longueur de données ne représente que 86% du total. C'est encore très représentatif. Les frais généraux de l'excellente réponse de Sruzky devraient avoir une assez séparée.

J'utiliserais votre deuxième requête (pages) pour le total. Et utilisez la première (longueur de données) pour allouer la scission. De nombreux coûts sont alloués à l'aide d'une normalisation.

Et vous devez envisager une réponse plus étroite va augmenter les coûts, de sorte que même le département qui a perdu une scission peut encore payer plus.

6
paparazzo