1. 序章

このチュートリアルでは、JPAの@Indexアノテーションを使用したインデックスの定義について説明します。 例を通して、JPAとHibernateを使用して最初のインデックスを定義する方法を学習します。 その後、インデックスをカスタマイズするための追加の方法を示す定義を変更します。

2. @Indexアノテーション

簡単に要約することから始めましょう。 データベースインデックスはデータ構造であり、追加の書き込みとストレージスペースを犠牲にして、テーブルでのデータ取得操作の速度を向上させます。 ほとんどの場合、これは単一のテーブルからのデータの選択された列のコピーです。 永続層のパフォーマンスを向上させるために、インデックスを作成する必要があります。

JPAでは、 @Index を使用してコードからインデックスを定義することにより、これを実現できます。 この注釈はスキーマ生成プロセスによって解釈され、アーティファクトが自動的に作成されます。 エンティティにインデックスを指定する必要はないことに注意してください。

それでは、定義を見てみましょう。

2.1. javax.persistence.Index

インデックスのサポートは、javax.persistence.IndexによってJPA2.1仕様に最終的に追加されました。 このアノテーションにより、テーブルのインデックスを定義し、それに応じてカスタマイズできます。

@Target({})
@Retention(RUNTIME)
public @interface Index {
    String name() default "";
    String columnList();
    boolean unique() default false;
}

ご覧のとおり、 columnList 属性のみが必須であり、これを定義する必要があります。 後で、例を見て、各パラメーターを詳しく見ていきます。

ここで注意すべき点の1つは、アノテーションがデフォルトのインデックス作成アルゴリズムであるbtreeの変更をサポートしていないことです。

2.2. JPAと Hibernate

JPAは単なる仕様であることを私たちは知っています。 正しく機能するには、永続性プロバイダーも指定する必要があります。 デフォルトでは、HibernateFrameworkはSpringによって提供されるJPAの実装です。 詳細については、こちらをご覧ください。

インデックスのサポートがJPAに追加されたのは非常に遅いことを覚えておく必要があります。 それ以前は、多くのORMフレームワークは、動作が異なる可能性のある独自のカスタム実装を導入することでインデックスをサポートしています。 Hibernate Frameworkもそれを行い、org.hibernate.annotations.Indexアノテーションを導入しました。 このフレームワークを使用する際は、JPA 2.1仕様のサポート以降、非推奨になっていることに注意する必要があります。また、JPAのフレームワークを使用する必要があります。

技術的なバックグラウンドがあれば、例を見て、JPAで最初のインデックスを定義できます。

3. @Indexの定義

このセクションでは、インデックスを実装しています。 後で、さまざまなカスタマイズの可能性を提示して、それを変更しようとします。

開始する前に、プロジェクトを適切に初期化し、モデルを定義する必要があります。

Studentエンティティを実装しましょう。

@Entity
@Table
public class Student implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;

    // getters, setters
}

モデルができたら、最初のインデックスを実装しましょう。 @Indexアノテーションを追加するだけです。 これは、indexes属性の下の@Tableアノテーションで行います。 列の名前を指定することを忘れないでください。

@Table(indexes = @Index(columnList = "firstName"))

firstName列を使用して最初のインデックスを宣言しました。 スキーマ作成プロセスを実行すると、次のことを検証できます。

[main] DEBUG org.hibernate.SQL -
  create index IDX2gdkcjo83j0c2svhvceabnnoh on Student (firstName)

次に、追加機能を示す宣言を変更します。

3.1. @Index名前

ご覧のとおり、インデックスには名前が必要です。 デフォルトでは、指定しない場合、プロバイダーによって生成された値になります。 カスタムラベルが必要な場合は、name属性を追加するだけです。

@Index(name = "fn_index", columnList = "firstName")

このバリアントは、ユーザー定義の名前でインデックスを作成します。

[main] DEBUG org.hibernate.SQL -
  create index fn_index on Student (firstName)

さらに、 name でスキーマの名前を指定することにより、別のスキーマでインデックスを作成できます。

@Index(name = "schema2.fn_index", columnList = "firstName")

3.2. マルチカラム@Index

それでは、columnList構文を詳しく見てみましょう。

column ::= index_column [,index_column]*
index_column ::= column_name [ASC | DESC]

すでに知っているように、インデックスに含める列名を指定できます。 もちろん、単一のインデックスに複数の列を指定することもできます。 これを行うには、名前をコンマで区切ります。

@Index(name = "mulitIndex1", columnList = "firstName, lastName")

@Index(name = "mulitIndex2", columnList = "lastName, firstName")
[main] DEBUG org.hibernate.SQL -
  create index mulitIndex1 on Student (firstName, lastName)
   
[main] DEBUG org.hibernate.SQL -
  create index mulitIndex2 on Student (lastName, firstName)

永続性プロバイダーは、指定された列の順序を順守する必要があることに注意してください。 この例では、同じ列のセットを指定している場合でも、インデックスはわずかに異なります。

3.3. @Index注文

前のセクションで構文を確認したので、column_nameの後にASC(昇順)および DESC (降順)の値を指定することもできます。 これを使用して、インデックス付き列の値の並べ替え順序を設定します。

@Index(name = "mulitSortIndex", columnList = "firstName, lastName DESC")
[main] DEBUG org.hibernate.SQL -
  create index mulitSortIndex on Student (firstName, lastName desc)

各列の順序を指定できます。 そうでない場合は、昇順が想定されます。

3.4. @Index独自性

最後のオプションのパラメーターはunique属性で、インデックスが一意であるかどうかを定義します。 一意のインデックスにより、インデックス付きフィールドに重複する値が格納されないようにします。 デフォルトでは、falseです。 変更したい場合は、次のように宣言できます。

@Index(name = "uniqueIndex", columnList = "firstName", unique = true)
[main] DEBUG org.hibernate.SQL -
  alter table Student add constraint uniqueIndex unique (firstName)

この方法でインデックスを作成するときは、@Columnアノテーションのunique属性と同様に、列に一意性制約を追加します。 @Index は、複数列の一意の制約を宣言できるため、@Columnよりも優れています。

@Index(name = "uniqueMulitIndex", columnList = "firstName, lastName", unique = true)

3.5. 単一のエンティティに複数の@Index

これまで、インデックスのさまざまなバリアントを実装してきました。 もちろん、エンティティに対して単一のインデックスを宣言することに限定されません。 宣言を収集して、すべてのインデックスを一度に指定しましょう。 これを行うには、 @Index アノテーションを中かっこで繰り返し、コンマで区切ります。

@Entity
@Table(indexes = {
  @Index(columnList = "firstName"),
  @Index(name = "fn_index", columnList = "firstName"),
  @Index(name = "mulitIndex1", columnList = "firstName, lastName"),
  @Index(name = "mulitIndex2", columnList = "lastName, firstName"),
  @Index(name = "mulitSortIndex", columnList = "firstName, lastName DESC"),
  @Index(name = "uniqueIndex", columnList = "firstName", unique = true),
  @Index(name = "uniqueMulitIndex", columnList = "firstName, lastName", unique = true)
})
public class Student implements Serializable

さらに、同じ列のセットに対して複数のインデックスを作成することもできます。

3.6. 主キー

インデックスについて話すとき、主キーでしばらく停止する必要があります。 ご存知のとおり、 EntityManager によって管理されるすべてのエンティティは、主キーにマップされる識別子を指定する必要があります。

一般に、主キーは特定のタイプの一意のインデックスです。 前に示した方法でこのキーの定義を宣言する必要がないことを付け加える価値があります。 すべては@Idアノテーションによって自動的に行われます。

3.7. 非エンティティ@Index

インデックスを実装するさまざまな方法を学んだ後、インデックスを指定する場所は@Tableだけではないことに注意してください。 同様に、 @SecondaryTable 、@ CollectionTable、 @JoinTable @TableGeneratorアノテーションでインデックスを宣言できます。 これらの例は、この記事では取り上げていません。 詳細については、 javax.persistenceJavaDocを確認してください。

4. 結論

この記事では、JPAを使用したインデックスの宣言について説明しました。 それらに関する一般的な知識を確認することから始めました。 その後、最初のインデックスを実装し、例を通じて、名前、含まれる列、順序、および一意性を変更してインデックスをカスタマイズする方法を学びました。 最後に、主キーと、それらを宣言できる追加の方法と場所について話しました。

いつものように、記事の例はGitHubから入手できます。