共用方式為


索引

索引是許多數據存放區中常見的概念。 雖然其在數據存放區中的實作可能會有所不同,但用來根據數據行(或數據行集)進行查閱會更有效率。 如需良好索引使用方式的詳細資訊,請參閱效能檔中的 索引一節

您可以對欄位指定索引,如下所示:

[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; }
}

嘗試插入多個在索引的列集中具有相同值的實體,將會引發例外狀況。

索引排序順序

在大部分的資料庫中,索引所涵蓋的每個數據行都可以是遞增或遞減。 若索引只涵蓋一個數據行,這通常並不重要:資料庫可以視需要以相反順序周遊索引。 不過,對於複合式索引來說,排序對於良好的效能至關重要,並且可能決定查詢是否會使用該索引。 一般而言,索引數據行的排序順序應該對應至查詢子 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 一次以上,該屬性會繼續設定單一索引,而不是建立新的索引:

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();

由於第二 HasIndex 個呼叫會覆寫第一個呼叫,因此只會建立單一遞減索引。 這對於進一步設定慣例所建立的索引很有用。

若要在同一組屬性上建立多個索引,請將名稱傳遞至 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 時,會針對屬於唯一 'IS NOT NULL' 索引的所有可為 Null 數據行新增篩選。 若要覆寫此慣例,您可以提供 null 值。

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

包含的欄位

某些關係資料庫可讓您設定一組包含在索引中的數據行,但不是其「索引鍵」的一部分。 當查詢中的所有數據行都包含在索引中做為索引鍵或非索引鍵數據行時,這可能會大幅改善查詢效能,因為不需要存取數據表本身。 如需 SQL Server 內含數據行的詳細資訊, 請參閱檔

在下列範例中,數據 Url 行是索引鍵的一部分,因此該數據行的任何查詢篩選都可以使用索引。 但此外,僅存取 TitlePublishedOn 欄的查詢不需要存取數據表,並且會更有效率地執行。

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

檢查約束條件

檢查條件約束是標準關係型功能,可讓您定義必須保存數據表中所有數據列的條件;任何嘗試插入或修改違反條件約束的數據都會失敗。 檢查條件約束類似於非 Null 條件約束(禁止數據行中的 Null)或唯一條件約束(禁止重複專案),但允許定義任意 SQL 運算式。

您可以使用 Fluent API 來指定資料表上的檢查條件約束,並提供為 SQL 運算式:

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

您可以在相同的數據表上定義多個檢查條件約束,每個數據表都有自己的名稱。

注意:您可以透過社群套件 EFCore.CheckConstraints 來設定一些常見的檢查條件約束。