2

我有一个存储过程的一部分,它被调用了成千上万次,因此占据了整个过程的大部分。通过执行计划运行它后,看起来 TOP 4 和 Order By 部分占据了很多。order by 使用的功能虽然简化了,但仍会被使用。

这是一个奇怪的情况,因为对于 99.5% 的数据,无论如何都会返回 4 个或更少的结果,只有 0.5% 的时间我们需要 TOP 4。这是数据算法的要求,因此消除了 TOP 4 完全不是一个选项。

所以可以说我的语法是

SELECT SomeField * SomeOtherField as MainField, SomeOtherField
FROM
(
    SELECT TOP 4
        SomeField, 1/dbo.[Myfunction](Param1, Param2, 34892) as SomeOtherField
    FROM #MytempTable
    WHERE 
        Param1 > @NextMargin1 AND Param1 < @NextMargin1End
        AND Param2 > @NextMargin2 AND Param2 < @NextMargin2End
    ORDER BY dbo.[MyFunction](Param1, Param2, 34892)
) d

有没有一种方法可以告诉 SQL Server 当且仅当在 where 发生后返回超过 4 个结果时才进行排序?否则我不需要订单。也许是一个表变量和if中的表计数?

--- 基于 Davids Answer 的更新,试图找出它变慢的原因:

我做了检查,可以确认 96.5% 的时间有 4 个或更少的结果,所以这不是数据比预期更多的情况。

这是插入到@FunctionResults 的执行计划 执行计划 1

以及插入和线轴的故障: 故障

然后是top4和orderby的选择执行计划: 执行计划2

如果需要任何进一步的信息或细分,请告诉我,#Mytemptable 的大小通常为 28000 行并且它有索引

CREATE INDEX MyIndex on #MyTempTable (Param1, Param2) INCLUDE ([SomeField])
4

1 回答 1

2

此答案已根据提问者的持续反馈进行了更新。最初的建议是尝试使用表变量来存储预先计算并从结果中选择前 4 个。然而,在实践中,优化器似乎高估了行数并选择了错误的执行计划。

除了之前的建议之外,我还建议在对此过程进行任何更改后定期更新统计信息,以便为查询优化器提供更新的信息,从而做出更明智的决策。

由于这是一个无法直接访问源环境的性能调整过程,因此预计此答案会根据用户反馈而改变。根据上面@SteveFord 的建议,下面的示例查询反映了使用 CROSS APPLY 来尝试避免多次不必要的函数调用。

SELECT TOP 4
    M.SomeField,
    M.SomeField * 1/F.FunctionResults [SomeOtherField]
FROM #MytempTable M
CROSS APPLY (SELECT dbo.Myfunction(M.Param1, M.Param2, 34892)) F(FunctionResults)
ORDER BY F.FunctionResults
于 2013-10-29T14:44:56.347 回答