我似乎在SQL 2008中面临一个奇怪的问题。
我有一个查询,它可以从查询分析器中快速运行,但是如果通过存储过程运行则会超时! SP只是从此查询开始,在此查询之前没有其他代码
SELECT col1,col2 FROM TBL1 (nolock)
INNER JOIN TBL2 (nolock)
ON tbl1.col=LEFT(tbl2.col1,LEN(tbl2.col1)-2) AND tbl1.col2=RIGHT(tbl2.col1,2)
AND tbl1.col4=2233
AND tbl1.date1 BETWEEN tbl2.date1 and isnull(tbl2.date2,getdate())
请注意,tbl1实际上是一个视图,其中col和col2是通过自联接来的。另外,根据业务需求,tbl2.col1需要具有连接值。如果需要解决这个问题,我可以修改我的观点。
答案 0 :(得分:2)
作为一个副作用,请注意,如果你可以对字符串长度做一些假设,你的连接表达式可以简化(并且可能会获得更好的性能,因为一方现在使用相等):
SELECT tbl1.col1, tbl1.col2
FROM
TBL1
INNER JOIN TBL2
ON tbl1.col + tbl1.col2 = tbl2.col1
AND tbl1.col4=2233
AND tbl1.date1 BETWEEN tbl2.date1 AND Coalesce(tbl2.date2, GetDate())
另外,如果您正在寻找最佳性能,请尝试以下方法:
ALTER TABLE TBL2 ADD LeftPart AS (LEFT(col1, LEN(col1)-2));
ALTER TABLE TBL2 ADD RightPart AS (RIGHT(tbl2.col1,2));
CREATE NONCLUSTERED INDEX IX_TBL2_Parts ON TBL2 (LeftPart, RightPart);
现在你可以这样加入:
SELECT tbl1.col1, tbl1.col2
FROM
TBL1
INNER JOIN TBL2
ON tbl1.col = tbl2.LeftPart
AND tbl1.col2 = tbl2.RightPart
AND tbl1.col4=2233
AND tbl1.date1 BETWEEN tbl2.date1 AND Coalesce(tbl2.date2, GetDate())
更好,更改数据库设计以将TBL2.col1数据实际存储在两列中。您通过在一列中放置两个不同的数据来违反第一个正常形式,现在,正如您所发现的那样,您在整个应用程序中就性能,开发和放大而付费。维护时间,查询复杂性等。
您甚至可以反转我的方案,以便LeftPart和RightPart列是真实的,并且您创建一个具有Col1名称的新计算列,其中包含一个索引,用于实现值并使它们可搜索。最后,如果绝对需要,您可以重命名表,使用旧名称在表上创建视图,然后在视图上放置INSTEAD-OF触发器以拦截对表的数据操作并将它们转换为正确的模式。 / p>
<强>更新强>
顺便说一句,如果你对表格设计有任何影响,你可能要考虑使用“99991231”的“开放结束日期”值或tbl2.date2而不是NULL。 Coalesce可以扼杀性能,有时在可能进行搜索时强制进行扫描。
答案 1 :(得分:1)
过去我遇到过由parameter sniffing引起的类似情况。您可以尝试上面文章中讨论的方法,看看它是否有所作为。
当您第一次运行存储过程时,SQL Server会缓存它的执行计划并将其用于未来。如果运行带有参数的存储过程使这个执行计划不是最佳的,那么你可以看到你所描述的行为。
您还可以使用查询提示recompile
来确保每次执行时都使用新的执行计划。为此,您需要在查询末尾添加OPTION(RECOMPILE)
:
SELECT id, name
from tableName
WHERE id between @min and @max
OPTION(RECOMPILE);
This link针对参数嗅探问题找到了几个解决方案。