← Назад к вопросам

Как создать index?

2.0 Middle🔥 152 комментариев
#Базы данных и SQL

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Создание индексов в C# Backend (Entity Framework и SQL)

Создание индексов — важнейший аспект оптимизации производительности баз данных в backend-разработке на C#. Рассмотрим основные подходы.

1. Аннотации данных в Entity Framework Core

В EF Core 5+ индексы можно создавать с помощью атрибутов прямо в классах-сущностях:

using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

public class User
{
    public int Id { get; set; }
    
    [Index(nameof(Email), IsUnique = true)]
    public string Email { get; set; }
    
    [Index]
    public DateTime CreatedAt { get; set; }
    
    // Составной индекс
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

2. Fluent API в DbContext

Более гибкий способ — конфигурация через Fluent API в методе OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Простой индекс
    modelBuilder.Entity<User>()
        .HasIndex(u => u.Email)
        .IsUnique();
    
    // Составной индекс
    modelBuilder.Entity<User>()
        .HasIndex(u => new { u.LastName, u.FirstName })
        .HasDatabaseName("IX_Users_Name")
        .HasFilter(null);
    
    // Индекс с сортировкой
    modelBuilder.Entity<Order>()
        .HasIndex(o => o.CreatedAt)
        .IsDescending();
    
    // Частичный индекс (фильтрованный)
    modelBuilder.Entity<Product>()
        .HasIndex(p => p.CategoryId)
        .HasFilter("[IsActive] = 1");
}

3. Миграции и применение индексов

После определения индексов создаем и применяем миграцию:

# Создание миграции
dotnet ef migrations add AddIndexes

# Применение к БД
dotnet ef database update

4. Прямые SQL-запросы

Для сложных индексов или специфичных оптимизаций используем SQL:

public partial class AddCustomIndexes : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql(@"
            CREATE NONCLUSTERED INDEX IX_Orders_Status_Created
            ON Orders (Status, CreatedAt DESC)
            INCLUDE (TotalAmount, CustomerId)
            WHERE Status IN ('Pending', 'Processing')");
    }
    
    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex("IX_Orders_Status_Created");
    }
}

5. Рекомендации по созданию индексов

Ключевые принципы:

  • Индексируйте поля, используемые в WHERE, JOIN, ORDER BY
  • Составные индексы должны учитывать порядок полей (от наиболее селективного к наименее)
  • Избегайте избыточных индексов — каждый индекс замедляет INSERT/UPDATE/DELETE
  • Используйте INCLUDE для покрывающих индексов
  • Фильтрованные индексы эффективны для части данных

6. Пример оптимизированной конфигурации

// Конфигурация для типичной e-commerce системы
modelBuilder.Entity<Order>(entity =>
{
    // Основной кластерный индекс (обычно PK)
    entity.HasKey(e => e.Id);
    
    // Индекс для частых поисков по статусу
    entity.HasIndex(e => e.Status);
    
    // Составной индекс для отчетов
    entity.HasIndex(e => new { e.CustomerId, e.CreatedAt })
        .IncludeProperties(e => e.TotalAmount);
    
    // Уникальный индекс для номера заказа
    entity.HasIndex(e => e.OrderNumber)
        .IsUnique();
    
    // Фильтрованный индекс для активных записей
    entity.HasIndex(e => e.LastUpdated)
        .HasFilter("[IsDeleted] = 0");
});

7. Мониторинг и обслуживание

Важные аспекты:

// Проверка использования индексов через системные представления
var unusedIndexesQuery = @"
    SELECT 
        OBJECT_NAME(i.object_id) as TableName,
        i.name as IndexName
    FROM sys.indexes i
    WHERE i.object_id > 100 
        AND i.is_primary_key = 0 
        AND i.is_unique = 0
        AND i.is_disabled = 0
        AND NOT EXISTS (
            SELECT 1 FROM sys.dm_db_index_usage_stats s
            WHERE s.object_id = i.object_id 
                AND s.index_id = i.index_id
        )";

8. Производительность и компромиссы

  • Чтение vs Запись: Индексы ускоряют SELECT, но замедляют INSERT/UPDATE/DELETE
  • Фрагментация: Регулярно проводите реорганизацию или перестроение индексов
  • Покрывающие индексы: Используйте INCLUDE для исключения key lookups
  • Память: Индексы занимают место на диске и в оперативной памяти

Лучшие практики:

  1. Анализируйте планы выполнения запросов
  2. Используйте Database Tuning Advisor
  3. Тестируйте производительность под нагрузкой
  4. Регулярно пересматривайте стратегию индексирования

Правильное создание и управление индексами — критически важно для производительности приложений, работающих с большими объемами данных. Всегда балансируйте между скоростью чтения и скоростью модификации данных.