Les tables système SQL Server peuvent-elles être défragmentées?

15

Nous avons plusieurs bases de données dans lesquelles un grand nombre de tables sont créées et supprimées. D'après ce que nous pouvons en dire, SQL Server n'effectue aucune maintenance interne sur les tables de base du système , ce qui signifie qu'elles peuvent devenir très fragmentées au fil du temps et gonflées en taille. Cela exerce une pression inutile sur le pool de mémoire tampon et a également un impact négatif sur les performances des opérations telles que le calcul de la taille de toutes les tables d'une base de données.

Quelqu'un a-t-il des suggestions pour minimiser la fragmentation sur ces tables internes principales? Une solution évidente pourrait éviter de créer autant de tables (ou de créer toutes les tables transitoires dans tempdb), mais pour les besoins de cette question, disons que l'application n'a pas cette flexibilité.

Edit: Des recherches supplémentaires montrent cette question sans réponse , qui semble étroitement liée et indique qu'une certaine forme de maintenance manuelle via ALTER INDEX...REORGANIZEpeut être une option.


Recherches initiales

Les métadonnées sur ces tables peuvent être consultées dans sys.dm_db_partition_stats:

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136

Cependant, sys.dm_db_index_physical_statsne semble pas prendre en charge l'affichage de la fragmentation de ces tables:

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM sys.dm_db_index_physical_stats(
    DB_ID(),
    OBJECT_ID('sys.syscolpars'),
    NULL,
    NULL,
    'DETAILED'
)

Les scripts d'Ola Hallengren contiennent également un paramètre pour prendre en compte la défragmentation des is_ms_shipped = 1objets, mais la procédure ignore silencieusement les tables de base du système même si ce paramètre est activé. Ola a précisé qu'il s'agit du comportement attendu; seules les tables utilisateur (pas les tables système) qui sont ms_shipped (par exemple msdb.dbo.backupset) sont prises en compte.

-- Returns code 0 (successful), but does not do any work for system base tables.
-- Instead of the expected commands to update statistics and reorganize indexes,
-- no commands are generated. The script seems to assume the target tables will
-- appear in sys.tables, but this does not appear to be a valid assumption for
-- system tables like sys.sysrowsets or sys.syscolpars.
DECLARE @result int;
EXEC @result = IndexOptimize @Databases = 'Test',
        @FragmentationLow = 'INDEX_REORGANIZE',
        @FragmentationMedium = 'INDEX_REORGANIZE',
        @FragmentationHigh = 'INDEX_REORGANIZE',
        @PageCountLevel = 0,
        @UpdateStatistics = 'ALL',
        @Indexes = '%Test.sys.sysrowsets.%',
        -- Proc works properly if targeting a non-system table instead
        --@Indexes = '%Test.dbo.Numbers.%',
        @MSShippedObjects = 'Y',
        @Execute = 'N';
PRINT(@result);


Informations supplémentaires demandées

J'ai utilisé une adaptation de la requête d'Aaron sous l'inspection de l'utilisation du pool de mémoire tampon de table système, et cela a révélé qu'il y a des dizaines de Go de tables système dans le pool de mémoire tampon pour une seule base de données, avec environ 80% de cet espace étant de l'espace libre dans certains cas .

-- Compute buffer pool usage by system table
SELECT OBJECT_NAME(p.object_id),
    COUNT(b.page_id) pages,
    SUM(b.free_space_in_bytes/8192.0) free_pages
FROM sys.dm_os_buffer_descriptors b
JOIN sys.allocation_units a
    ON a.allocation_unit_id = b.allocation_unit_id
JOIN sys.partitions p
    ON p.partition_id = a.container_id
    AND p.object_id < 1000 -- A loose proxy for system tables
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY pages DESC

entrez la description de l'image ici

Geoff Patterson
la source

Réponses:

11

Êtes-vous sûr d'avoir identifié positivement et précisément cette table système comme la seule source de "pression inutile sur le pool de mémoire tampon et ayant également un impact négatif sur les performances des opérations telles que le calcul de la taille de toutes les tables dans une base de données"? Êtes-vous sûr que cette table système n'est pas autogérée de telle manière que (a) la fragmentation soit minimisée ou maintenue en échec secrètement ou simplement (b) gérée efficacement en mémoire afin que les niveaux de défragmentation n'affectent vraiment pas grand-chose?

Vous pouvez voir combien de pages sont en cours d'utilisation, et vous pouvez voir combien d'espace libre est sur les pages qui sont en mémoire ( page_free_space_percentest toujours NULLdans les allocations DMF, mais cela est disponible à partir du tampon DMV) - cela devrait vous donner une idée si ce qui vous inquiète est vraiment quelque chose dont vous devriez vous inquiéter:

SELECT 
  Number_of_Pages = COUNT(*), 
  Number_of_Pages_In_Memory = COUNT(b.page_id),
  Avg_Free_Space = AVG(b.free_space_in_bytes/8192.0) 
FROM sys.dm_db_database_page_allocations
(
  DB_ID(),
  OBJECT_ID(N'sys.syscolpars'),
  NULL,NULL,'DETAILED'
) AS p
LEFT OUTER JOIN sys.dm_os_buffer_descriptors AS b
ON b.database_id = DB_ID() 
AND b.page_id = p.allocated_page_page_id 
AND b.file_id = p.allocated_page_file_id;

Si votre nombre de pages est petit (comme probablement <10000 pour les tables système) ou si l'espace libre est "bas" (vous ne savez pas quels sont vos seuils typiques pour la réorganisation / reconstruction), concentrez-vous sur d'autres fruits plus intéressants et plus bas .

Si votre nombre de pages est important et que l'espace libre est "élevé", d'accord, je donne peut-être trop de crédit à SQL Server pour sa propre auto-maintenance. Comme vous l'avez montré dans l'autre question , cela fonctionne ...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

... et fait de réduire la fragmentation. Bien que cela puisse nécessiter des autorisations élevées (je n'ai pas essayé en tant que péon).

Peut-être pouvez-vous le faire périodiquement dans le cadre de votre propre maintenance, si cela vous fait du bien et / ou si vous avez des preuves que cela a un impact positif sur votre système.

Aaron Bertrand
la source
J'ai ajouté une autre réponse résumant ce que nous avons fini par faire, puis j'ai nettoyé les commentaires précédents ici. Merci encore pour votre aide!
Geoff Patterson
7

Sur la base des conseils de la réponse d'Aaron ainsi que de recherches supplémentaires, voici un bref résumé de l'approche que j'ai adoptée.

D'après ce que je peux dire, les options d'inspection de la fragmentation des tables de base du système sont limitées. Je suis allé de l'avant et j'ai déposé un problème de connexion pour offrir une meilleure visibilité, mais en attendant, il semble que les options incluent des choses comme l'examen du pool de mémoire tampon ou la vérification du nombre moyen d'octets par ligne.

J'ai ensuite créé une procédure pour effectuer `ALTER INDEX ... REORGANIZE sur toutes les tables de base du système . L'exécution de cette procédure sur quelques-uns de nos serveurs de développement les plus (ab) utilisés a montré que la taille cumulée des tables de base du système était réduite jusqu'à 50 Go (avec ~ 5 MM de tables d'utilisateurs sur le système, donc clairement un cas extrême).

L'une de nos tâches de maintenance nocturne, qui aide à nettoyer de nombreuses tables d'utilisateurs créées par divers tests unitaires et développement, prenait auparavant environ 50 minutes. Une combinaison de sp_whoisactive, sys.dm_os_waiting_taskset a DBCC PAGEmontré que les attentes étaient dominées par les E / S sur les tables de base du système.

Après la réorganisation de toutes les tables de base du système, la tâche de maintenance est tombée à environ 15 minutes. Il y avait encore quelques attentes d'E / S, mais elles ont été considérablement réduites, peut-être en raison d'une plus grande quantité de données restant dans le cache et / ou de plus de lectures en raison d'une fragmentation plus faible.

Par conséquent, ma conclusion est que l'ajout ALTER INDEX...REORGANIZEde tables de base système dans un plan de maintenance peut être une chose utile à considérer, mais probablement uniquement si vous avez un scénario dans lequel un nombre inhabituel d'objets est créé sur une base de données.

Geoff Patterson
la source
+1 pour votre question et la réponse - les internes sont un peu une boîte noire, et vous avez aidé à faire la lumière sur ce qui ressemble à un scénario de performance vraiment désagréable (même si le vôtre est un cas de bord).
Max Vernon