utilisation de l'espace sur sys.allocation_units et sp_spaceused

13

C'est un fait connu que les DMV ne contiennent pas d'informations précises concernant le nombre de pages et le nombre de lignes. Cependant, lorsque vous avez mis à jour les statistiques, je ne vois pas pourquoi elles ne le seraient pas.

Je travaille sur un outil de surveillance, je veux connaître la taille du disque de chaque index et données, etc. Finalement, je voudrais trouver le bon facteur de remplissage, etc.

L'espace utilisé par ma fonction et l'ancien sp_spaceused diffère un peu sur l'utilisation de l'espace, mais pas sur le nombre d'enregistrements.

Pouvez-vous voir s'il manque quelque chose dans ma sélection?

c'est le sp_spaceused (alors je convertis les nombres en Mo):

sp_spaceused 'tblBOrderRelationship'
go

select 318008/1024.00 AS reserved,
140208/1024.00  AS data,
177048/1024.00 AS index_size,
752/1024.00    AS unused

entrez la description de l'image ici

Mais lorsque j'exécute ma sélection, code ci-dessous \ image ci-dessous, j'obtiens des chiffres légèrement différents.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT 
    schema_name(t.schema_id) as SchemaName,
    t.NAME AS TableName,
    t.type_desc,
    t.is_ms_shipped,
    t.is_published,
    t.lob_data_space_id,
    t.filestream_data_space_id,
    t.is_replicated,
    t.has_replication_filter,
    t.is_merge_published,
    t.is_sync_tran_subscribed,
    --t.is_filetable,
    i.name as indexName,
    i.type_desc,
    i.is_unique,
    i.is_primary_key,
    i.is_unique_constraint,
    i.fill_factor,
    i.is_padded,


    sum(p.rows)               OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as RowCounts,
    sum(a.total_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as TotalPages, 
    sum(a.used_pages)         OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as UsedPages, 
    sum(a.data_pages)         OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as DataPages,

    (sum(a.total_pages)       OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024 as TotalSpaceMB, 
    (sum(a.used_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024 as UsedSpaceMB, 
    (sum(a.data_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024 as DataSpaceMB
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
WHERE 
    t.NAME NOT LIKE 'dt%' AND
    i.OBJECT_ID > 255 
AND T.NAME = 'tblBOrderRelationship'

les figures

les figures

l'image plus grande, y compris les noms d'index l'image plus grande, y compris les noms d'index

Maintenant, faisons quelques calculs pour vérifier les résultats:

--==================================
-- the figures from sp_spaceused
--==================================
select 318008/1024.00 AS reserved,
140208/1024.00  AS data,
177048/1024.00 AS index_size,
752/1024.00    AS unused

--==================================
-- the figures from my select
--==================================
select 137+61+56+54 AS reserved,
       137 AS data,
       61+56+54 AS index_size

entrez la description de l'image ici

Ce n'est pas si loin, vraiment, à part le fait que je n'ai pas calculé l'espace inutilisé!

Que puis-je faire pour rendre cela précis?

APRÈS CHANGEMENTS:

Après avoir remplacé 1024 par 1024,00, les résultats sont beaucoup plus précis. J'ai remarqué que des enregistrements ont été insérés dans le tableau en question, et évidemment les statistiques ne sont pas si à jour, mais les résultats correspondent toujours (différence de moins de 1 Mo - ce qui me convient)

Les nouveaux jeux de résultats sont les suivants:

--==================================
-- the figures from sp_spaceused
--==================================
select
318072 /1024.00 AS reserved,
140208 /1024.00 AS data,
177096 /1024.00 AS index_size,
768 /1024.00 AS unused
go

--==================================
-- the figures from my select
--==================================
select 137.7578125+61.7968750+56.4218750+54.6406250 as reserved,
       137.7578125 as data,
       61.7968750+56.4218750+54.6406250 as index_size

entrez la description de l'image ici

Marcello Miorelli
la source

Réponses:

24

Même si vous avez résolu le problème d'arrondi immédiat, l'algorithme global pour obtenir les statistiques par objet / index est incorrect. Il ne gère pas correctement les données LOB et de débordement de ligne. Il exclut également: les vues indexées, les index FullText, les index XML et quelques autres cas. Par conséquent, vous pourriez ne pas voir toutes vos données.

Ce qui suit est une adaptation du code que j'ai posté à une réponse sur StackOverflow ( sp_spaceused - Comment mesurer la taille en Go dans toutes les tables en SQL ) qui gère tous les cas qui sp_spaceusedgère. Cette question SO ne concernait que les statistiques par objet, pas par index, j'ai donc ajusté le code pour gérer les choses au niveau de l'index.

;WITH agg AS
(   -- Get info for Tables, Indexed Views, etc
    SELECT  ps.[object_id] AS [ObjectID],
            ps.index_id AS [IndexID],
            NULL AS [ParentIndexID],
            NULL AS [PassThroughIndexName],
            NULL AS [PassThroughIndexType],
            SUM(ps.in_row_data_page_count) AS [InRowDataPageCount],
            SUM(ps.used_page_count) AS [UsedPageCount],
            SUM(ps.reserved_page_count) AS [ReservedPageCount],
            SUM(ps.row_count) AS [RowCount],
            SUM(ps.lob_used_page_count + ps.row_overflow_used_page_count)
                    AS [LobAndRowOverflowUsedPageCount]
    FROM    sys.dm_db_partition_stats ps
    GROUP BY    ps.[object_id],
                ps.[index_id]
    UNION ALL
    -- Get info for FullText indexes, XML indexes, Spatial indexes, etc
    SELECT  sit.[parent_id] AS [ObjectID],
            sit.[object_id] AS [IndexID],
            sit.[parent_minor_id] AS [ParentIndexID],
            sit.[name] AS [PassThroughIndexName],
            sit.[internal_type_desc] AS [PassThroughIndexType],
            0 AS [InRowDataPageCount],
            SUM(ps.used_page_count) AS [UsedPageCount],
            SUM(ps.reserved_page_count) AS [ReservedPageCount],
            0 AS [RowCount],
            0 AS [LobAndRowOverflowUsedPageCount]
    FROM    sys.dm_db_partition_stats ps
    INNER JOIN  sys.internal_tables sit
            ON  sit.[object_id] = ps.[object_id]
    WHERE   sit.internal_type IN
               (202, 204, 207, 211, 212, 213, 214, 215, 216, 221, 222, 236)
    GROUP BY    sit.[parent_id],
                sit.[object_id],
                sit.[parent_minor_id],
                sit.[name],
                sit.[internal_type_desc]
), spaceused AS
(
SELECT  agg.[ObjectID],
        agg.[IndexID],
        agg.[ParentIndexID],
        agg.[PassThroughIndexName],
        agg.[PassThroughIndexType],
        OBJECT_SCHEMA_NAME(agg.[ObjectID]) AS [SchemaName],
        OBJECT_NAME(agg.[ObjectID]) AS [TableName],
        SUM(CASE
                WHEN (agg.IndexID < 2) THEN agg.[RowCount]
                ELSE 0
            END) AS [Rows],
        SUM(agg.ReservedPageCount) * 8 AS [ReservedKB],
        SUM(agg.LobAndRowOverflowUsedPageCount +
            CASE
                WHEN (agg.IndexID < 2) THEN (agg.InRowDataPageCount)
                ELSE 0
            END) * 8 AS [DataKB],
        SUM(agg.UsedPageCount - agg.LobAndRowOverflowUsedPageCount -
            CASE
                WHEN (agg.IndexID < 2) THEN agg.InRowDataPageCount
                ELSE 0
            END) * 8 AS [IndexKB],
        SUM(agg.ReservedPageCount - agg.UsedPageCount) * 8 AS [UnusedKB],
        SUM(agg.UsedPageCount) * 8 AS [UsedKB]
FROM    agg
GROUP BY    agg.[ObjectID],
            agg.[IndexID],
            agg.[ParentIndexID],
            agg.[PassThroughIndexName],
            agg.[PassThroughIndexType],
            OBJECT_SCHEMA_NAME(agg.[ObjectID]),
            OBJECT_NAME(agg.[ObjectID])
)
SELECT sp.SchemaName,
       sp.TableName,
       sp.IndexID,
       CASE
         WHEN (sp.IndexID > 0) THEN COALESCE(si.[name], sp.[PassThroughIndexName])
         ELSE N'<Heap>'
       END AS [IndexName],
       sp.[PassThroughIndexName] AS [InternalTableName],
       sp.[Rows],
       sp.ReservedKB,
       (sp.ReservedKB / 1024.0 / 1024.0) AS [ReservedGB],
       sp.DataKB,
       (sp.DataKB / 1024.0 / 1024.0) AS [DataGB],
       sp.IndexKB,
       (sp.IndexKB / 1024.0 / 1024.0) AS [IndexGB],
       sp.UsedKB AS [UsedKB],
       (sp.UsedKB / 1024.0 / 1024.0) AS [UsedGB],
       sp.UnusedKB,
       (sp.UnusedKB / 1024.0 / 1024.0) AS [UnusedGB],
       so.[type_desc] AS [ObjectType],
       COALESCE(si.type_desc, sp.[PassThroughIndexType]) AS [IndexPrimaryType],
       sp.[PassThroughIndexType] AS [IndexSecondaryType],
       SCHEMA_ID(sp.[SchemaName]) AS [SchemaID],
       sp.ObjectID
       --,sp.ParentIndexID
FROM   spaceused sp
INNER JOIN sys.all_objects so -- in case "WHERE so.is_ms_shipped = 0" is removed
        ON so.[object_id] = sp.ObjectID
LEFT JOIN  sys.indexes si
       ON  si.[object_id] = sp.ObjectID
      AND  (si.[index_id] = sp.IndexID
         OR si.[index_id] = sp.[ParentIndexID])
WHERE so.is_ms_shipped = 0
--so.[name] LIKE N''  -- optional name filter
--ORDER BY ????
Solomon Rutzky
la source
8

Vous divisez INTdonc vous n'obtiendrez jamais qu'une réponse entière.

Vous vous retrouvez donc avec un problème d'arrondi sur vos propres calculs d'espace. C'est pourquoi, lorsque vous les additionnez, vous obtenez une réponse différente.

Bien que la différence soit minime, il s'agit de l'un de ces «pièges» clés avec la gestion des nombres non entiers dans SQL Server.

Modifiez votre requête de partition dans la procédure:

(sum(a.total_pages)       OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024.00 as TotalSpaceMB, 
(sum(a.used_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024.00 as UsedSpaceMB, 
(sum(a.data_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024.00 as DataSpaceMB
Mark Sinkinson
la source