インデックス
Prisma ORMは、データベースのインデックス、ユニーク制約、主キー制約の設定を可能にします。これはバージョン4.0.0以降で一般提供されています。バージョン3.5.0以降では、extendedIndexesプレビュー機能で有効にできます。
バージョン3.6.0では、新しい@@fulltext属性を介して、MySQLおよびMongoDBにおける全文インデックスのイントロスペクションとマイグレーションのサポートも導入されています。これはfullTextIndexプレビュー機能を通じて利用できます。
バージョン4.0.0より前のバージョンからアップグレードする場合、これらのインデックス設定および全文インデックスへの変更は、これらの機能を使用している既存のデータベースにとっては**破壊的な変更**となる可能性があります。以前のバージョンからのアップグレードで、アップグレード方法の詳細を確認してください。
インデックス設定
以下の属性引数で、インデックス、ユニーク制約、主キー制約を設定できます。
-
length引数を使用すると、String型およびBytes型の値のインデックス化されるサブパートの最大長を指定できます@id、@@id、@unique、@@unique、および@@index属性で利用可能です- MySQLのみ
-
sort引数を使用すると、データベースに制約またはインデックスのエントリが格納される順序を指定できます- すべてのデータベースの
@unique、@@unique、@@index属性で、またSQL Serverの@idおよび@@id属性で利用可能です
- すべてのデータベースの
-
type引数を使用すると、PostgreSQLのデフォルトのBTreeアクセスメソッド以外のインデックスアクセスメソッドをサポートできます@@index属性で利用可能です- PostgreSQLのみ
- サポートされているインデックスアクセスメソッド:
Hash、Gist、Gin、SpGist、Brin
-
clustered引数を使用すると、制約またはインデックスがクラスター化されているか非クラスター化されているかを設定できます@id、@@id、@unique、@@unique、および@@index属性で利用可能です- SQL Serverのみ
各機能が最初に導入されたバージョンについては、リンク先のセクションを参照してください。
lengthによるインデックス長の構成 (MySQL)
length引数はMySQLに特有のもので、String型とByte型の列にインデックスと制約を定義できます。これらの型では、値全体がMySQLのインデックスサイズの制限を超える場合に、インデックス化される値のサブパートの最大長を指定する必要があります。詳細については、MySQLドキュメントを参照してください。
length引数は、@id、@@id、@unique、@@unique、および@@index属性で利用可能です。バージョン4.0.0以降で一般提供されており、バージョン3.5.0以降ではextendedIndexesプレビュー機能の一部として利用できます。
例として、以下のデータモデルは、最大長3000文字のidフィールドを宣言しています。
model Id {
id String @id @db.VarChar(3000)
}
これはMySQLのインデックスストレージ制限を超えるため、MySQLでは有効ではなく、Prisma ORMはこのデータモデルを拒否します。生成されたSQLはデータベースによって拒否されます。
CREATE TABLE `Id` (
`id` VARCHAR(3000) PRIMARY KEY
)
length引数を使用すると、id値のサブパートのみが主キーを表すことを指定できます。以下の例では、最初の100文字が使用されます。
model Id {
id String @id(length: 100) @db.VarChar(3000)
}
Prisma Migrateは、データモデルで指定されていれば、length引数を使用して制約とインデックスを作成できます。これにより、PrismaスキーマのByte型とString型の値にインデックスと制約を作成できます。引数を指定しない場合、インデックスは以前と同様に値全体をカバーするものとして扱われます。
イントロスペクションは、既存のデータベースにこれらの制限が存在する場合、それらを取得します。これにより、Prisma ORMは以前抑制されていたインデックスと制約をサポートできるようになり、この機能を利用するMySQLデータベースのサポートが向上します。
length引数は、以下の例のように、@@id属性を使用して複合主キーにも使用できます。
model CompoundId {
id_1 String @db.VarChar(3000)
id_2 String @db.VarChar(3000)
@@id([id_1(length: 100), id_2(length: 10)])
}
同様の構文は、@@uniqueおよび@@index属性にも使用できます。
sortによるインデックスソート順序の構成
sort引数は、Prisma ORMがサポートするすべてのデータベースで利用可能です。これにより、インデックスまたは制約のエントリがデータベースに格納される順序を指定できます。これは、データベースが特定のクエリにインデックスを使用できるかどうかに影響を与える可能性があります。
sort引数は、すべてのデータベースで@unique、@@unique、および@@indexで利用可能です。さらに、SQL Serverでは@idおよび@@idでも使用できます。バージョン4.0.0以降で一般提供されており、バージョン3.5.0以降ではextendedIndexesプレビュー機能の一部として利用できます。
例として、以下のテーブルは
CREATE TABLE `Unique` (
`unique` INT,
CONSTRAINT `Unique_unique_key` UNIQUE (`unique` DESC)
)
としてイントロスペクトされます
model Unique {
unique Int @unique(sort: Desc)
}
sort引数は、複合インデックスにも使用できます
model CompoundUnique {
unique_1 Int
unique_2 Int
@@unique([unique_1(sort: Desc), unique_2])
}
例: sortとlengthを一緒に使用する
以下の例は、Postモデルのインデックスと制約を設定するために、sortとlength引数を使用する方法を示しています。
model Post {
title String @db.VarChar(300)
abstract String @db.VarChar(3000)
slug String @unique(sort: Desc, length: 42) @db.VarChar(3000)
author String
created_at DateTime
@@id([title(length: 100, sort: Desc), abstract(length: 10)])
@@index([author, created_at(sort: Desc)])
}
typeによるインデックスアクセスタイプの構成 (PostgreSQL)
type引数は、@@index属性を使用してPostgreSQLでインデックスタイプを設定するために利用できます。利用可能なインデックスアクセスメソッドは、デフォルトのBTreeインデックスアクセスメソッドの他に、Hash、Gist、Gin、SpGist、Brinです。type引数はバージョン4.0.0以降で一般提供されています。Hashインデックスアクセスメソッドはバージョン3.6.0以降でextendedIndexesプレビュー機能の一部として利用可能であり、Gist、Gin、SpGist、Brinインデックスアクセスメソッドはバージョン3.14.0以降でプレビュー版として利用可能です。
Hash
Hashタイプは、インデックスデータを検索および挿入がはるかに高速で、ディスクスペースを少なく使用する形式で保存します。ただし、=および<>の比較のみがインデックスを使用できるため、<や>のような他の比較演算子は、デフォルトのBTreeタイプを使用する場合よりもHashを使用した場合の方がはるかに遅くなります。
例として、以下のモデルはvalueフィールドにHash型のインデックスを追加します。
model Example {
id Int @id
value Int
@@index([value], type: Hash)
}
これは以下のSQLコマンドに変換されます
CREATE TABLE "Example" (
id INT PRIMARY KEY,
value INT NOT NULL
);
CREATE INDEX "Example_value_idx" ON "Example" USING HASH (value);
汎用転置インデックス (GIN)
GINインデックスは、配列やJsonBデータなどの複合値を格納します。これは、あるオブジェクトが別のオブジェクトの一部であるかどうかをクエリする速度を向上させるのに役立ちます。全文検索によく使用されます。
インデックス付きフィールドは、インデックスによって処理される演算子を定義する演算子クラスを定義できます。
to_tsvectorなどの関数を使用してインデックス化された値を決定するインデックスは、Prisma ORMではまだサポートされていません。この方法で定義されたインデックスは、prisma db pullでは表示されません。
例として、以下のモデルはvalueフィールドにGinインデックスを追加し、インデックスの使用を許可する演算子のクラスとしてJsonbPathOpsを指定します。
model Example {
id Int @id
value Json
// ^ field type matching the operator class
// ^ operator class ^ index type
@@index([value(ops: JsonbPathOps)], type: Gin)
}
これは以下のSQLコマンドに変換されます
CREATE TABLE "Example" (
id INT PRIMARY KEY,
value JSONB NOT NULL
);
CREATE INDEX "Example_value_idx" ON "Example" USING GIN (value jsonb_path_ops);
JsonbPathOpsの一部として、@>演算子がインデックスによって処理され、value @> '{"foo": 2}'のようなクエリを高速化します。
GINのサポートされている演算子クラス
Prisma ORMは通常、PostgreSQLバージョン10以降で提供される演算子クラスをサポートしています。演算子クラスがPrisma ORMがまだサポートしていないフィールドタイプを要求する場合、文字列入力を伴うraw関数を使用すると、検証なしでこれらの演算子クラスを使用できます。
デフォルトの演算子クラス (✅でマークされているもの) は、インデックス定義から省略できます。
| 演算子クラス | 許可されるフィールド型 (ネイティブ型) | デフォルト | その他 |
|---|---|---|---|
ArrayOps | 任意の配列 | ✅ | CockroachDBでも利用可能 |
JsonbOps | Json (@db.JsonB) | ✅ | CockroachDBでも利用可能 |
JsonbPathOps | Json (@db.JsonB) | ||
raw("other") |
公式PostgreSQLドキュメントで組み込み演算子クラスについて詳しく読む。
CockroachDB
GINとBTreeは、CockroachDBでサポートされている唯一のインデックスタイプです。CockroachDBで動作するとマークされている演算子クラスのみが、そのデータベースで許可され、Prisma ORMでサポートされています。演算子クラスはPrisma Schema Languageで定義できません。ops引数はCockroachDBでは不要または許可されていません。
汎用検索ツリー (GiST)
GiSTインデックスタイプは、ユーザー定義型のインデックス付けスキームを実装するために使用されます。デフォルトでは、GiSTインデックスの直接的な用途は多くありませんが、例えばB-TreeインデックスタイプはGiSTインデックスを使用して構築されています。
例として、以下のモデルはvalueフィールドにGistインデックスを追加し、インデックスを使用する演算子としてInetOpsを指定します。
model Example {
id Int @id
value String @db.Inet
// ^ native type matching the operator class
// ^ index type
// ^ operator class
@@index([value(ops: InetOps)], type: Gist)
}
これは以下のSQLコマンドに変換されます
CREATE TABLE "Example" (
id INT PRIMARY KEY,
value INET NOT NULL
);
CREATE INDEX "Example_value_idx" ON "Example" USING GIST (value inet_ops);
value > '10.0.0.2'のようなIPアドレスを比較するクエリは、このインデックスを使用します。
GiSTのサポートされている演算子クラス
Prisma ORMは通常、PostgreSQLバージョン10以降で提供される演算子クラスをサポートしています。演算子クラスがPrisma ORMがまだサポートしていないフィールドタイプを要求する場合、文字列入力を伴うraw関数を使用すると、検証なしでこれらの演算子クラスを使用できます。
| 演算子クラス | 許可されるフィールド型 (許可されるネイティブ型) |
|---|---|
InetOps | String (@db.Inet) |
raw("other") |
公式PostgreSQLドキュメントで組み込み演算子クラスについて詳しく読む。
空間分割GiST (SP-GiST)
SP-GiSTインデックスは、さまざまな非バランスデータ構造に適しています。クエリがパーティショニングルールに一致する場合、非常に高速になります。
GiSTと同様に、SP-GiSTはユーザー定義型の構成要素として重要であり、カスタム検索演算子をデータベースと直接実装することを可能にします。
例として、以下のモデルはvalueフィールドにSpGistインデックスを追加し、インデックスを使用する演算子としてTextOpsを指定します。
model Example {
id Int @id
value String
// ^ field type matching the operator class
@@index([value], type: SpGist)
// ^ index type
// ^ using the default ops: TextOps
}
これは以下のSQLコマンドに変換されます
CREATE TABLE "Example" (
id INT PRIMARY KEY,
value TEXT NOT NULL
);
CREATE INDEX "Example_value_idx" ON "Example" USING SPGIST (value);
value LIKE 'something%'のようなクエリは、このインデックスによって高速化されます。
SP-GiSTのサポートされている演算子クラス
Prisma ORMは通常、PostgreSQLバージョン10以降で提供される演算子クラスをサポートしています。演算子クラスがPrisma ORMがまだサポートしていないフィールドタイプを要求する場合、文字列入力を伴うraw関数を使用すると、検証なしでこれらの演算子クラスを使用できます。
デフォルトの演算子クラス (✅でマークされているもの) は、インデックス定義から省略できます。
| 演算子クラス | 許可されるフィールド型 (ネイティブ型) | デフォルト | サポートされているPostgreSQLバージョン |
|---|---|---|---|
InetOps | String (@db.Inet) | ✅ | 10+ |
TextOps | String (@db.Text, @db.VarChar) | ✅ | |
raw("other") |
公式PostgreSQLドキュメントで組み込み演算子クラスについて詳しく読む。
ブロック範囲インデックス (BRIN)
BRINインデックスタイプは、日付や時刻の値のように、挿入後に変更されない大量のデータがある場合に役立ちます。データがインデックスに適している場合、最小限のスペースで大きなデータセットを格納できます。
例として、以下のモデルはvalueフィールドにBrinインデックスを追加し、インデックスを使用する演算子としてInt4BloomOpsを指定します。
model Example {
id Int @id
value Int
// ^ field type matching the operator class
// ^ operator class ^ index type
@@index([value(ops: Int4BloomOps)], type: Brin)
}
これは以下のSQLコマンドに変換されます
CREATE TABLE "Example" (
id INT PRIMARY KEY,
value INT4 NOT NULL
);
CREATE INDEX "Example_value_idx" ON "Example" USING BRIN (value int4_bloom_ops);
value = 2のようなクエリは、BTreeまたはHashインデックスが使用するスペースのごく一部しか使用しないインデックスを使用するようになります。
BRINのサポートされている演算子クラス
Prisma ORMは通常、PostgreSQLバージョン10以降で提供される演算子クラスをサポートしており、一部のサポートされている演算子はPostgreSQLバージョン14以降でのみ利用可能です。演算子クラスがPrisma ORMがまだサポートしていないフィールドタイプを要求する場合、文字列入力を伴うraw関数を使用すると、検証なしでこれらの演算子クラスを使用できます。
デフォルトの演算子クラス (✅でマークされているもの) は、インデックス定義から省略できます。
| 演算子クラス | 許可されるフィールド型 (ネイティブ型) | デフォルト | サポートされているPostgreSQLバージョン |
|---|---|---|---|
BitMinMaxOps | String (@db.Bit) | ✅ | |
VarBitMinMaxOps | String (@db.VarBit) | ✅ | |
BpcharBloomOps | String (@db.Char) | 14+ | |
BpcharMinMaxOps | String (@db.Char) | ✅ | |
ByteaBloomOps | Bytes (@db.Bytea) | 14+ | |
ByteaMinMaxOps | Bytes (@db.Bytea) | ✅ | |
DateBloomOps | DateTime (@db.Date) | 14+ | |
DateMinMaxOps | DateTime (@db.Date) | ✅ | |
DateMinMaxMultiOps | DateTime (@db.Date) | 14+ | |
Float4BloomOps | Float (@db.Real) | 14+ | |
Float4MinMaxOps | Float (@db.Real) | ✅ | |
Float4MinMaxMultiOps | Float (@db.Real) | 14+ | |
Float8BloomOps | Float (@db.DoublePrecision) | 14+ | |
Float8MinMaxOps | Float (@db.DoublePrecision) | ✅ | |
Float8MinMaxMultiOps | Float (@db.DoublePrecision) | 14+ | |
InetInclusionOps | String (@db.Inet) | ✅ | 14+ |
InetBloomOps | String (@db.Inet) | 14+ | |
InetMinMaxOps | String (@db.Inet) | ||
InetMinMaxMultiOps | String (@db.Inet) | 14+ | |
Int2BloomOps | Int (@db.SmallInt) | 14+ | |
Int2MinMaxOps | Int (@db.SmallInt) | ✅ | |
Int2MinMaxMultiOps | Int (@db.SmallInt) | 14+ | |
Int4BloomOps | Int (@db.Integer) | 14+ | |
Int4MinMaxOps | Int (@db.Integer) | ✅ | |
Int4MinMaxMultiOps | Int (@db.Integer) | 14+ | |
Int8BloomOps | BigInt (@db.BigInt) | 14+ | |
Int8MinMaxOps | BigInt (@db.BigInt) | ✅ | |
Int8MinMaxMultiOps | BigInt (@db.BigInt) | 14+ | |
NumericBloomOps | Decimal (@db.Decimal) | 14+ | |
NumericMinMaxOps | Decimal (@db.Decimal) | ✅ | |
NumericMinMaxMultiOps | Decimal (@db.Decimal) | 14+ | |
OidBloomOps | Int (@db.Oid) | 14+ | |
OidMinMaxOps | Int (@db.Oid) | ✅ | |
OidMinMaxMultiOps | Int (@db.Oid) | 14+ | |
TextBloomOps | String (@db.Text, @db.VarChar) | 14+ | |
TextMinMaxOps | String (@db.Text, @db.VarChar) | ✅ | |
TextMinMaxMultiOps | String (@db.Text, @db.VarChar) | 14+ | |
TimestampBloomOps | DateTime (@db.Timestamp) | 14+ | |
TimestampMinMaxOps | DateTime (@db.Timestamp) | ✅ | |
TimestampMinMaxMultiOps | DateTime (@db.Timestamp) | 14+ | |
TimestampTzBloomOps | DateTime (@db.Timestamptz) | 14+ | |
TimestampTzMinMaxOps | DateTime (@db.Timestamptz) | ✅ | |
TimestampTzMinMaxMultiOps | DateTime (@db.Timestamptz) | 14+ | |
TimeBloomOps | DateTime (@db.Time) | 14+ | |
TimeMinMaxOps | DateTime (@db.Time) | ✅ | |
TimeMinMaxMultiOps | DateTime (@db.Time) | 14+ | |
TimeTzBloomOps | DateTime (@db.Timetz) | 14+ | |
TimeTzMinMaxOps | DateTime (@db.Timetz) | ✅ | |
TimeTzMinMaxMultiOps | DateTime (@db.Timetz) | 14+ | |
UuidBloomOps | String (@db.Uuid) | 14+ | |
UuidMinMaxOps | String (@db.Uuid) | ✅ | |
UuidMinMaxMultiOps | String (@db.Uuid) | 14+ | |
raw("other") |
公式PostgreSQLドキュメントで組み込み演算子クラスについて詳しく読む。
clusteredによるインデックスのクラスター化/非クラスター化の構成 (SQL Server)
clustered引数は、SQL Serverでクラスター化/非クラスター化インデックスを設定するために利用できます。@id、@@id、@unique、@@unique、および@@index属性で使用できます。バージョン4.0.0以降で一般提供されており、バージョン3.13.0以降ではextendedIndexesプレビュー機能の一部として利用できます。
例として、以下のモデルは@idを非クラスター化 (クラスター化されたデフォルトではなく) に設定します。
model Example {
id Int @id(clustered: false)
value Int
}
これは以下のSQLコマンドに変換されます
CREATE TABLE [Example] (
id INT NOT NULL,
value INT,
CONSTRAINT [Example_pkey] PRIMARY KEY NONCLUSTERED (id)
)
各属性のclusteredのデフォルト値は以下の通りです。
| 属性 | 値 |
|---|---|
@id | true |
@@id | true |
@unique | false |
@@unique | false |
@@index | false |
テーブルは、最大1つのクラスター化インデックスを持つことができます。
以前のバージョンからのアップグレード
これらのインデックス設定の変更は、特定の既存のデータベースの既存のPrismaスキーマの機能を有効にする際に、**破壊的な変更**となる可能性があります。必要なプレビュー機能を有効にした後、prisma db pullを実行して既存のデータベースをイントロスペクトし、Prisma Migrateを再度使用する前にPrismaスキーマを更新してください。
以下の状況で破壊的な変更が発生する可能性があります
- 既存のソート制約とインデックス: 以前のバージョンのPrisma ORMは、順序が明示的に指定されていない場合、目的のソート順序が昇順であると想定します。これは、降順ソート順序を使用している既存の制約またはインデックスがあり、データモデルでこれを最初に指定せずにデータベースをマイグレーションする場合、破壊的な変更になることを意味します。
- 既存の長さ制約とインデックス: 以前のバージョンのPrisma ORMでは、MySQLで長さ制約のあるインデックスと制約はPrismaスキーマで表現できませんでした。そのため、
prisma db pullはこれらを取得せず、手動で指定することもできませんでした。prisma db pushまたはprisma migrate devを実行しても、データベースにすでに存在する場合は無視されていました。現在これらを指定できるようになったため、データモデルには存在しないがデータベースには存在するインデックスと制約は、マイグレーションコマンドによって削除されます。 BTree以外の既存のインデックス (PostgreSQL): 以前のバージョンのPrisma ORMは、デフォルトのBTreeインデックスタイプのみをサポートしていました。その他のサポートされているインデックス (Hash、Gist、Gin、SpGist、Brin) は、データベースをマイグレーションする前に追加する必要があります。- 既存のクラスター化/非クラスター化インデックス (SQL Server): 以前のバージョンのPrisma ORMは、インデックスをクラスター化または非クラスター化として設定することをサポートしていませんでした。デフォルトを使用しないインデックスの場合、これらはデータベースをマイグレーションする前に追加する必要があります。
上記各ケースにおいて、不要なデータベースの変更は、必要に応じてデータモデルでこれらのプロパティを適切に指定することで防止できます。最も簡単な方法は、prisma db pullを使用して既存の制約や設定を取得することです。 あるいは、これらの引数を手動で追加することもできます。これは、アップグレード後にprisma db pushまたはprisma migrate devを初めて使用する前に行う必要があります。
全文インデックス (MySQLおよびMongoDB)
fullTextIndexプレビュー機能は、バージョン3.6.0以降のMySQLおよびMongoDBにおける全文インデックスのイントロスペクションとマイグレーションをサポートします。これは@@fulltext属性を使用して設定できます。データベース内の既存の全文インデックスは、db pullでイントロスペクト後にPrismaスキーマに追加され、Prismaスキーマに追加された新しい全文インデックスは、Prisma Migrateを使用する際にデータベースに作成されます。これにより、以前機能しなかった一部のデータベーススキーマでの検証エラーも防止されます。
現在、MongoDB用Prisma Clientでは全文検索コマンドは有効にしていません。進捗状況はMongoDBのissueで追跡できます。
fullTextIndexプレビュー機能の有効化
fullTextIndexプレビュー機能を有効にするには、schema.prismaファイルのgeneratorブロックにfullTextIndex機能フラグを追加します
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextIndex"]
}
例
以下の例は、Postモデルのtitleおよびcontentフィールドに@@fulltextインデックスを追加する方法を示しています。
model Post {
id Int @id
title String @db.VarChar(255)
content String @db.Text
@@fulltext([title, content])
}
MongoDBでは、@@fulltextインデックス属性 (fullTextIndexプレビュー機能経由) をsort引数とともに使用して、全文インデックスにフィールドを昇順または降順で追加できます。以下の例は、Postモデルのtitleおよびcontentフィールドに@@fulltextインデックスを追加し、titleフィールドを降順にソートします。
generator js {
provider = "prisma-client-js"
previewFeatures = ["fullTextIndex"]
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
model Post {
id String @id @map("_id") @db.ObjectId
title String
content String
@@fulltext([title(sort: Desc), content])
}
以前のバージョンからのアップグレード
これは、特定の既存のデータベースの既存のPrismaスキーマの機能を有効にする際に、**破壊的な変更**となる可能性があります。必要なプレビュー機能を有効にした後、prisma db pullを実行して既存のデータベースをイントロスペクトし、Prisma Migrateを再度使用する前にPrismaスキーマを更新してください。
以前のバージョンのPrisma ORMは、全文インデックスを@@fulltext属性ではなく@@index属性を使用して変換していました。fullTextIndexプレビュー機能を有効にした後、prisma db pullを実行してこれらのインデックスを@@fulltextに変換してから、Prisma Migrateで再度マイグレーションしてください。これを行わないと、既存のインデックスは削除され、その代わりに通常のインデックスが作成されます。