Как узнать, содержит ли индекс столбец типа varchar (max)? - PullRequest
3 голосов
/ 03 марта 2009

Я работаю над сценарием дефрагментации индекса MSSQL. Некоторые виды индексов могут быть перестроены онлайн, а другие - нет.

Для кластеризованных индексов достаточно легко увидеть, содержит ли таблица какие-либо столбцы больших объектов, но для некластеризованного индекса мне нужно конкретно знать, есть ли какие-либо столбцы больших объектов, охватываемые этим конкретным индексом.

Раньше я мог это делать, просматривая alloc_unit_type_desc в dm_db_index_physical_stats, но это не работает для столбцов типа varchar (max) и xml.

Это не для моей базы данных, поэтому я не хочу вступать в дискуссию о том, является ли индекс подходящим, давайте просто примем, что он существует и что я хотел бы, чтобы скрипт мог обрабатывать эта ситуация.

Кто-нибудь знает, какой SQL я могу написать, чтобы проверить это? Предположим, у меня есть все соответствующие идентификаторы объектов и имена объектов в скалярных переменных.

Ответы [ 3 ]

3 голосов
/ 03 марта 2009

Если у вас есть символ или nvarchar с максимальной длиной, он будет иметь запись в таблице sys.columns с соответствующим идентификатором типа системы для поля, с максимальной длиной -1.

Итак, если вы хотите найти все идентификаторы всех индексов, которые имеют varchar (системный идентификатор типа 167), вы должны сделать это:

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 голосов
/ 16 января 2016

Будьте осторожны, ребята. Кластерный индекс - это другое животное, когда дело доходит до больших объектов. Давайте сделаем тест, чтобы понять, что я имею в виду.

Сначала давайте настроим тестовую таблицу. Для этого теста данные не нужны, но у нас есть кластерный индекс (IndexID = 1) в качестве PK. У нас также есть некластеризованный индекс (IndexID = 2), который не содержит столбцы больших объектов как INCLUDE, и у нас также есть некластеризованный индекс, который содержит столбец больших объектов как 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 для поиска индексов, которые содержат большие объекты. Я закомментировал system_type_id в предложении WHERE, чтобы открыть его немного ...

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

Невозможно сказать, что кластерный индекс содержит большой объект, поскольку большой объект не является одним из столбцов индекса. Попытка перестроить этот кластерный индекс приведет к сбою.

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

Сообщение 2725, уровень 16, состояние 2, строка 1 Операция индексирования в сети не может быть выполняется для индекса 'PK_IndexTest_Has_LOB', поскольку индекс содержит столбец «SomeLOB1» типа данных text, ntext, image, varchar (max), nvarchar (max), varbinary (max) или xml. Для некластеризованного индекса столбец может быть столбцом включения индекса, для кластеризованного индекса - может быть любой столбец таблицы. В случае drop_existing столбца может быть частью нового или старого индекса. Операция должна быть выполнена в автономном режиме.

С кончиком шляпы Ремусу Русану (система не разрешила мне опубликовать ссылку) ...

... мы можем попробовать что-то немного другое. Каждый индекс (кластеризованный, некластеризованный или HEAP) отображается как единица выделения, а также идентифицирует данные в строке, данные вне строки и большие объекты. Следующий код находит ВСЕ индексы, с которыми связан большой объект ... даже Кластерный индекс.

--===== 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
0 голосов
/ 03 марта 2009

Я думаю, что для столбцов "max" длина или размер поля в таблице sys.columns должны быть -1. У меня нет документации, но дайте мне знать, если это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...