【问题标题】:How can I tell if an index contains a column of type varchar(max)?如何判断索引是否包含 varchar(max) 类型的列?
【发布时间】:2009-03-03 16:56:19
【问题描述】:

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

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

我以前可以通过查看 dm_db_index_physical_stats 中的 alloc_unit_type_desc 来做到这一点,但这不适用于 varchar(max) 和 xml 类型的列。

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

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

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

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

    因此,如果您想查找所有具有 varchar(系统类型 id 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 和长度的东西。
    【解决方案2】:

    我认为对于“max”列,sys.columns 表中的长度或大小字段应该是-1。我面前没有文档,但如果可行,请告诉我。

    【讨论】:

      【解决方案3】:

      小心,伙计们。就 LOB 而言,聚簇索引是另一种动物。让我们做一个测试,看看我的意思。

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

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

      它无法判断聚集索引包含 LOB,因为 LOB 不是索引列之一。尝试重建此聚集索引将导致失败。

        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”执行,因为该索引包含 数据类型为 text、ntext、image、varchar(max) 的列“SomeLOB1”, nvarchar(max)、varbinary(max) 或 xml。对于非聚集索引 列可以是索引的包含列,对于聚集索引它 可以是表格的任何列。在 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 获取了聚集索引,而基于 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
      

      【讨论】:

        【解决方案4】:

        您也可以查看 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'
        

        【讨论】:

          猜你喜欢
          • 2012-08-29
          • 1970-01-01
          • 1970-01-01
          • 2018-07-21
          • 2023-03-19
          • 2019-08-17
          • 2012-05-17
          • 2017-08-30
          • 2018-06-30
          相关资源
          最近更新 更多