2009-03-03 4 views
3

Je travaille sur mon script de défragmentation d'index MSSQL. Certains types d'index peuvent être reconstruits en ligne, et d'autres ne le peuvent pas. Pour les index clusterisés, il est assez facile de voir si la table contient des colonnes LOB, mais pour un index non cluster, je dois spécifiquement savoir s'il existe des colonnes LOB couvertes par cet index spécifique. J'avais l'habitude de faire cela en regardant alloc_unit_type_desc dans dm_db_index_physical_stats, mais cela ne fonctionne pas pour les colonnes de type varchar (max) et xml.Comment puis-je savoir si un index contient une colonne de type varchar (max)?

Ce n'est pas pour ma base de données, donc je ne veux pas entrer dans une discussion pour savoir si l'index est approprié, acceptons simplement qu'il existe et que je voudrais que le script puisse gérer cette situation.

Est-ce que quelqu'un sait quel type de SQL je peux écrire pour vérifier cela? Supposons que j'ai tous les identifiants d'objets et noms d'objets pertinents dans les variables scalaires.

Répondre

0

Je pense que pour les colonnes "max", la taille ou la taille de la feild dans la table sys.columns doit être -1. Ne pas avoir la documentation devant moi, mais laissez-moi savoir si cela fonctionne.

3

Si vous avez un caractère ou nvarchar avec une longueur maximale, alors il aura une entrée dans la table sys.columns avec l'ID de type de système approprié pour le champ, avec -1 comme longueur maximale.

Donc, si vous voulez trouver tous les IDs de tous les indices qui ont un varchar (identifiant de type de système 167), vous faites ceci:

select distinct 
    si.* 
from 
    sys.indexes as si 
     inner join sys.index_columns as ic on 
      ic.object_id = si.object_id and 
      ic.index_id = si.index_id 
      inner join sys.columns as sc on 
       sc.object_id = ic.object_id and 
       sc.column_id = ic.column_id 
where 
    sc.system_type_id = 167 and 
    sc.max_length = -1 
+0

Merci, je pense que ça va faire l'affaire –

+0

Fèves fraîches. Je savais que c'était quelque chose avec -1 et la longueur. –

0

Attention, les gens. L'index clusterisé est un animal différent quand il s'agit de LOBs. Faisons un test pour voir ce que je veux dire.

Tout d'abord, configurons une table de test. Aucune donnée n'est nécessaire pour ce test mais nous avons un index clusterisé (IndexID = 1) comme PK. Nous avons également un Index Non Clustered (IndexID = 2) qui ne contient aucune colonne LOB en tant que INCLUDE et nous avons également un Index Non Clustered qui contient une colonne LOB en tant que INCLUDE. Voici le code de configuration de test ...

--======================================================================== 
--  Test Setup 
--======================================================================== 
--===== If the test table already exists, 
    -- drop it to make reruns in SSMS easier. 
    IF OBJECT_ID('dbo.IndexTest','U') IS NOT NULL 
     DROP TABLE dbo.IndexTest 
; 
GO 
--===== Create the test table 
CREATE TABLE dbo.IndexTest 
     (
     SomeID  INT IDENTITY(1,1) 
     ,SomeInt INT 
     ,SomeLOB1 VARCHAR(MAX) 
     ,CONSTRAINT PK_IndexTest_Has_LOB 
     PRIMARY KEY CLUSTERED (SomeID) 
     ) 
; 
--===== Add an index that has no INCLUDE of a LOB 
CREATE INDEX IX_Has_No_LOB 
    ON dbo.IndexTest (SomeInt) 
; 
--===== Add an index that has INCLUDEs a LOB 
CREATE INDEX IX_Includes_A_LOB 
    ON dbo.IndexTest (SomeInt) INCLUDE (SomeLOB1) 
; 

Maintenant, nous allons essayer le code qui utilise sys.index_columns pour trouver des indices qui contiennent LOB. Je l'ai commenté le system_type_id dans la clause WHERE pour l'ouvrir un peu ...

--======================================================================== 
--  Test for LOBs using sys.index_columns. 
--======================================================================== 
select distinct 
    si.* 
from 
    sys.indexes as si 
     inner join sys.index_columns as ic on 
      ic.object_id = si.object_id and 
      ic.index_id = si.index_id 
      inner join sys.columns as sc on 
       sc.object_id = ic.object_id and 
       sc.column_id = ic.column_id 
where 
    --sc.system_type_id = 167 and 
    sc.max_length = -1 
; 

est ici la sortie de la course ci-dessus ...

object_id name    index_id type type_desc ... 
----------- ----------------- ----------- ---- ------------ ... 
163204448 IX_Includes_A_LOB 3   2 NONCLUSTERED ... 

Il ne pouvait pas dire que l'index cluster contient un objet LOB car le LOB n'est pas l'une des colonnes d'index. Essayer de reconstruire cet index clusterisé provoquera un échec.

ALTER INDEX PK_IndexTest_Has_LOB 
    ON dbo.IndexTest REBUILD WITH (ONLINE = ON) 
; 

Msg 2725, niveau 16, état 2, opération d'index en ligne ligne 1 ne peut pas être réalisée pour l'indice 'PK_IndexTest_Has_LOB' parce que l'index contient colonne 'SomeLOB1' du texte de type de données, ntext, image, varchar (max), nvarchar (max), varbinary (max) ou xml. Pour les index non clusterisés, la colonne peut être une colonne include de l'index, pour l'index clusterisé, peut être n'importe quelle colonne de la table.En cas de drop_existing, la colonne pourrait faire partie d'un index nouveau ou ancien. L'opération doit être effectuée hors ligne.

Avec une pointe du chapeau à Remus Rusanu (système ne me laisse pas poster le lien) ...

... nous pouvons essayer quelque chose d'un peu différent. Chaque index (clusterisé, non clusterisé ou HEAP) apparaît comme une unité d'allocation et identifie également les données dans la rangée, les données hors ligne et les objets LOB. Le code suivant trouve tous les index qui ont un métier associé ... même l'index groupé.

--===== Find all indexes that contain any type of LOB 
SELECT SchemaName = OBJECT_SCHEMA_NAME(p.object_id) 
     ,ObjectName = OBJECT_NAME(p.object_id) 
     ,IndexName = si.name 
     ,p.object_id 
     ,p.index_id 
     ,au.type_desc 
    FROM sys.system_internals_allocation_units au --Has allocation type 
    JOIN sys.system_internals_partitions p  --Has an Index_ID 
    ON au.container_id = p.partition_id 
    JOIN sys.indexes si       --For the name of the index 
    ON si.object_id = p.object_id 
    AND si.index_id  = p.index_id 
    WHERE p.object_id  = OBJECT_ID('IndexTest') 
    AND au.type_desc = 'LOB_DATA' 
; 

Cela produit la sortie suivante pour ce test particulier. Notez qu'il a détecté l'index cluster par object_id et index_id, contrairement au code basé sur sys.index_columns.

SchemaName ObjectName IndexName   object_id index_id type_desc 
---------- ---------- -------------------- --------- -------- --------- 
dbo  IndexTest PK_IndexTest_Has_LOB 163204448 1  LOB_DATA 
dbo  IndexTest IX_Includes_A_LOB 163204448 3  LOB_DATA 
Questions connexes