如何判断索引是否包含varchar(max)类型的列?

时间:2009-03-03 16:56:20

标签: sql sql-server tsql

我正在处理我的MSSQL索引碎片整理脚本。某些索引可以在线重建,其他类型则不能。

对于聚簇索引,可以很容易地查看该表是否包含任何LOB列,但对于非聚簇索引,我需要明确知道该特定索引是否包含任何LOB列。

我曾经通过查看dm_db_index_physical_stats中的alloc_unit_type_desc来做到这一点,但这对varchar(max)和xml类型的列不起作用。

这不适用于我的数据库,因此我不想讨论索引是否合适,让我们接受它存在并且我希望脚本能够处理这种情况。

有谁知道我可以写什么样的SQL来检查这个?假设我在标量变量中包含所有相关的对象ID和对象名称。

4 个答案:

答案 0 :(得分:3)

如果您的char或nvarchar具有最大长度,那么它将在sys.columns表中有一个条目,该字段具有该字段的相应系统类型ID,其中-1为最大长度。

因此,如果要查找具有varchar(系统类型标识为167)的所有索引的所有id,则执行此操作:

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

答案 1 :(得分:0)

我认为对于“max”列,sys.columns表中的length或size字段应为-1。没有在我面前的文档,但请告诉我这是否有效。

答案 2 :(得分:0)

小心,伙计们。当涉及到LOB时,聚集指数是一种不同的动物。让我们做一个测试,看看我的意思。

首先,让我们设置一个测试表。此测试不需要任何数据,但我们确实有一个Clustered Index(IndexID = 1)作为PK。我们还有一个非聚集索引(IndexID = 2),它不包含LOB列作为INCLUDE,我们还有一个非聚集索引,它包含一个LOB列作为INCLUDE。这是测试设置代码......

--========================================================================
--      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)
;

现在,让我们尝试使用sys.index_columns的代码来查找包含LOB的索引。我已经在WHERE子句中注释掉了system_type_id来打开它......

--========================================================================
--      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
;

这里是上面运行的输出......

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

它无法告诉Clustered Index包含LOB,因为LOB不是索引列之一。尝试重建此Clustered Index会导致失败。

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

Msg 2725,Level 16,State 2,Line 1在线索引操作不能   为索引' PK_IndexTest_Has_LOB'执行因为索引包含   专栏' SomeLOB1'数据类型text,ntext,image,varchar(max),   nvarchar(max),varbinary(max)或xml。对于非聚集索引   column可以是索引的include列,用于聚簇索引   可以是表格的任何一列。在drop_existing列的情况下   可能是新旧索引的一部分。必须执行该操作   脱机。

向Remus Rusanu提示(系统不会让我发布链接)......

......我们可以尝试一些不同的东西。每个索引(集群,非集群或HEAP)都显示为分配单元,还将标识行内数据,行外数据和LOB。以下代码查找具有与其关联的LOB的所有索引...甚至是聚簇索引。

--===== 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'
;

为此特定测试生成以下输出。请注意,它确实通过object_id和index_id获取了Clustered Index,其中基于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

答案 3 :(得分:0)

您还可以检查DMV-sys.dm_db_index_physical_stats

它有一个alloc_unit_type_desc列,可以告诉我们索引是否具有 LOB_DATA

SELECT S.name as 'Schema',
T.name as 'Table',
I.name as 'Index',
DDIPS.avg_fragmentation_in_percent,
DDIPS.page_count,
DDIPS.alloc_unit_type_desc
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'LIMITED') AS DDIPS
INNER JOIN sys.tables T on T.object_id = DDIPS.object_id
INNER JOIN sys.schemas S on T.schema_id = S.schema_id
INNER JOIN sys.indexes I ON I.object_id = DDIPS.object_id
AND DDIPS.index_id = I.index_id
WHERE DDIPS.database_id = DB_ID()
and I.name is not null
and DDIPS.alloc_unit_type_desc = 'LOB_DATA'