[SQL]主キーとインデックスって同じもの?

# はじめに

最近とある企業の技術面接でSQLの主キーはなぜ検索が速いのかという質問を受けたのですが、その際に全く答えられなかったので調べてみました。
SQLについてあまり詳しくないという方の助けになれば幸いです。

# 対象読者

- SQLについてあまり詳しくない方

私のSQLレベルとしては、DockerでPostgresサーバーを立てて、Nextjsで書かれたフロントからAPI経由でデータを取得する程度です。
`SELECT`や`WHERE`など基本的なクエリは書けますが、`EXISTS`や`HAVING`などは勉強中です。

# 主キーとインデックスって同じもの?

これについてMySQLとSQL Serverのドキュメントを見てみると、以下のように書かれています。(こちらに関して[主キー制約とインデックスの話 - Qiita](https://qiita.com/suzukito/items/ca6a19fc7c6dec35b302#%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E5%AE%9A%E7%BE%A9%E3%81%AB%E4%B8%BB%E3%82%AD%E3%83%BC%E3%82%92%E5%90%AB%E3%82%81%E3%82%8B)を非常に参考にさせていただきました)

## MySQL

> テーブル上で PRIMARY KEY を定義すると、InnoDB ではそれがクラスタ化されたインデックスとして使用されます。 作成するテーブルごとに主キーを定義します。 論理的に一意で、Null 以外のカラムまたはカラムのセットが存在しない場合は、自動的に値が入力される新しい自動インクリメントカラムを追加します。  
> [15.6.2.1 クラスタインデックスとセカンダリインデックス - MySQL 8.0 リファレンスマニュアル](https://dev.mysql.com/doc/refman/8.0/ja/innodb-index-types.html#:~:text=%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E4%B8%8A%E3%81%A7%20PRIMARY%20KEY%20%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B%E3%81%A8%E3%80%81InnoDB%20%E3%81%A7%E3%81%AF%E3%81%9D%E3%82%8C%E3%81%8C%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E5%8C%96%E3%81%95%E3%82%8C%E3%81%9F%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E7%94%A8%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82%20%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%94%E3%81%A8%E3%81%AB%E4%B8%BB%E3%82%AD%E3%83%BC%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%20%E8%AB%96%E7%90%86%E7%9A%84%E3%81%AB%E4%B8%80%E6%84%8F%E3%81%A7%E3%80%81Null%20%E4%BB%A5%E5%A4%96%E3%81%AE%E3%82%AB%E3%83%A9%E3%83%A0%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%AB%E3%83%A9%E3%83%A0%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%81%8C%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E5%80%A4%E3%81%8C%E5%85%A5%E5%8A%9B%E3%81%95%E3%82%8C%E3%82%8B%E6%96%B0%E3%81%97%E3%81%84%E8%87%AA%E5%8B%95%E3%82%A4%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88%E3%82%AB%E3%83%A9%E3%83%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)

## SQL Server
>テーブルにクラスター化インデックスがある場合、またはインデックスがインデックス付きビューにある場合は、行ロケーターが行のクラスター化インデックス キーになります。  
> [非クラスター化インデックスのアーキテクチャ - SQL Server 2022](https://learn.microsoft.com/ja-jp/sql/relational-databases/sql-server-index-design-guide?view=sql-server-ver16#nonclustered-index-architecture:~:text=%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AB%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E5%8C%96%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E4%BB%98%E3%81%8D%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AB%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%E8%A1%8C%E3%83%AD%E3%82%B1%E3%83%BC%E3%82%BF%E3%83%BC%E3%81%8C%E8%A1%8C%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC%E5%8C%96%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%E3%82%AD%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)

## 結論

1. MySQLのドキュメントからPRIMARY KEYから自動的にクラスタ化されたインデックスが作成されることがわかります。
2. そして、SQL Serverのドキュメントからクラスター化インデックスがある場合、行ロケーターが行のクラスター化インデックス キーになることがわかります。
3. 従って、主キーとインデックスは異なるものでありますが、主キーを定義するとインデックスが自動的に作成されるため、使用者はそれらの違いを意識する必要はないと考えられます。

# インデックスがあるとなぜ検索が速いのか

主キーとインデックスの違いを整理できたところで、インデックスがあるとなぜ検索が速いのかについて勉強したので解説します。

> 空間インデックスを除き、InnoDB インデックスは B-tree データ構造です。
> [15.6.2.2 InnoDB インデックスの物理構造 - MySQL 8.0 リファレンスマニュアル](https://dev.mysql.com/doc/refman/8.0/ja/innodb-physical-structure.html#:~:text=%E7%A9%BA%E9%96%93%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E9%99%A4%E3%81%8D%E3%80%81InnoDB%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20B%2Dtree%20%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0%E3%81%A7%E3%81%99%E3%80%82)

上にある引用文からわかるように、インデックスはB-treeデータ構造であるとのことです。
そして、B-treeは2分木のようなものですが、ノードが持つことのできる子ノードが2個以上でも良いため、2分木に比べて高さが低くなり、高速に検索することが可能となります。
具体的には、計算量がおよそO(logN)となるため、データ量が増えても計算速度を高速に保つことができます。

# おわりに

簡単にではありますが、主キーとインデックスの違いについて説明しました。
この話題について調べる中で自身のSQLに対する知識のなさを痛感したため、今後もコツコツ勉強していきたいと思います。

# 参考

- [主キーとIndexについて整理する - Qiita](https://qiita.com/pirorirori_n712/items/b47ade3fdaf8b4a109ba)
- [Create primary keys - Microsoft](https://learn.microsoft.com/en-us/sql/relational-databases/tables/create-primary-keys?view=sql-server-ver16)
- [主キー制約とインデックスの話 - Qiita](https://qiita.com/suzukito/items/ca6a19fc7c6dec35b302)
- [8.3.1 MySQL のインデックスの使用の仕組み - MySQL 8.0 リファレンスマニュアル](https://dev.mysql.com/doc/refman/8.0/ja/mysql-indexes.html)