在我的办公室,我们有一个非常丑陋的查询,但在生产环境和开发环境中运行良好(分别为 20 秒和 4 秒)。然而,在我们的测试环境中,它需要超过 4 小时。SQL2005(+最新补丁)正在生产和开发中运行。SQL2008R2 正在测试中运行。
我查看了查询计划,它显示 SQL2008R2 正在使用 TempDB,通过表假脱机(惰性假脱机)来存储从链接服务器返回的行。下一步显示嵌套循环(左反半连接)占用了 96.3% 的查询。两个运营商之间的界线是 5,398MB!
SQL 2005 的查询计划显示没有使用 tempdb,也没有使用 Left Anti Semi Join。
下面是经过清理的代码和执行计划,顶部是 2005 计划,底部是 2008R2。
是什么导致了急剧的减速和变化?我期待看到不同的执行计划,所以这不会打扰我。查询时间的急剧下降让我很困扰。
我是否必须查看底层硬件,因为 2008R2 版本使用的是 tempdb 我必须看看如何优化它的使用?
有没有更好的方法来编写查询?
谢谢您的帮助。
INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT
Table1.iGroupID,
GETDATE()
FROM Table1
WHERE
NOT EXISTS (
SELECT 1
FROM LinkedServer.Database.Table2 Alias2
WHERE
(
Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
AND NOT Alias2.FirstName IS NULL
AND NOT Alias2.LastName IS NULL
) OR (
Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
AND NOT Alias2.Familyname IS NULL
AND NOT Alias2.Child1Name IS NULL
) OR (
Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
AND NOT Alias2.StepFamilyName IS NULL
AND NOT Alias2.StepFamilyNameChild1 IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
)
) AND NOT EXISTS (
SELECT 1
FROM Table3
INNER JOIN Table4
ON Table4.FirstNameType = Table3.FirstNameType
INNER JOIN table5
ON table5.LastNameType = Table3.LastNameType
WHERE
Table3.iGroupID = Table1.iGroupID
AND Table3.bIsClosed = 0
AND Table4.sNameTypeConstant = 'new_lastname'
AND table5.sFirstNameConstant = 'new_firstname'
)
:: 编辑 :: 从不同的 SQL2005 实例执行查询,与“好”的执行计划几乎相同。仍然不确定两个 2005 版本对 2008R2 链接服务器的运行效果如何优于 2008R2 实例对 2008R2 实例的运行效果。
虽然我不否认代码可以使用一些工作,但如果代码是问题所在,我不会在我的所有试验中看到相同的执行计划吗?不管SQL版本如何?
:: 编辑 :: 我已将 SP1 和 CU3 应用于两个 2008R2 实例,但仍然没有骰子。我在链接服务器中专门设置了搭配,没有骰子。我已将我的用户帐户的权限专门设置为两个实例上的系统管理员,没有骰子。我还记得我的 sql server 2008 内部结构和故障排除,我们将看看我是否能找到一些方法。
感谢大家的帮助和提示。
:: 编辑 :: 我对链接服务器进行了各种权限更改。我使用过 SQL 登录、域登录、模拟用户、使用过“使用此安全上下文”选项。我在链接服务器的两端都创建了在服务器上具有系统管理员权限的用户。我没主意了。
我仍然想知道为什么 SQL2005 执行的查询与 SQL2008R2 截然不同。如果是查询不好,我会在 SQL2005 和 SQL2008R2 上看到 4 小时以上的运行时间。
添加到前面的答案中,计划回归的原因可能是由于计划包含反半联接时已知的基数估计错误。见知识库 2222998
假设 2005 计划产生了可接受的性能,您可能会发现将服务器升级到包含该修复程序的版本(并启用 TF4199 来激活它)将使您返回“良好”计划。
也就是说,还有许多其他机会可以改进该查询,因此这可能是专注于这样做的好时机。
我建议远程数据在本地假脱机,因为其中之一
对于第 1 点,请参阅sp_serveroption
对于第 2 点,还要检查 server/db 排序规则。
对于第 3 点,请参阅 Linchi Shea 的这些:
您要求 SQL Server 在本地处理所有数据,按照我的回答: 在视图中使用 OPENQUERY 的性能影响
编辑
再看一遍,我看到“好”计划有 2 个远程调用,而不是 1 个。这证实了我在这里所说的
我希望您重新编写查询。
您有 sargability 问题,甚至在那里使用标量函数调用,这也会损害查询。您可能希望在 Table2 上创建一个 FullName 计算列并在其上放置一个索引,确保您的索引包括 FirstName 和 LastName。您还应该添加有助于其他人的索引
此外,制作一个内联表值函数来执行“RemoveNonLetter”功能,并重新编写查询以使用它,可能像我在这里所做的那样使用 APPLY。
并且一定要检查保罗的回答 所指的那个错误。
这种比较有很多问题......我只是不知道从哪里开始。
为您的生产和测试机器获取准确的规格。
确定两种环境中各种链接服务器之间的网络链接。他们的速度一样吗?两种环境中的服务器是否彼此相邻?
有什么办法可以重写查询以不使用链接服务器?跨服务器连接表会使您容易受到拓扑变化的影响,并且在大多数情况下他的速度非常慢。
使用 NOT 和 OR 通常会导致全表扫描。尝试重写查询。
+1 尝试从 datagod 重写您的查询评论。
我还想知道您是否在链接服务器端遇到权限问题,从而导致速度变慢。不久前,我在博客中谈到了这个链接服务器的减速。可能值得验证 perms(它是 SQL 链接服务器吗?还是另一个 DBMS?如果是后者,那么无论如何你都不会得到很好的统计数据)
您是否还在测试环境中使用 SQL Server 2005 来尝试此查询并排除该环境?
升级后您是否重建了统计信息?