Bagikan melalui


Indeks

Indeks adalah konsep umum di banyak penyimpanan data. Meskipun implementasinya di penyimpanan data dapat bervariasi, mereka digunakan untuk membuat pencarian berdasarkan kolom (atau kumpulan kolom) lebih efisien. Lihat bagian indeks dalam dokumentasi performa untuk informasi selengkapnya tentang penggunaan indeks yang baik.

Anda dapat menentukan indeks melalui kolom sebagai berikut:

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

Catatan

Menurut konvensi, indeks dibuat di setiap properti (atau sekumpulan properti) yang digunakan sebagai kunci asing.

Indeks komposit

Indeks juga dapat mencakup lebih dari satu kolom:

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

Indeks di beberapa kolom, juga dikenal sebagai indeks komposit, mempercepat kueri yang memfilter kolom indeks, tetapi juga kueri yang hanya memfilter pada kolom pertama yang dicakup oleh indeks. Lihat dokumen performa untuk informasi selengkapnya.

Keunikan indeks

Secara default, indeks tidak unik: beberapa baris diizinkan untuk memiliki nilai yang sama untuk kumpulan kolom indeks. Anda dapat membuat indeks unik sebagai berikut:

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

Mencoba menyisipkan lebih dari satu entitas dengan nilai yang sama untuk kumpulan kolom indeks akan menyebabkan pengecualian dilemparkan.

Urutan pengurutan indeks

Catatan

Fitur ini sedang diperkenalkan di EF Core 7.0.

Di sebagian besar database, setiap kolom yang dicakup oleh indeks bisa naik atau menurun. Untuk indeks yang hanya mencakup satu kolom, ini biasanya tidak masalah: database dapat melintasi indeks dalam urutan terbalik sesuai kebutuhan. Namun, untuk indeks komposit, pengurutan dapat sangat penting untuk performa yang baik, dan dapat berarti perbedaan antara indeks yang digunakan oleh kueri atau tidak. Secara umum, urutan pengurutan kolom indeks harus sesuai dengan yang ditentukan dalam ORDER BY klausa kueri Anda.

Urutan pengurutan indeks naik secara default. Anda dapat membuat semua kolom memiliki urutan turun sebagai berikut:

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

Anda juga dapat menentukan urutan pengurutan berdasarkan kolom demi kolom sebagai berikut:

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

Penamaan indeks dan beberapa indeks

Menurut konvensi, indeks yang dibuat dalam database relasional diberi nama IX_<type name>_<property name>. Untuk indeks komposit, <property name> menjadi daftar nama properti yang dipisahkan garis bawah.

Anda bisa mengatur nama indeks yang dibuat dalam database:

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

Perhatikan bahwa jika Anda memanggil HasIndex lebih dari sekali pada kumpulan properti yang sama, yang terus mengonfigurasi satu indeks daripada membuat yang baru:

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

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

Karena panggilan kedua HasIndex mengambil alih panggilan pertama, ini hanya membuat satu indeks menurun. Ini dapat berguna untuk mengonfigurasi lebih lanjut indeks yang dibuat oleh konvensi.

Untuk membuat beberapa indeks di atas sekumpulan properti yang sama, teruskan nama ke HasIndex, yang akan digunakan untuk mengidentifikasi indeks dalam model EF, dan untuk membedakannya dari indeks lain di atas properti yang sama:

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

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

Perhatikan bahwa nama ini juga digunakan sebagai default untuk nama database, jadi panggilan HasDatabaseName eksplisit tidak diperlukan.

Filter indeks

Beberapa database relasional memungkinkan Anda menentukan indeks yang difilter atau sebagian. Ini memungkinkan Anda untuk mengindeks hanya subset nilai kolom, mengurangi ukuran indeks dan meningkatkan performa dan penggunaan ruang disk. Untuk informasi selengkapnya tentang indeks yang difilter SQL Server, lihat dokumentasi.

Anda dapat menggunakan API Fasih untuk menentukan filter pada indeks, yang disediakan sebagai ekspresi SQL:

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

Saat menggunakan penyedia SQL Server EF menambahkan 'IS NOT NULL' filter untuk semua kolom nullable yang merupakan bagian dari indeks unik. Untuk mengambil alih konvensi ini, Anda dapat memberikan null nilai.

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

Kolom yang disertakan

Beberapa database relasional memungkinkan Anda mengonfigurasi sekumpulan kolom yang disertakan dalam indeks, tetapi bukan bagian dari "kunci"-nya. Ini dapat secara signifikan meningkatkan performa kueri ketika semua kolom dalam kueri disertakan dalam indeks baik sebagai kolom kunci atau tidak kunci, karena tabel itu sendiri tidak perlu diakses. Untuk informasi selengkapnya tentang kolom yang disertakan SQL Server, lihat dokumentasi.

Dalam contoh berikut, Url kolom adalah bagian dari kunci indeks, sehingga pemfilteran kueri apa pun pada kolom tersebut dapat menggunakan indeks. Tetapi selain itu, kueri yang hanya Title mengakses kolom dan PublishedOn tidak perlu mengakses tabel dan akan berjalan lebih efisien:

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

Periksa batasan

Batasan pemeriksaan adalah fitur relasional standar yang memungkinkan Anda menentukan kondisi yang harus ditangguhkan untuk semua baris dalam tabel; setiap upaya untuk menyisipkan atau mengubah data yang melanggar batasan akan gagal. Batasan pemeriksaan mirip dengan batasan non-null (yang melarang null dalam kolom) atau ke batasan unik (yang melarang duplikat), tetapi memungkinkan ekspresi SQL arbitrer ditentukan.

Anda dapat menggunakan API Fasih untuk menentukan batasan pemeriksaan pada tabel, yang disediakan sebagai ekspresi SQL:

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

Beberapa batasan pemeriksaan dapat ditentukan pada tabel yang sama, masing-masing dengan nama mereka sendiri.

Catatan: beberapa batasan pemeriksaan umum dapat dikonfigurasi melalui paket komunitas EFCore.CheckConstraints.