我试图了解 SQL Server 如何尝试估计 SQL Server 2014 中的“大于”和“大于等于”where 子句。
我想我确实了解基数估计,例如,如果我这样做
select * from charge where charge_dt >= '1999-10-13 10:47:38.550'
Run Code Online (Sandbox Code Playgroud)
基数估计是 6672,可以很容易地计算为 32(EQ_ROWS) + 6624(RANGE_ROWS) + 16 (EQ_ROWS) = 6672(下面截图中的直方图)
但是当我这样做时
select * from charge where charge_dt >= '1999-10-13 10:48:38.550'
Run Code Online (Sandbox Code Playgroud)
(将时间增加到 10:48 所以它不是一步)
估计是 4844.13。
那是怎么计算的?
performance sql-server sql-server-2014 cardinality-estimates performance-tuning
我有一个简单的连接,如下所示:
select *
from fact_sales f
join dim_company d on f.company_SK = d.company_SK
Run Code Online (Sandbox Code Playgroud)
事实表包含略多于 5 亿条记录(带有 NC 列存储),查询将返回所有记录,但是,联接后的估计行数仅为 3 亿条。直到哈希连接,估计的行数是正确的,只有在连接之后才下降到 3 亿。这是查询的估计计划:
我已经更新了事实表(使用全扫描)和维度表中联接中使用的 SK 列的统计数据,这是每个表的直方图:
这个问题似乎只发生在数据库中的几个维度表上,加入其他维度表不会产生相同类型的基数估计问题 - 关于如何解决这个问题或进一步调查的任何建议?
如果我在查询中添加一个 where 子句,它会正确估计连接之前/之后的行数,例如
select *
from fact_sales f
join dim_company d on f.company_SK = d.company_SK where company_SK = 1
Run Code Online (Sandbox Code Playgroud)
将估计来自连接的 467,583,000 行,这与直方图中的内容相匹配。
该问题似乎仅在查询中没有任何过滤器时才会发生。它在更大的查询中导致问题(排序溢出)。我已经将范围缩小到这个特定的连接。
我确实有一个 FK 约束,但它们WITH NOCHECK在事实表上已被关闭 ( )(我们被告知关闭它们以便 ETL 可以更快)。不幸的是,重新打开 FK 不是一种选择:(
更新:启用跟踪标志 2301 解决了这个问题:p
sql-server execution-plan sql-server-2012 cardinality-estimates