我正在尝试提高复杂存储过程的性能。瓶颈是这个巨大的查询,它有超过 30 个连接(其中大部分都留下了),并且 WHERE 语句中的条件数量多得离谱。此外,SELECT 部分包含对多个函数的调用,这些函数也执行重要的工作。
伪示例:
select fn_DoWork1(caseID, orderID) as cln1,
fn_DoWork2(caseID, orderID) as cln2,
... 20 other columns
BalanceDue
from tbl1
left join tbl2 on ...
...
left join tbl30 on ...
where
(tbl10.ArrivalDate between @foo1 and @foo2)
...
(@prmProcessingID = 0 OR tbl10.ProcessingID = @prmProcessingID)
你明白了。我将查询分成更小的部分,一路将数据存入临时表中,以便每个连续的查询都必须处理较小的子集。但最终,它仍然匹配了数千条记录,因此性能并没有像我希望的那样提高。
我的下一个想法是一次只返回 1 页记录(每页 20 条记录),因为这就是用户需要查看的全部内容。所以我添加了
OFFSET x ROWS
和 FETCH NEXT 20 ROWS ONLY
并解决了性能问题。
但是,现在的问题是我返回了 20 行,但我不知道总共有多少行符合条件。因此,我无法告诉用户有多少页数据 - 例如我无法在 UI 上正确呈现寻呼机。
有没有更好的方法来解决这个问题?
有没有更好的方法来解决这个问题?
计算行数需要评估整个数据集上的 JOIN 和 WHERE 子句,因此运行查询和存储结果的成本几乎很高。
您的选择是运行完整查询并缓存结果,或者采用不显示总页数的 UX。
尝试将查询分解为多个WITH语句,并将函数调用推迟到最后一个可能的查询,以简化查询结构。 从逻辑上讲,它们与一个大查询相同。
David Browne 是正确的,如果你不需要在前端 UI 中显示行数,就不要计算它。
我们按照这个顺序执行了所有的WITH语句
WITH customerData AS
(
SELECT customer data fields used and join in lookup data WHERE filter in only active customers
),
purchaseOrders as
(
SELECT purchase order fields where customer Id in CustomerData rows and date range in A to B
),
...
然后最终查询加入右侧的With语句并调用函数、case语句等
它的好处是你可以慢慢地将原始查询重构为一系列更简单的查询。