Есть ли способ сообщить оптимизатору запросов, что AddDate упорядочен так же, как и OrderId (поэтому данные уже упорядочены по AddDate)?
Нет, нетЭто невозможно.
Однако вы можете заказать по OrderId
вместо AddDate
, если AddDate
упорядочен так же, как OrderId
, он вернет те же результаты.Но, к сожалению, SQL Server все равно будет сканировать всю таблицу.
Не будем принимать таблицы заказов Northwind и столбец OrderDate.
Запрос:
SELECT *
FROM dbo.Orders
WHERE OrderDate BETWEEN '1997-12-10' AND '1998-03-05'
ORDER BY OrderDate
Производит этот план .Он полностью сканирует кластерный индекс при применении фильтра, а затем упорядочивает результат.
Запрос:
SELECT *
FROM dbo.Orders
WHERE OrderDate BETWEEN '1997-12-10' AND '1997-12-17'
ORDER BY OrderId -- It's equivalent to ordering by OrderDate
Создает этот план .Он также полностью сканирует кластеризованный индекс и применяет фильтр, но не упорядочивает.
Наличие OrderDate
в качестве ключа кластеризованного индекса кардинально улучшит производительность запроса, но вы, возможно, не захотите иметьтакой ключ кластеризованного индекса.Однако вы создаете облачный индекс, который также значительно повысит производительность:
CREATE INDEX IX_Orders_OrderDate ON dbo.Orders(OrderDate)
INCLUDE ([OrderID], [CustomerID], [EmployeeID], [RequiredDate], [ShippedDate], [ShipVia], [Freight], [ShipName], [ShipAddress], [ShipCity], [ShipRegion], [ShipPostalCode], [ShipCountry])
Запрос:
SELECT *
FROM dbo.Orders
WHERE OrderDate BETWEEN '1997-12-10' AND '1998-03-05'
ORDER BY OrderDate
Создает этот план .Он просто ищет индекс.Это не может быть быстрее.
Но этот индекс толстый, он будет наказывать за изменение данных.
Однако вы можете воспользоваться более тонким индексом, подобным следующему:
CREATE INDEX IX_Orders_OrderDate ON dbo.Orders(OrderDate, OrderId)
Используя запрос, подобный следующему:
DECLARE @FromOrderId int, @ToOrderId int;
SELECT TOP (1) @FromOrderId = OrderId FROM dbo.Orders WHERE OrderDate <= '1997-12-10' ORDER BY OrderDate DESC, OrderId DESC;
SELECT TOP (1) @ToOrderId = OrderId FROM dbo.Orders WHERE OrderDate >= '1998-03-05' ORDER BY OrderDate ASC, OrderId ASC;
SELECT *
FROM dbo.Orders
WHERE
(OrderId >= @FromOrderId OR @FromOrderId IS NULL)
AND (OrderId <= @ToOrderId OR @ToOrderId IS NULL)
ORDER BY OrderID
OPTION (RECOMPILE)
Выдает thisплан .Для решения вопроса достаточно 3 попыток.