注意が必要な一意キー、主キーの利用（Azure Synapse Analytics SQLプール）

#Azure Synapse Analytics SQLプール上の特殊な一意キー、主キー
Azure Synapse Analytics SQLプールはSQL Serverとある程度互換性のあるDWHシステム等の大量のデータを格納・処理するワークロードに特化したデータベースサービスとなります。なので、もちろん一意キーや主キーなどの制約がSQL Server同様に存在します。一方で、これら制約の扱いはSQL Serverとは異なります。Azure Synapse Analytics SQLプール上のこれらの扱いをちゃんと理解していなければ、「結果不正」などにもつながりかねないので注意が必要です。

##一意キー（一意制約）
一意キー（一意制約）は、ALTER TABLE等で作成する場合に`NOT ENFORCED`が使用された場合にのみ作成が可能です。

```SQL
ALTER TABLE <テーブル名> ADD CONSTRAINT <制約名> UNIQUE(<カラム名>[,<カラム名>・・・]) NOT ENFORCED;
```

##主キー（プライマリ制約）
主キー（プライマリ制約）は、ALTER TABLE等で作成する場合に、`NONCLUSTERED`と`NOT ENFORCED`が使用された場合にのみ作成が可能です。

```SQL
ALTER TABLE <テーブル名> ADD CONSTRAINT <制約名> PRIMARY KEY NONCLUSTERED (<カラム名>[,<カラム名>・・・]) NOT ENFORCED;
```

##外部キー（参照整合性制約）
Azure Synapse Analyticsではサポートされていない制約となります。

#一意キー、主キー作成時の注意点
Azure Synapse Analyticsでのこれらの制約を使用する場合には以下の注意が必要です。
##注意点①そもそも制約としての機能を果たさない
注意点の1つ目は、構文の中に`NOT ENFORCED`（強制しない）が入っているので、既にお気づきかもしれませんが、作成することは出来ても、基本的に制約としての機能は果たしません。

例えば`TEST`テーブルを用意します。

```SQL
--TESTテーブルの作成
CREATE TABLE TEST(
	 ID		INT NOT NULL
	,NAME	NVARCHAR(200)
) WITH (
	DISTRIBUTION = ROUND_ROBIN,
	CLUSTERED COLUMNSTORE INDEX
);
```

このテーブルに`ID`列にて主キーを作成します。

```SQL
ALTER TABLE TEST ADD CONSTRAINT TEST_ID_PK PRIMARY KEY NONCLUSTERED (ID) NOT ENFORCED;
```

ここに重複データをインサートします。

```SQL
--主キー項目のID列が重複
INSERT INTO TEST VALUES(1,N'田中');
INSERT INTO TEST VALUES(1,N'山田');
```
通常のRDBMSでは`ID`列に主キーが作成されている場合、上記のSQLはID列の重複しているデータを入れようとしている為、制約違反となりインサート（厳密には２個目のインサート）ができませんが、Azure Synapse Analytics SQLプールでは制約としては機能しないので以下の通りインサートが行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697647/746c3117-b0d4-c0b8-8fac-9c682f526120.png)

またデータを確認しても問題なくインサートされている事が確認出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697647/4f5211cc-7de5-61d2-c583-e38905c45f4c.png)

この動作は一意キーでも同様の動作となります。
このようにAzure Synapse Analyticsでは一意キーや主キーは制約として動作することはありません。

##注意点②一意キー、主キーを作成した状態で重複データがテーブル内に入っていると結果不正が生じる
注意点の2つ目は、一意キーや主キーをテーブルに作成した状態で、重複データがテーブル内に入っていると結果不正となるケースが存在する点です。

例えば先ほどと同様の`TEST`テーブルを作成し、`ID`列に主キーを作成します。

```SQL
--TESTテーブルの作成
CREATE TABLE TEST(
	 ID		INT NOT NULL
	,NAME	NVARCHAR(200)
) WITH (
	DISTRIBUTION = ROUND_ROBIN,
	CLUSTERED COLUMNSTORE INDEX
);

--主キーの作成
ALTER TABLE TEST ADD CONSTRAINT TEST_ID_PK PRIMARY KEY NONCLUSTERED (ID) NOT ENFORCED;
```

データをインサートします。この時に、`ID`が1のデータは2件（重複状態）、`ID`が2~4のデータは各`ID`毎に１件ずつのデータとなるようにデータの挿入を行います。

```SQL
--重複データ
INSERT INTO TEST VALUES(1,N'田中');
INSERT INTO TEST VALUES(1,N'山田');

--各ID毎に1件ずつ
INSERT INTO TEST VALUES(2,N'鈴木');
INSERT INTO TEST VALUES(3,N'斎藤');
INSERT INTO TEST VALUES(4,N'松本');
```

ここで、ID毎の件数を確認するような以下のSQLを実行します。

```SQL
select ID,count(*) AS ID毎の件数 from TEST group by ID order by 1;
```
期待値としては以下のような結果になると思われます。

| ID | ID毎の件数 |
|:-:|:-:|
| 1 | 2  |
| 2 | 1  |
| 3 | 1  |
| 4 | 1  |

一方で実際の実行結果は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697647/fe3d1954-a930-5ccb-7e1a-260c29e1ca56.png)
`ID`列でGroup byを行っているにも関わらず、結果不正が発生し、ID=1の値が複数行出力されてしまっています。いわゆる結果不正が発生しているという状況になります。

一方で、これは主キーを削除することで意図した結果を得ることが可能です。

```SQL
--制約の削除
ALTER TABLE TEST DROP CONSTRAINT TEST_ID_PK;

--SQLにてID毎の件数を再確認
select ID,count(*) AS ID毎の件数 from TEST group by ID order by 1;
```
__結果__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697647/0318ba00-8047-6711-5eb7-a6aa554a2a76.png)

このように主キーや一意キーをテーブルに作成しているにも関わらず、そのテーブル内に重複データ存在していると意図しない結果不正が発生する可能性があるため十分に注意が必要です。

なので、__主キーや一意キーをテーブルに作成した場合には、作成したテーブル内のデータが必ず制約に則って一意となるように意識する必要があります。__

#一意キー、主キーの作成のメリット
一意キーや主キーについては__制約として機能せず、データによっては結果不正を招く可能性がある__と言う特徴を鑑みると、作成するメリットは何もないように思われます。では、一意キー、主キーを作成することでどのようなメリットがあるのかと言いますと、それはずばり性能の向上です。
Azure Synapse Analyticsではクエリを実行する際に、実行計画を生成しますが、主キーや一意キーを作成することに__より最適な実行計画を生成する事が出来る__ようにななります。最適な実行計画が生成できればそれだけ性能が向上するというわけです。これが、Azure Synapse Analytics SQLプールで一意キー、主キーを作成する最大のメリットです。