다음을 통해 공유


인덱스

인덱스는 여러 데이터 저장소에서 일반적인 개념입니다. 데이터 저장소의 구현은 다를 수 있지만 열(또는 열 집합)을 기반으로 조회를 보다 효율적으로 만드는 데 사용됩니다. 좋은 인덱스 사용에 대한 자세한 내용은 성능 설명서의 인덱스 섹션을 참조하세요.

다음과 같이 열에 대해 인덱스를 지정할 수 있습니다.

[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 호출은 첫 번째 호출을 재정의하므로 단일 내림차순 인덱스만 만듭니다. 이 기능은 규칙에 의해 만들어진 인덱스 추가 구성에 유용할 수 있습니다.

동일한 속성 집합에 대해 여러 인덱스를 만들려면 EF 모델에서 인덱스를 식별하고 동일한 속성에 대한 다른 인덱스와 구분하는 데 사용할 이름을 HasIndex해당 인덱스에 전달합니다.

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는 고유 인덱스의 일부인 모든 nullable 열에 대해 '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를 통해 몇 가지 일반적인 CHECK 제약 조건을 구성할 수 있습니다.