次の方法で共有


索引

インデックスは、多くのデータ ストアで一般的な概念です。 データ ストアでの実装はさまざまですが、列 (または列のセット) に基づく参照をより効率的にするために使用されます。 適切なインデックスの使用方法の詳細については、パフォーマンス ドキュメントの インデックス」セクションを参照してください。

列のインデックスは次のように指定できます。

[Index(nameof(Url))]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

規則により、外部キーとして使用される各プロパティ (またはプロパティのセット) にインデックスが作成されます。

複合インデックス

インデックスは、複数の列にまたがることもできます。

[Index(nameof(FirstName), nameof(LastName))]
public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

複数の列に対するインデックス (複合インデックスとも呼ばれます) は、インデックスの列をフィルター処理するクエリを高速化するだけでなく、インデックスの対象となる最初の のみをフィルター処理するクエリも高速化します。 詳細については、パフォーマンス に関するドキュメント を参照してください。

インデックスの一意性

既定では、インデックスは一意ではありません。インデックスの列セットに対して複数の行が同じ値を持つことができます。 インデックスは次のように一意にすることができます。

[Index(nameof(Url), IsUnique = true)]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

インデックスの列セットに同じ値を持つエンティティを複数挿入しようとすると、例外が発生します。

インデックスの並べ替え順序

ほとんどのデータベースでは、インデックスの対象となる各列を昇順または降順にすることができます。 1 つの列のみを対象とするインデックスの場合、通常、これは重要ではありません。データベースは、必要に応じて逆の順序でインデックスを走査できます。 ただし、複合インデックスの場合、順序付けはパフォーマンスを向上させるために非常に重要であり、クエリで使用されるインデックスの違いを意味する可能性があります。 一般に、インデックス列の並べ替え順序は、クエリの ORDER BY 句で指定されているものに対応している必要があります。

インデックスの並べ替え順序は、既定では昇順です。 すべての列を次のように降順にすることができます。

[Index(nameof(Url), nameof(Rating), AllDescending = true)]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public int Rating { get; set; }
}

並べ替え順序は、次のように列単位で指定することもできます。

[Index(nameof(Url), nameof(Rating), IsDescending = new[] { false, true })]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public int Rating { get; set; }
}

インデックスの名前付けと複数のインデックス

慣例により、リレーショナル データベースで作成されたインデックスには IX_<type name>_<property name>という名前が付けられます。 複合インデックスの場合、<property name> はプロパティ名のアンダースコアで区切られたリストになります。

データベースに作成されたインデックスの名前を設定できます。

[Index(nameof(Url), Name = "Index_Url")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

同じプロパティ セットで HasIndex を複数回呼び出した場合、新しいインデックスを作成するのではなく、1 つのインデックスを構成し続けます。

modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.FirstName, p.LastName })
    .HasDatabaseName("IX_Names_Ascending");

modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.FirstName, p.LastName })
    .HasDatabaseName("IX_Names_Descending")
    .IsDescending();

2 番目の HasIndex 呼び出しは最初の呼び出しをオーバーライドするため、1 つの降順インデックスのみが作成されます。 これは、規則によって作成されたインデックスをさらに構成する場合に役立ちます。

同じプロパティ セットに対して複数のインデックスを作成するには、HasIndexに名前を渡します。この名前は、EF モデル内のインデックスを識別し、同じプロパティを介して他のインデックスと区別するために使用されます。

modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.FirstName, p.LastName }, "IX_Names_Ascending");

modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.FirstName, p.LastName }, "IX_Names_Descending")
    .IsDescending();

この名前はデータベース名の既定値としても使用されるため、明示的に HasDatabaseName を呼び出す必要はありません。

インデックス フィルター

一部のリレーショナル データベースでは、フィルター処理されたインデックスまたは部分的なインデックスを指定できます。 これにより、列の値のサブセットにのみインデックスを付け、インデックスのサイズを小さくし、パフォーマンスとディスク領域の両方の使用量を向上させることができます。 SQL Server でフィルター処理されたインデックスの詳細については、ドキュメントを参照してください。

Fluent API を使用して、SQL 式として提供されるインデックスのフィルターを指定できます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasIndex(b => b.Url)
        .HasFilter("[Url] IS NOT NULL");
}

SQL Server プロバイダー EF を使用すると、一意のインデックスの一部である null 許容列すべてに対して 'IS NOT NULL' フィルターが追加されます。 この規則をオーバーライドするには、null 値を指定します。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasIndex(b => b.Url)
        .IsUnique()
        .HasFilter(null);
}

インクルードされた列

一部のリレーショナル データベースでは、インデックスに含まれる列のセットを構成できますが、その "キー" の一部ではありません。 これにより、テーブル自体にアクセスする必要がないため、クエリ内のすべての列がキー列またはキー以外の列としてインデックスに含まれている場合、クエリのパフォーマンスが大幅に向上する可能性があります。 SQL Server に含まれる列の詳細については、ドキュメントを参照してください。

次の例では、Url 列がインデックス キーの一部であるため、その列のクエリ フィルター処理でインデックスを使用できます。 ただし、Title 列と PublishedOn 列にのみアクセスするクエリは、テーブルにアクセスする必要はなく、より効率的に実行されます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasIndex(p => p.Url)
        .IncludeProperties(
            p => new { p.Title, p.PublishedOn });
}

CHECK 制約

チェック制約は、テーブル内のすべての行に対して保持する必要がある条件を定義できる標準的なリレーショナル機能です。制約に違反するデータを挿入または変更しようとすると失敗します。 Check 制約は、null 以外の制約 (列内の null を禁止する制約) や一意の制約 (重複を禁止する制約) に似ていますが、任意の SQL 式を定義できます。

Fluent API を使用して、SQL 式として提供されるテーブルに check 制約を指定できます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Product>()
        .ToTable(b => b.HasCheckConstraint("CK_Prices", "[Price] > [DiscountedPrice]"));
}

同じテーブルに対して複数の check 制約を定義できます。それぞれに独自の名前を付けます。

注: 一般的なチェック制約の一部は、EFCore.CheckConstraints コミュニティ パッケージを使用して構成できます。