Основные источники событий в SQL Server с использованием индексированных представлений

Я пытаюсь реализовать очень простой источник событий с помощью SQL Server. Никаких библиотек, никаких других серверов, ничего особенного, только основы с использованием SQL Server.

Предположим, у меня есть эта таблица:

Id | Name      | Data   | CreatedOn
1  | Fruit     | Apple  | <DATE_TIME> Apr 1, 2015
2  | Fruit     | Peach  | <DATE_TIME> Apr 5, 2015 
3  | Fruit     | Mango  | <DATE_TIME> Apr 10, 2015
4  | Vegetable | Potato | <DATE_TIME> May 20, 2015
5  | Vegetable | Tomato | <DATE_TIME> May 30, 2015

Теперь я хочу создать представление, которое показывает мне последние данные, сгруппированные по имени, чтобы результат был следующим:

Id | Name      | Data   | CreatedOn
3  | Fruit     | Mango  | <DATE_TIME> Apr 10, 2015
4  | Vegetable | Tomato | <DATE_TIME> May 30, 2015

Достаточно просто, CREATE VIEW Latest AS SELECT t1.* FROM table t1 JOIN (SELECT TOP 1 Id FROM table ORDER BY CreatedOn DESC, Id DESC) t2 ON t2.Id = t1.Id;

Теперь у меня будет много миллионов строк в таблице и много-много одновременных операций чтения в представлении. Поэтому я хотел бы проиндексировать его (индексированные представления SQL Server). Кажется, мне здесь не повезло, поскольку индексированные представления не могут содержать производные таблицы ИЛИ TOP ИЛИ MAX ИЛИ самообъединения.

Любые мысли о том, как я могу создать индексированное представление?

Если это невозможно, я мог бы использовать триггер INSTEAD OF, который обновляет столбец IsLatest BIT в таблице и создает индексированное представление на основе этого фильтра.

Любые другие предложения?


person tejas    schedule 24.10.2015    source источник


Ответы (1)


Существующее определение представления не сработало бы, поскольку SELECT TOP 1 Id FROM table ORDER BY CreatedOn DESC, Id DESC возвращает только одну строку, а вам потребовалось бы по одной на внешнюю строку.

Этот запрос не может быть реализован с индексированным представлением. Даже если вы переформулируете запрос следующим образом:

select *
from T t1
join (
 select Name, MAX(ID) as MaxID
 from T
 group by Name
) t2 on t1.name = t2.Name and t1.ID = t2.MaxID

Вы не можете материализовать какую-либо значимую часть этого. Обычно этот шаблон можно использовать для материализации хотя бы части group by, но здесь агрегация MAX предотвращает это. И в этом есть смысл, потому что трудно поддерживать индексированное представление и сохранять какое-то максимальное значение точным при наличии удалений или обновлений (вставки легко).

Ваши варианты:

  1. Правильно индексируйте базовую таблицу.
  2. Вручную поддерживайте денормализованную версию данных.
person usr    schedule 24.10.2015