引言#
データベースインデックスとは何ですか#
データベースインデックスは、データベースサーバーがテーブルデータのサブセットを格納するために使用する小さな補助データ構造です。インデックスは通常、特定のテーブルの読み取りパフォーマンスを向上させるために使用されます。
インデックスにはキーと値のペアが含まれます:
- key: インデックスを作成するための列
- value: 特定のテーブル内のレコードを指すポインタ
1 つのテーブルに複数の列にインデックスを作成することができます。たとえば、User という名前のテーブルがあり、id、firstName、lastName の 3 つの列がある場合、firstName と lastName の列にインデックスを作成することができます。
データベースインデックスの種類#
- Index (デフォルト): 通常の非一意のインデックスであり、データに制約を強制しません
- Primay Key: 行を一意に識別するために使用される主キー
- Unique indexes: 列の値の一意性を強制するための一意のインデックスで、重複値を防ぎます
- Full-text indexes: テキスト列に使用され、全文検索をサポートします
インデックスのみでレコードを直接検索する#
データベースは、クエリを元のテーブルを問い合わせることなく、インデックスから一致するレコードを返すことも選択できます。これはインデックススキャンと呼ばれます。
SELECT firstName from 'User' where firstName = 'Jimmy';
インデックスを使用した高速な読み取りのコスト#
インデックスは読み取りパフォーマンスの向上に非常に効果的であると一般的に考えられていますが、インデックスにはコストがかかります。
書き込み操作には追加のオーバーヘッドが発生します。これは、書き込み操作ごとにインデックスを更新する必要があるためです。
インデックスのもう 1 つのコストは、データベースサーバーから追加のリソースを取得してメンテナンスする必要があることです。インデックスには、データベースサーバーからの追加のストレージ、メモリ、および IO が必要です。
B-Tree インデックスによるクエリパフォーマンスの向上#
B ツリーの時間複雑度#
順次スキャンは線形時間複雑度(O(n))を持ちます。これは、レコードを取得するためにかかる時間が所有しているレコードの数に比例することを意味します。
一方、B ツリーは対数時間複雑度(O log(n))を持ちます。これは、データの規模が増えるにつれて、レコードの取得コストが明らかに遅くなることを意味します。
インデックスの追加とフルスキャン#
最初のクエリ インデックスなし(216ms)
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
}
2 番目のクエリ firstName を追加(59ms)
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
@@index(fields: [firstName])
}
3 番目のクエリ 複合インデックスを追加(17ms)
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
@@index(fields: [firstName, lastName])
}
4 番目のクエリ インデックスとソートを追加 (11ms)
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
@@index(fields: [firstName("desc"), lastName])
}
ハッシュインデックスによるクエリパフォーマンスの向上(postgreSQL)#
ハッシュインデックスの使用#
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
@@index(fields: [firstName], type: Hash)
}
npx prisma migrate dev --name add-firstName-index