Во всех версиях ProductStatus столбец DateTime во вторичном индексе (не PK) имеет значение DESCending;самое последнее - «сначала»Конечно, вам нужно экспериментировать с набором данных разумного размера и принимать собственные решения.Если здесь есть что-то, чего вы не понимаете, пожалуйста, спросите, и я расширю.
Ответы на комментарии
Сообщите обо всех продуктах с текущим состоянием 2
<code>SELECT ProductId,
Description
FROM Product p,
ProductStatus ps
WHERE p.ProductId = ps.ProductId -- Join
AND StatusCode = 2 -- Request
AND DateTime = ( -- Current Status on the left ...
SELECT MAX(DateTime) -- Current Status row for outer Product
FROM ProductStatus ps_inner
WHERE p.ProductId = ps_inner.ProductId
)
ProductId
Индексируется, ведущий столбец, обе стороны
DateTime
в индексированном, 2 столбец в покрытом запросеОпция
StatusCode
индексируется, 3-й столбец - в покрытом запросетребуется для удовлетворения внутреннего запроса
строки требуются одновременно для одного запроса;они близко друг к другу (благодаря Clstered Index);почти всегда на одной странице из-за короткого размера строки.
Это обычный SQL, подзапрос, использующий возможности механизма SQL, обработка реляционного набора.Это один правильный метод , нет ничего быстрее, и любой другой метод будет медленнее.Любой инструмент отчетов создаст этот код несколькими щелчками мыши, без ввода.
Две даты в ProductStatus
Столбцы, такие как DateTimeFrom и DateTimeTo, являются грубыми ошибками.Давайте рассмотрим это в порядке важности.
Это грубая ошибка нормализации.DateTimeTo легко выводится из единственного DateTime следующей строки;поэтому он является избыточным, дублирующим столбцом.
- Точность не входит в это: это легко решается с помощью DataType (DATE, DATETIME, SMALLDATETIME).Независимо от того, отображаете ли вы одну секунду, микросекунду или наносекунду, это бизнес-решение;это не имеет ничего общего с данными, которые хранятся.
Реализация столбца DateTo является 100% дубликатом (DateTime следующей строки). Это занимает вдвое больше дискового пространства . Для большого стола это было бы значительным ненужным мусором.
Учитывая, что это короткая строка, вам потребуется вдвое больше логических и физических операций ввода-вывода для чтения таблицы при каждом доступе.
И в два раза больше кэш-памяти (или, иначе, только половина строк будет помещаться в любое данное пространство кеша).
Вводя дубликат столбца, вы ввели возможность ошибки (теперь значение можно получить двумя способами: из дубликата столбца DateTimeTo или DateTimeFrom следующей строки).
Это также Аномалия обновления . При обновлении любого DateTimeFrom обновляется, DateTimeTo предыдущей строки должны быть извлечены (нет ничего сложного, поскольку он близок) и Обновлено (большое дело, поскольку это дополнительный глагол, которого можно избежать).
«Короче» и «ярлыки кодирования» не имеют значения, SQL - это громоздкий язык манипулирования данными, но SQL - это все, что у нас есть (просто справиться с этим). Любой, кто не может кодировать подзапрос, не должен кодировать. Любой, кто дублирует столбец, чтобы облегчить незначительную «сложность» кодирования, не должен моделировать базы данных.
Обратите внимание, что если правило высшего порядка (нормализация) сохраняется, то устраняется весь набор проблем более низкого порядка.
Думайте в терминах наборов
Любой, кто испытывает «трудности» или испытывает «боль» при написании простого SQL-кода, страдает при выполнении своей функции работы. Обычно разработчик не думает в терминах наборов , а реляционная база данных - модель, ориентированная на наборы .
Для вышеприведенного запроса нам нужен Current DateTime; поскольку ProductStatus представляет собой набор состояний продукта в хронологическом порядке, нам просто требуется последний или MAX (DateTime) set , принадлежащий продукту.
Теперь давайте посмотрим на что-то якобы "сложное", с точки зрения наборов . Для отчета о продолжительности пребывания каждого Продукта в определенном состоянии: DateTimeFrom - это доступный столбец, который определяет горизонтальное ограничение: sub set (мы можем исключить более ранние строки); DateTimeTo является самым ранним из подмножества набора состояний продукта.
<code>SELECT ProductId,
Description,
[DateFrom] = DateTime,
[DateTo] = (
SELECT MIN(DateTime) -- earliest in subset
FROM ProductStatus ps_inner
WHERE p.ProductId = ps_inner.ProductId -- our Product
AND ps_inner.DateTime > ps.DateTime -- defines subset, cutoff
)
FROM Product p,
ProductStatus ps
WHERE p.ProductId = ps.ProductId
AND StatusCode = 2 -- Request
Мышление в терминах получения следующей строки ориентировано на строки, не - ориентированная на множество обработка. Ухудшается при работе с базой данных, ориентированной на множество. Пусть Оптимизатор сделает все это за вас. Проверьте свой SHOWPLAN, это прекрасно оптимизирует.
Неспособность мыслить в наборах , ограничиваясь тем самым написанием только одноуровневых запросов, не является разумным оправданием для: реализации масштабного дублирования и обновления аномалий в базе данных; тратить онлайн ресурсы и дисковое пространство; гарантируя половину производительности. Гораздо дешевле научиться писать простые подзапросы SQL для получения легко получаемых данных.