我有一个表格(Orders
和CLUSTERED IDENTITY PRIMARY KEY
(OrderId
),并且我正在过滤和排序添加日期列(AddDate
)。
有没有一种方法可以告诉查询优化器AddDate
的排序方式与OrderId
相同(因此数据已经由AddDate
排序了)?
SQL Server确实不需要扫描整个表然后对其进行排序。所有操作所需的是扫描表直到找到结束日期,然后在开始日期之前过滤掉数据并按原样返回(不进行排序)。
示例:
SELECT
*
FROM Orders
WHERE AddDate BETWEEN @FromDate AND @ToDate
ORDER BY AddDate
答案 0 :(得分:4)
有没有办法告诉查询优化器AddDate是有序的 OrderId的方式相同(因此,数据由AddDate排序 已经)?
不,没有任何办法。
但是,您可以通过interface Bar<T extends NoParameterCtor<unknown>> {
theConstructor: T,
theInstance: InstanceType<T>
}
class Zar implements Bar<typeof Zoo> {
theConstructor = Zoo; // the constructor
theInstance = new Zoo(); // an instance
}
而不是OrderId
进行订购,如果AddDate
的订购方式与AddDate
相同,则会返回相同的结果。但是不幸的是,SQL Server还是会扫描整个表。
不要使用Northwind订单表和OrderDate列。
查询:
OrderId
产生this plan。在应用过滤器时,它将完全扫描聚簇索引,然后对结果进行排序。
查询:
SELECT *
FROM dbo.Orders
WHERE OrderDate BETWEEN '1997-12-10' AND '1998-03-05'
ORDER BY OrderDate
产生this plan。它还会完全扫描聚簇索引并应用过滤器,但是不排序。
使用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])
产生this plan。它只是在寻找索引。它不可能更快。
但是该索引很胖,它会惩罚数据修改。
但是,您可以利用以下更薄的索引:
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)
它产生this plan。只需3次即可解决查询。
答案 1 :(得分:2)
您无能为力了。首先,如果您知道排序方式相同,则没有理由为什么要用AddDate
而不是OrderId
来排序结果集。
其次,如果您知道这种关系,您可以按照@耶稣向您展示的日期框架OrderId
进行分配。
最好的方法是在OrderDate
(仅)上创建附加索引。对于这样一个简单的查询,这将是最好的方法,不需要包括额外的列,无论如何,PK都将在后台覆盖,并且将基于整个过滤。
您仍然可以带来一些改进的最后一个选择(虽然不如索引好,但仍会有所帮助)是在OrderDate
列上添加额外的统计信息,基于这些统计信息,SQL Server的kardionality估计器将能够产生这些统计信息更好的计划应该可以提高性能。
答案 2 :(得分:1)
您可以在AddDate的OrderId上添加非聚集索引:
CREATE INDEX IX_Orders_AddDate_OrderID
ON dbo.Orders(AddDate, OrderID)
然后重写查询:
SELECT *
FROM Orders
WHERE OrderId >=
(SELECT MIN(OrderId)
FROM dbo.Orders
WHERE AddDate >= @FromDate) AND
OrderId <=
(SELECT MAX(OrderId)
FROM dbo.Orders
WHERE AddDate <= @ToDate)
ORDER BY AddDate