TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #3219 1.47K
День 2689. #ЗаметкиНаПолях
Темпоральные таблицы в EF Core. Часть 4

1. Что это?
2. Настройка
3. Запросы
 
Безопасная миграция в производственной среде
Изменение существующей таблицы на темпоральную — более деликатный процесс, чем создание её с нуля. Безопаснее всего создать ручную миграцию с чистым SQL:
public partial class TemporalOnOrders : Migration
{
  protected override void Up(MigrationBuilder mb)
  {
    // Добавляем столбцы периода
    mb.Sql(@"
  ALTER TABLE [Orders] ADD
  [ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN
    CONSTRAINT DF_Orders_ValidFrom DEFAULT '2000-01-01 00:00:00.0000000',
  [ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN
    CONSTRAINT DF_Orders_ValidTo DEFAULT '9999-12-31 23:59:59.9999999',
  PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo]);
    ");
 
     // Включаем версионирование
    mb.Sql(@"
  ALTER TABLE [Orders]
  SET (SYSTEM_VERSIONING = ON (
    HISTORY_TABLE = [audit].[OrdersHistory],
    DATA_CONSISTENCY_CHECK = ON));
    ");
  }
 
  protected override void Down(MigrationBuilder migrationBuilder)
  {
    mb.Sql(@"
  ALTER TABLE [Orders] SET (SYSTEM_VERSIONING = OFF);
  ALTER TABLE [Orders] DROP PERIOD FOR SYSTEM_TIME;
  ALTER TABLE [Orders] DROP COLUMN [ValidFrom];
  ALTER TABLE [Orders] DROP COLUMN [ValidTo];
  DROP TABLE IF EXISTS [audit].[OrdersHistory];
   ");
  }
}

Замечание: В производственной среде вы, наверное, не захотите удалять историю, а просто отключите версионирование.
 
Производительность записи
Темпоральные таблицы не бесплатны. Каждое обновление или удаление требует от SQL Server записи дополнительной строки в таблицу истории. Для таблиц с высокой нагрузкой на запись это может быть значительным. В типичных сценариях OLTP накладные расходы - 5–15%. Для сценариев с высокой нагрузкой следует оценить, оправдывает ли необходимая детализация истории эти затраты.
 
Рост таблиц истории
Таблицы истории со временем могут значительно увеличиваться в размерах. Можно архивировать старые данные:
public async Task ArchiveOldHistoryAsync()
{
  var cutoff = DateTime.UtcNow.AddYears(-2);
 
  await _db.Database.ExecuteSqlRawAsync(@"
  -- Перемещаем в архив
  INSERT INTO [audit].[OrdersHistoryArchive]
  SELECT * FROM [audit].[OrdersHistory]
   WHERE [ValidTo] < {0};
 
  -- Удаляем историю (надо отключить версионирование)
  ALTER TABLE [Orders] SET (SYSTEM_VERSIONING = OFF);
 
  DELETE FROM [audit].[OrdersHistory]
   WHERE [ValidTo] < {0};
 
  ALTER TABLE [Orders] SET (SYSTEM_VERSIONING = ON (
   HISTORY_TABLE = [audit].[OrdersHistory]));
  ", cutoff);
}

 
Производительность чтения
Функции TemporalAll() и TemporalBetween() сканируют таблицу истории. Для панелей аудита с большими таблицами истории всегда используйте агрессивную фильтрацию и правильные индексы.
 
EF Core создаёт кластерный индекс по столбцам периода в таблице истории. Для запросов к конкретным сущностям на определённый момент времени добавьте некластерный индекс:
CREATE NONCLUSTERED INDEX IX_OrdersHistory_IdValidFrom
ON [audit].[OrdersHistory] ([Id], [ValidFrom] DESC);

 
Окончание следует…
 
Источник:
https://thecodeman.net/posts/temporal-tables-efcore-auditing-history
  • 👍 3
  • 👎 1
More from @netdeveloperdiary
  1. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  2. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  3. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  4. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  5. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  6. Sep 22, 2026День 2792. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →