web-dev-qa-db-ja.com

同じ列にクラスター化インデックスと非クラスター化インデックスを付けることは理にかなっていますか

同じ列にクラスター化インデックスと非クラスター化インデックスを付けることは理にかなっていますか

私はデータベースとそれに付随するWebサービスを継承しました。

重複のインデックスを見ると、同じ列(1つの列と同じ方法で並べ替えられている)を指す2つのインデックスが見つかります。 1つはクラスター化されており、1つはクラスター化されていません。これが唯一の違いです。

  1. これらの両方を維持することは理にかなっていますか?
  2. どれを削除したらいいですか
5
Maestro1024

2つの質問に取り組む前に、クラスター化インデックスと非クラスター化インデックスの違いを簡単に定義しましょう。

クラスタ化インデックスは、キー列で編成されています。また、行構造の一部として1つおきの列が含まれます(つまり、行全体が含まれます)。

非クラスター化インデックスもキー列によって編成されます。クラスター化キー列(テーブルがクラスター化されている場合)、または行へのポインター(テーブルがヒープの場合)が暗黙的に含まれます。 INCLUDE列が明示的に指定されている場合、それらもインデックス構造に含まれます。

これらの両方を維持することは理にかなっていますか?

非クラスター化インデックスがクラスター化インデックスを「複製」することが理にかなっているという、まれなケースがあります。テーブルを頻繁にスキャンするクエリがあり、クラスタリングキー列のみを使用する場合、クエリオプティマイザは非クラスタ化インデックスの使用を優先します。非クラスター化インデックスには完全な行データが含まれていないため、必要な物理スペースは少なくなります。必要な物理スペースが少ないため、SQL Serverは少ないIOでテーブルをスキャンでき、パフォーマンス上の理由からそれを利用します。

sys.dm_db_index_usage_statsuser_seeksおよびuser_scans 2つのインデックス。これは、2つのインデックスがどのように使用されているかを確認し、2つのインデックスの有用性を判断するのに役立ちます。

どれを削除したら、どれを削除する必要がありますか?

原則として、ほとんどのテーブルにはクラスター化インデックスが必要です。 (それは完全に他のトピックです)。インデックスの使用法やデータアクセスに関する詳細がわからないので、1つ削除すると、非クラスター化インデックスも削除されると思います(ただし、これは私が知っていることに基づいた推測です)。

クラスタリングキー、データ、データアクセスパターンなどに応じて、最も正しい答えは、クラスタ化インデックスを削除して別のクラスタ化インデックスを作成することです。 Effective Clustered Indexes の詳細をご覧ください。

11
AMtwo

インデックスの統計を知らなくても、安全または良い答えがあるかどうかはわかりません。まず、実際にどれだけ使用されているか、どれが使用されていないかを確認してから、何を保持する必要があるかを判断する必要があります。これは、どのインデックスが使用されているか、または使用されていないかを判断するときに使用します。

CREATE TABLE #IndexStats
(
ObjectName VARCHAR(200),
    IndexName VARCHAR(200),
    UserSeeks BIGINT,
    UserScans BIGINT,
    UserLookups BIGINT,
    UserUpdates BIGINT
)

INSERT INTO
    #IndexStats
SELECT
    OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME],
    I.[NAME] AS [INDEX NAME],
    USER_SEEKS,
    USER_SCANS,
    USER_LOOKUPS,
    USER_UPDATES
FROM
    SYS.DM_DB_INDEX_USAGE_STATS AS S
INNER JOIN
    SYS.INDEXES AS I ON I.[OBJECT_ID] = S.[OBJECT_ID] AND I.INDEX_ID = S.INDEX_ID
WHERE
    OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1
ORDER BY
    USER_LOOKUPS DESC

SELECT
    s.[name] AS 'Schema',
    t.[name] AS 'Table',
    i.[name] AS 'Index',
    p.avg_fragmentation_in_percent AS 'Fragmentation Percent',
    p.page_count AS 'Page Count',
    i.fill_factor AS 'Fill Factor',
    i.is_padded AS 'Padding',
    IDX.UserLookups,
    IDX.UserScans,
    IDX.UserSeeks,
    IDX.UserUpdates
FROM
    sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS p
INNER JOIN
    sys.tables t ON t.[object_id] = p.[object_id]
INNER JOIN
    sys.schemas s ON t.[schema_id] = s.[schema_id]
INNER JOIN
    sys.indexes AS i ON i.[object_id] = p.[object_id] AND p.index_id = i.index_id
JOIN
    #IndexStats IDX ON IDX.ObjectNAME = t.name
WHERE
    p.database_id = DB_ID()
    AND p.avg_fragmentation_in_percent >= 50
ORDER BY
    p.avg_fragmentation_in_percent DESC, IDX.UserLookups ASC

DROP TABLE #IndexStats
1
Jason B.