我有一个查询,其中包含多个性能不佳的联接。经过大量分类后,我决定拆开查询,只看驱动表。以下是仅基于驱动表的查询示例。
DECLARE @VAR AS INT
SET @VAR = 11652862
SELECT Field1, Field2
FROM tablea
WHERE Field2 = @VAR
当我按原样运行代码时,实际执行计划会返回 15k 估计行和 1m 实际行。是的,这只是一个简单的SELECT...FROM TABLE
,但请记住,这只是更大查询的一部分,因此随着我们添加更多连接,这种估计差异会大大增加。
我知道问题是@VAR
因为优化器在将查询编译成计划时不知道变量的值,所以它返回字段估计的平均行数。如果我添加OPTION (RECOMPILE)
它将在编译时强制输入值并返回正确的行数。
关键是:这不是我公司可以编辑的自定义代码。它是我无法编辑的第三方应用程序的一部分。更新统计数据无济于事(我查看了直方图,它正确地列出了我的变量的值)。我已经有了这两个领域的覆盖 NC 索引。我能想到的唯一选择是对该查询使用强制执行计划。不过,我从来没有能够成功地做到这一点。有人对强制执行计划有任何其他想法或很好的操作方法参考吗?
由于在评论中被问到,索引的创建语句是:
CREATE NONCLUSTERED INDEX idx ON tablea (Field2)
除了计划指南,我还有其他想法,我会将它们张贴在这里供您考虑,但我不建议实际实施它们。至少有两种不同的方法可以提高 tablea 的行估计值。第一个涉及手动设置统计信息,第二个涉及重定向第三方应用程序以使用您定义的视图而不是直接访问 tablea。
CREATE STATISTICS 和 UPDATE STATISTICS 都有一个 STATS_STREAM 选项。以下是联机丛书对它的描述:
如果这让您无法使用它,那是完全可以理解的,但它允许您做的是将统计数据从一个对象移植到另一个对象。假设您希望将使用 tablea 的查询的基数估计值提高 50 倍。您可以从 tablea 中获取数据,将其复制 50 次,使用 FULLSCAN 收集统计信息,然后使用来自其他表的 STATS_STREAM 值以及 NORECOMPUTE 选项更新 tablea 上的统计信息。您可能还想更改 ROWCOUNT 值。这应该对引用该表的所有查询产生相当大的影响。您可能会遇到其他查询的问题,表中的基础数据发生变化,索引统计信息未更新等等。这不是一个好的选择。
根据第三方应用程序连接到 SQL Server 的方式,您可以使用与 tablea 不同的架构创建视图,并指示应用程序的该部分在视图中使用。该视图应具有与 tablea 相同的所有列,但应具有增加返回行数的附加代码。我没有那么努力地让它工作,因为它看起来很不切实际,但这种方法的灵感来自 Adam Machanic 关于强制执行并行计划的文章:
我对那个查询不是很满意,但也没有花太多时间在上面。在这种形式下,它对表进行一次扫描,但查询优化器将基数估计高估了 100 倍。TF 8690 用于防止无意义的表假脱机,但这可能不适用于视图或较大的查询。如果同一个应用程序将数据插入到该表中,您需要以某种方式处理它。这不是一个好的选择。
重申一下,我认为您不应该尝试这两种选择中的任何一种。与供应商交谈会好得多,或者如果这不起作用,请接受它并使用计划指南重试。我对这些没有任何经验,所以我无法提供帮助。