-- Create a simple orders table CREATE TABLE Orders (OrderDate DATE NOT NULL,Col2 INT NOT NULL,Col3 INT NOT NULL ) GO-- Create a Non-Unique Clustered Index on the table CREATE CLUSTERED INDEX idx_CI ON Orders(OrderDate) GO-- Insert 31465 rows from the AdventureWorks2008r2 database INSERT INTO Orders (OrderDate, Col2, Col3) SELECT OrderDate, CustomerID, TerritoryID FROM AdventureWorks2008R2.Sales.SalesOrderHeader GO-- Rebuild the Clustered Index, so that we get fresh statistics. -- The last value in the Histogram is 2008-07-31. ALTER INDEX idx_CI ON Orders REBUILD GO-- Insert 200 additional rows *after* the last step in the Histogram INSERT INTO Orders (OrderDate, Col2, Col3) VALUES ("20100101", 1, 1) GO 200在索引重建后,我们再看下直方图,我们发现最后步进的值是2008-07-31。
你已经看到,在最后步进到表里后,我们插入了200条额外记录。这样的话,直方图并没有真实反馈实际的数据分布情况,但SQL Server还是要进行基数计算。我们现在来看看在不同版本里SQL Server是如何处理这个问题的。
复制代码 代码如下:
SQL Server 2005 SP1- SQL Server 2012
在SQL Server 2014之前,基数计算对此问题的处理非常简单:SQL Server估计行数为1,你可以从下面的图片里看到。
点击工具栏的显示包含实际的执行计划,并执行如下查询:
复制代码 代码如下:
SELECT * FROM dbo.Orders WHERE OrderDate="2010-01-01"
自SQL Server 2005 SP1起,查询优化器可以标记1列为自增长(Ascending)来克服刚才介绍的限制。如果你用自增长列值更新了统计信息对象3次,那列就会被标记为自增长列。为了看有没有列标记为自增长,你可以使用跟踪标记2388。当你启用这个跟踪标记,DBCC SHOW_STATISTICS的输出就改变了,有额外列返回。
复制代码 代码如下:
DBCC TRACEON(2388)
DBCC SHOW_STATISTICS("dbo.Orders", "idx_CI")
现在下面的代码更新统计信息3次,每次用自增长键列值在我们聚集索引末尾插入行。
-- => 1st update the Statistics on the table with a FULLSCANUPDATE STATISTICS Orders WITH FULLSCANGO-- Insert 200 additional rows *after* the last step in the HistogramINSERT INTO Orders (OrderDate, Col2, Col3) VALUES ("20100201", 1, 1)GO 200 -- => 2nd update the Statistics on the table with a FULLSCAN UPDATE STATISTICS Orders WITH FULLSCAN GO-- Insert 200 additional rows *after* the last step in the Histogram INSERT INTO Orders (OrderDate, Col2, Col3) VALUES ("20100301", 1, 1) GO 200-- => 3rd update the Statistics on the table with a FULLSCAN UPDATE STATISTICS Orders WITH FULLSCAN GO然后,当我们执行DBCC SHOW_STATISTICS命令,你会看到SQL Server已讲那列标记为Ascending。
-- Now we query the newly inserted range which is currently not present in the Histogram.-- With Trace Flag 2389, the Query Optimizer uses the Density Vector to make the Cardinality Estimation.SELECT * FROM OrdersWHERE OrderDate = "20100401"OPTION (RECOMPILE, QUERYTRACEON 2389)GO来看下现在的表密度:
这虽然不是最好的结果,但比估计行数1好很多!
(这里有问题,我本地是SQL Server 2008r2,测试估计行数还是1,不知原因,望知道的朋友解释下,多谢!)
SQL Server 2014
在SQL Server 2014引入的一个新功能是新基数计算。新基数计算对于自增长键问题的处理非常简单:默认不使用任何跟踪标记,来使用统计信息对象的密度向量来进行基数计算。下面查询启用2312跟踪标记的基数计算来运行同个查询。
1 -- With the new Cardinality Estimator SQL Server estimates 28.4516 rows at the Clustered Index Seek operator.2 SELECT * FROM Orders3 WHERE OrderDate = "20100401"4 OPTION (RECOMPILE, QUERYTRACEON 2312)5 GO