Indeksy
Indeksy są często spotykaną koncepcją w wielu magazynach danych. Chociaż ich implementacja w magazynie danych może się różnić, są one używane do bardziej wydajnego wyszukiwania na podstawie kolumny (lub zestawu kolumn). Aby uzyskać więcej informacji na temat dobrego użycia indeksów, zobacz sekcję indeksów w dokumentacji dotyczącej wydajności.
Indeks dla kolumny można określić w następujący sposób:
[Index(nameof(Url))]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Uwaga
Zgodnie z konwencją indeks jest tworzony w każdej właściwości (lub zestawie właściwości), które są używane jako klucz obcy.
Indeks złożony
Indeks może również obejmować więcej niż jedną kolumnę:
[Index(nameof(FirstName), nameof(LastName))]
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Indeksy w wielu kolumnach, znane również jako indeksy złożone, przyspieszają zapytania filtrowane według kolumn indeksu, ale także zapytania, które filtruje tylko w pierwszych kolumnach objętych indeksem. Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą wydajności.
Unikatowość indeksu
Domyślnie indeksy nie są unikatowe: wiele wierszy może mieć te same wartości dla zestawu kolumn indeksu. Indeks można ustawić jako unikatowy w następujący sposób:
[Index(nameof(Url), IsUnique = true)]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Próba wstawienia więcej niż jednej jednostki o tych samych wartościach dla zestawu kolumn indeksu spowoduje zgłoszenie wyjątku.
Kolejność sortowania indeksu
Uwaga
Ta funkcja jest wprowadzana w programie EF Core 7.0.
W większości baz danych każda kolumna objęta indeksem może być rosnąca lub malejąca. W przypadku indeksów obejmujących tylko jedną kolumnę zwykle nie ma znaczenia: baza danych może przechodzić przez indeks w odwrotnej kolejności zgodnie z potrzebami. Jednak w przypadku indeksów złożonych kolejność może mieć kluczowe znaczenie dla dobrej wydajności i może oznaczać różnicę między indeksem używanym przez zapytanie, czy też nie. Ogólnie rzecz biorąc, kolejność sortowania kolumn indeksu powinna odpowiadać tym określonym w ORDER BY
klauzuli zapytania.
Kolejność sortowania indeksu jest domyślnie rosnąca. Możesz ustawić, że wszystkie kolumny mają kolejność malejącą w następujący sposób:
[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; }
}
Kolejność sortowania można również określić na podstawie kolumny po kolumnie w następujący sposób:
[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; }
}
Nazewnictwo indeksów i wiele indeksów
Zgodnie z konwencją indeksy utworzone w relacyjnej bazie danych mają nazwę IX_<type name>_<property name>
. W przypadku indeksów złożonych <property name>
staje się podkreślenia oddzieloną listą nazw właściwości.
Nazwę indeksu utworzonego w bazie danych można ustawić:
[Index(nameof(Url), Name = "Index_Url")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Należy pamiętać, że jeśli wywołasz HasIndex
więcej niż raz w tym samym zestawie właściwości, to nadal konfiguruje pojedynczy indeks zamiast tworzyć nowy:
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();
Ponieważ drugie HasIndex
wywołanie zastępuje pierwszy, powoduje to utworzenie tylko jednego indeksu malejącego. Może to być przydatne do dalszego konfigurowania indeksu utworzonego zgodnie z konwencją.
Aby utworzyć wiele indeksów w tym samym zestawie właściwości, przekaż nazwę do HasIndex
, która będzie używana do identyfikowania indeksu w modelu EF i odróżnienia go od innych indeksów nad tymi samymi właściwościami:
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();
Należy pamiętać, że ta nazwa jest również używana jako domyślna nazwa bazy danych, więc jawne wywoływanie HasDatabaseName
nie jest wymagane.
Filtr indeksu
Niektóre relacyjne bazy danych umożliwiają określenie filtrowanego lub częściowego indeksu. Dzięki temu można indeksować tylko podzbiór wartości kolumny, zmniejszając rozmiar indeksu i poprawiając wydajność oraz użycie miejsca na dysku. Aby uzyskać więcej informacji na temat filtrowanych indeksów programu SQL Server, zobacz dokumentację.
Interfejs API Fluent umożliwia określenie filtru indeksu podanego jako wyrażenie SQL:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.HasFilter("[Url] IS NOT NULL");
}
W przypadku korzystania z dostawcy programu SQL Server ef dodaje 'IS NOT NULL'
filtr dla wszystkich kolumn dopuszczających wartość null, które są częścią unikatowego indeksu. Aby zastąpić tę konwencję null
, możesz podać wartość.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.IsUnique()
.HasFilter(null);
}
Uwzględnione kolumny
Niektóre relacyjne bazy danych umożliwiają skonfigurowanie zestawu kolumn, które zostaną uwzględnione w indeksie, ale nie są częścią "klucza". Może to znacznie poprawić wydajność zapytań, gdy wszystkie kolumny w zapytaniu są zawarte w indeksie jako kolumny klucza lub bez klucza, ponieważ sama tabela nie musi być dostępna. Aby uzyskać więcej informacji na temat kolumn dołączonych do programu SQL Server, zobacz dokumentację.
W poniższym przykładzie kolumna Url
jest częścią klucza indeksu, więc każde filtrowanie zapytań w tej kolumnie może używać indeksu. Ponadto zapytania, które uzyskują Title
dostęp tylko do kolumn i PublishedOn
, nie będą musiały uzyskiwać dostępu do tabeli i będą działać wydajniej:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasIndex(p => p.Url)
.IncludeProperties(
p => new { p.Title, p.PublishedOn });
}
Sprawdzanie ograniczeń
Ograniczenia sprawdzania to standardowa funkcja relacyjna, która umożliwia zdefiniowanie warunku, który musi być przechowywany dla wszystkich wierszy w tabeli; próba wstawienia lub zmodyfikowania danych naruszających ograniczenie zakończy się niepowodzeniem. Ograniczenia sprawdzania są podobne do ograniczeń innych niż null (które uniemożliwiają używanie wartości null w kolumnie) lub unikatowych ograniczeń (które uniemożliwiają duplikaty), ale zezwalają na definiowanie dowolnego wyrażenia SQL.
Możesz użyć interfejsu API Fluent, aby określić ograniczenie sprawdzania w tabeli podane jako wyrażenie SQL:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Product>()
.ToTable(b => b.HasCheckConstraint("CK_Prices", "[Price] > [DiscountedPrice]"));
}
W tej samej tabeli można zdefiniować wiele ograniczeń sprawdzania, z których każda ma własną nazwę.
Uwaga: niektóre typowe ograniczenia sprawdzania można skonfigurować za pośrednictwem pakietu społeczności EFCore.CheckConstraints.