我有一个使用以下条件连接表的查询:
(Apps.mfrId = Manufacturer.id OR Apps.mfrId IS NULL OR Apps.mfrId = 0)
查询需要17秒才能运行,并且使用分析器查询会导致5到30条消息(每次运行会有所不同),并显示错误"错误:1222,严重性:16,状态:18"。
我保持查询完全相同,但我将上述条件更改为:
(Apps.mfrId = Manufacturer.id OR ISNULL(apps.mfrId, 0) = 0)
...现在,使用这一个更改的相同查询在140毫秒内运行并且没有锁定错误。
为什么会发生这种情况?
注意,在对表制造商和应用程序进行测试之前,我已经使用repair_bebuild选项运行了DBCC CHECKTABLE,并且还在两个表上重建了索引。
另请注意,同时没有其他查询针对数据库运行。
以下是查询的简化版本,其中包含错误:
select top 2000 Apps.object_id
from
Manufacturer
INNER JOIN Apps ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0
)
where
Apps.OBJECT_ID = 6879149
如果不是" top 2000"我用"前1000"查询完成时间超过100毫秒。
答案 0 :(得分:0)
如果Apps.mfrId为null,则您将加入每个制造商。
从您的测试中,"或ISNULL(apps.mfrId,0)= 0"这是否比"或Apps.mfrId IS NULL或Apps.mfrId = 0"
这些似乎非常相同,而且你已经有了修复,所以问题就是为什么和/或如何使非执行者工作。
说到这样的表现,如果你说的一切都是正确的,当我们开始问为什么时,我们就会开始指向查询优化工具。如果它对相同的参数执行不同的操作,则它将具有不同的查询计划。您可能会看到表扫描而不是索引使用情况,或者对性能不佳的其他解释。
我鼓励您比较查询计划,或者让其他人参与,以帮助回答有关不同的做法。但是,你已经可以告诉它采取不同的做法了。
一种可能性是,当查询优化工具修复程序被释放时,默认情况下它们不会打开,除非标记4199 (对于所有修复程序或特定修复程序的其他标记)打开了。这是因为一般修复可能对大多数人有好处,但也可能会破坏在现有先前怪癖环境中优化的应用程序。
https://dba.stackexchange.com/questions/102292/trace-flag-4199-enable-globally
在帮助上转4199吗?
select top 2000 Apps.object_id
from
Manufacturer
INNER JOIN Apps ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0
)
where
Apps.OBJECT_ID = 6879149
OPTION(QUERYTRACEON 4199)
另一个相关主题是参数嗅探。有时,查询计划可以缓存,这对于一个参数是最佳的,但对于另一个参数则是可怕的。在您的情况下,一个应用程序可能会返回1个制造商,但另一个应用程序可能会返回所有制造商,这就是值得一提的原因。当给定不同的参数时,这通常表现为相同的代码不一致地表现不佳。 您可以尝试关闭参数嗅探或强制重新编译,以帮助诊断是否这似乎是问题的一部分。
What are the main differences between OPTION(OPTIMIZE FOR UNKNOWN) and OPTION(RECOMPILE)?
我已经看到过,如果觉得查询优化器已经放弃了仔细阅读索引,只是因为语句过于复杂。但在你的例子中,这似乎不太可能;除了查询优化器的主题错误得到修复,但要使用它们你仍然必须打开查询标志,否则你安装的补丁可能会做什么都没有。
有时你也可以尝试帮助指导sql优化器。如果存在应始终使用的索引,则可以将其作为查询提示给出。
我也很想知道以下是否解决了这个问题:
select top 2000 Apps.object_id
from
(
select Apps.object_id, Apps.mfrId
from Apps
where Apps.OBJECT_ID = 6879149
) Apps
left join Manufacturer ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0 )
如果启用了所有查询优化器修复程序,并且问题仍然存在,我们必须询问查询优化程序为何这样做。它只能使用存在的索引,并且只能确定在存在统计信息时使用索引是否有益。与此同时,过时的统计数据将导致糟糕的选择。最好定期重建/重组索引并更新统计信息。您可能想尝试这样做,看看它是否有任何影响。
<强>结论强>
由于您已经有了工作修复,请使用它。但你的问题是为什么两个非常相似的事情会产生截然不同的结果。假设正在使用相同的参数,并且包括两个选项非常相似的事实,则问题指向查询优化器做出错误的选择。这表明您可能需要同时安装最新的修补程序(如果未安装)并启用4199以实际启用已通过sql server修补程序安装的所有查询优化程序修补程序。这包括将OPTION(QUERYTRACEON 4199)添加到sql的底部,或全局启用4199或类似的。