web-dev-qa-db-ja.com

SQL Server 2008の一意キーと一意インデックス

countriesというテーブルがあり、country_name列は、SQL Server 2008 R2で「一意のキー」タイプの「インデックス/キー」を作成することにより一意になります。

しかし、次の質問があります。

  1. タイプ「固有キー」の「インデックス/キー」を作成すると、この列に非クラスター化インデックスが自動的に作成されますか?
  2. タイプを「固有キー」から「インデックス」に変更し、IsUnique値を「はい」のままにすると、違いはありますか?
  3. それで、なぜ「ユニークキー」と「インデックス」の2つのオプションがあるのでしょうか?
51
john Gu

一意の制約は、一意のインデックスとしてバックグラウンドで実装されているため、どのように指定するかは重要ではありません。私は単に次のように実装する傾向があります:

ALTER TABLE dbo.foo ADD CONSTRAINT UQ_bar UNIQUE(bar);

代わりに、一意のインデックスを作成する人もいます。

CREATE UNIQUE INDEX IX_UQ_Bar ON dbo.foo(bar);

違いは意図にあります-一意性/ビジネスルールを適用する制約を作成する場合、制約を作成します。クエリパフォーマンスを支援するために制約を作成する場合、一意のインデックスを作成する方が論理的です。繰り返しますが、カバーの下では同じ実装ですが、そこにたどり着くまでの道はあなたの意図を文書化するのに役立つかもしれません。

以前のSybase機能とANSI標準の両方に準拠するための複数のオプションがあると思います(一意の制約は1つのNULL値のみを許可するため、一意の制約は標準100%に準拠していませんが、一意のインデックス、一方、WHERE句(WHERE col IS NOT NULL)SQL Server 2008以降)。

68
Aaron Bertrand

言及すべきもう1つのことは、インデックスを作成する場合、included columnsを指定できることです。これは、country_nameで検索する場合、SQLコードがより速く動作するのに役立ちます。

CREATE UNIQUE NONCLUSTERED INDEX IX_UQ_Bar
ON dbo.foo (
    bar
)
INCLUDE (foo_other_column)
GO

SELECT foo_other_column FROM Foo WHERE bar = 'test'

SQLサーバーは、インデックス自体に「foo_other_column」を格納します。一意制約の場合、最初に 'test'のインデックスを見つけ、次にfooテーブルの行を検索し、そこでのみ "foo_other_column"を取得します。

14

一意のインデックスまたは一意の制約の間に違いはなく、パフォーマンスの違いもありません。ただし、一意の制約に対して一部のインデックス作成オプションを使用できない場合、作成にはいくつかの違いがあります。

1
Noah

SqlMetal.exeを使用してDBMLまたはLinqToSqlエンティティを出力する場合:

  • 外部キーが一意のキーを使用する場合、期待どおりに関連付けが取得されます。
  • 外部キーが一意のインデックスを使用する場合、表示されません。

その理由は、SqlMetalの実装にあります。データベース情報スキーマ、特にキー列の使用法を照会します。一意のキーはそこに表示されますが、一意のインデックスは表示されません。

SELECT TABLE_NAME, CONSTRAINT_NAME, COLUMN_NAME, ORDINAL_POSITION
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE;
0
Tomas Karban

最も重要な点の1つは、一意キー制約ではできない一意性を維持しながら列値をnullにしたいが、一意キーインデックスでは一意性を維持して列値をnullにしたい場合です。そのため、Null対応の列で一意の列が必要な場合は一意のインデックスが必要です。Null対応でない列が必要な場合は一意のキー制約が必要です。

0
Amit

上記の優れた回答以外に、ここに2セントを追加します。

一意のキーは制約であり、一意のインデックスを使用してそれ自体を強制します。主キーが通常、クラスター化された一意のインデックスによって実施されるのと同じように。論理的に言えば、制約とインデックスは2つの異なるものです。ただし、RDBMSでは、インデックスを使用して制約を物理的に実装できます。

SQLサーバーで一意制約を使用してテーブルが作成された場合、制約オブジェクト一意インデックスの両方が表示されます。

create table dbo.t (id  int constraint my_unique_constraint unique (id));

select [Constraint]=name from sys.key_constraints 
where parent_object_id = object_id('dbo.t');

select name, index_id, type_desc from sys.indexes
where object_id = object_id('dbo.t')
and index_id > 0;

以下を取得します(制約とインデックス)

enter image description here

ただし、制約を作成せず、次のように一意のインデックスのみを作成する場合

create table dbo.t2 (id int );
create unique index my_unique_constraint on dbo.t2 (id);

select [Constraint]=name from sys.key_constraints 
where parent_object_id = object_id('dbo.t2');

select name, index_id, type_desc from sys.indexes
where object_id = object_id('dbo.t2')
and index_id > 0

制約オブジェクトは作成されていません(インデックスのみが作成されています)。

enter image description here

「理論的」観点から見ると、SQL Serverでは、制約はobject_id値を持つオブジェクトであり、スキーマにバインドされますが、インデックスはオブジェクトではなく、object_id値もスキーマ関連もありません。

0
jyao

一意性を強制する3番目のオプションは、Nullable Unique Indexを許可するためにFiltered Unique-Indexを使用することです。
これは、Unique-Constraintsでは機能しませんnot
たとえば、一意の値のみを許可する列があるとします。
ただし、複数のNULL値が存在しない場合でもサポートしたい。
Filtered Unique-Indexのみが機能します。

CREATE UNIQUE NONCLUSTERED INDEX [UF_Employee_UserID] ON [dbo].[Employee]
(
    [UserID] ASC--Not all Employees have a UserID to log into the System.
)
WHERE ([UserID] IS NOT NULL)--Enforce Uniqueness when not null.

現在、GUIを使用してテーブルを編集している間は、SSMSでフィルターインデックスを作成できません。
ただし、手動でインデックスを作成する代わりにGUIを使用する場合(上記のように)、開いているすべてのテーブルデザイナーを閉じて、オブジェクトエクスプローラーでインデックス自体のプロパティを開くことができます。 。

0
MikeTeeVee