gpt4 book ai didi

sql - 估计的子树成本大幅下降,糟糕的优化

转载 作者:行者123 更新时间:2023-12-04 03:15:50 25 4
gpt4 key购买 nike

我将一个有两个记录 ID 字段(record1、record2)的表连接到一个 View 两次——每条记录一次——并选择前 1000 个。该 View 由几个相当大的表组成,它的 id 字段是它们各自 ID 的字符串连接(这对于某些需要 View 的唯一 ID 的第三方软件来说是必需的。行编号非常慢)。 View 中还有一个 where 子句调用比较日期的函数。

估计的执行计划会产生“No Join Predicate”警告,除非我使用 OPTION(FORCE ORDER)。通过强制排序,执行计划有多个节点显示 100% 成本。在这两种情况下,端点处的估计子树成本比其中一个节点小 13 个数量级(它正在执行 lot 或嵌套循环连接,CPU 成本高达 35927400000000)

执行计划中的数字是怎么回事?为什么 SQL Server 很难优化查询?

只需向连接字符串的 View 添加索引并使用 NOEXPAND 表提示即可完全解决问题。它运行了 12 秒。但是为什么 sql 如此糟糕(甚至在我添加索引后需要 noexpand 提示)?

使用 CU 8 运行 SQL Server 2008 SP1。

View :

SELECT
dbo.fnGetCombinedTwoPartKey(N.NameID,A.AddressID) AS NameAddressKey,
[other fields]

FROM
[7 joined tables]
WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1

查询

SELECT TOP 1000
vw1.strFullName,
vw1.strAddress1,
vw1.strCity,
vw2.strFullName,
vw2.strAddress1,
vw2.strCity
FROM tblMatches M
JOIN vwImportNameAddress vw1 ON vw1.NameAddressKey = M.Record1
JOIN vwImportNameAddress vw2 ON vw2.DetailAddressKey = M.Record2

最佳答案

看起来您已经非常接近解释了。这是因为:

The view consists of several rather large tables, and it's id field is a string concatenation of their respective Ids...

这会创建一个不可优化的连接谓词条件,并防止 SQL Server 使用基表上的任何索引。因此,引擎必须对每个连接(在您的情况下是两个)执行所有基础表的完整扫描。

也许为了避免进行多次全表扫描(每个表扫描一次,乘以连接数),SQL Server 决定简单地使用笛卡尔积并在之后进行过滤会更快(因此“不加入谓词”警告)。当您FORCE ORDER 时,它会尽职尽责地执行您最初要求的所有完整扫描和嵌套循环。

我确实同意一些评论,即此 View 是有问题的数据模型的基础,但正如您所发现的那样,短期解决方法是为 View 中的计算 ID 列编制索引,这(显然)使得它再次可搜索,因为它具有实际生成的 ID 的哈希值。


编辑:我在第一次通读时也错过了这个:

WHERE dbo.fnDatesAreOverlapping(N.dtmValidStartDate,N.dtmValidEndDate,A.dtmValidStartDate,A.dtmValidEndDate) = 1

这又是一个不可优化的谓词,会导致性能不佳。在 UDF 中包装任何列将导致此行为。索引 View 也会具体化它,这也可能影响查询速度;如果没有索引,则每次都必须评估此谓词并强制对基表进行全面扫描,即使没有复合 ID。

关于sql - 估计的子树成本大幅下降,糟糕的优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3189409/

25 4 0
文章推荐: installation - Cygwin 没有正确安装
文章推荐: ruby-on-rails - 同一个应用程序中的 Heroku Delayed Job 和 Sidekiq
文章推荐: c# - 为什么不能将 Action 委托(delegate)用作线程池的 WaitCallback?