【发布时间】:2021-12-31 20:01:41
【问题描述】:
我有一些 SQL 可以自己快速运行,但是当同一个 SQL 在存储过程中时速度会慢 60 倍。 SQL 在其许多查询中使用临时表。为什么在 sp 中速度较慢?
【问题讨论】:
标签: performance stored-procedures sybase temp-tables sap-ase
我有一些 SQL 可以自己快速运行,但是当同一个 SQL 在存储过程中时速度会慢 60 倍。 SQL 在其许多查询中使用临时表。为什么在 sp 中速度较慢?
【问题讨论】:
标签: performance stored-procedures sybase temp-tables sap-ase
tl;dr
填充(临时)表后,考虑 a) 运行 create index 和/或 b) 在桌子上运行update statistics;这两者都提供以下好处:
如果没有minimal, reproducible example(包括 ASE 版本和查询计划),很难 100% 肯定地说,但需要考虑一些想法:
不管为什么 proc 的查询是使用不太理想的查询计划运行的,一般的“解决方案”是确保使用一些关于 temp 的最新信息来编译查询表。
如何/何时(重新)编译 proc 的查询取决于 ASE 版本和任意数量的相关场景:
deferred name resolution、procedure deferred compilation 和 optimize temp table resolution,它们可以指示何时编译 proc 中的单个查询;但如果想法 #2(上图)正在发挥作用,即使这样也可能还不够with recompile(在每次运行时强制重新编译)但如果(再次)想法 #2(上文)在起作用,这可能还不够update statistics(同样,最好在填充临时表之后)应该强制重新编译任何后续查询虽然文档建议在调用 proc 之前创建临时表可能有一些好处,但这里也存在一些缺陷:
【讨论】:
Sybase says, "当您在使用它的同一个存储过程或批处理中创建表时,查询优化器无法确定该表的大小,因为该表不是在优化查询时创建的。这适用于临时表和普通用户表。”
Sybase 建议在存储过程之外创建临时表。如果您以某些方式创建索引,还有一些解决方案。请参阅Sybase docs 了解更多详情
【讨论】:
你的存储过程有参数吗?
如果是,SQL Server 在执行具有参数的存储过程时会使用一个称为参数嗅探的过程。当过程被编译或重新编译时,传递给参数的值被评估并用于创建执行计划。然后将该值与执行计划一起存储在计划缓存中。在随后的执行中,使用相同的值和相同的计划。
当您查询的表中的值分布不均匀时会发生什么?如果一个值返回 10 行而另一个值返回 10,000 行或 1000 万行会怎样? 将发生的情况是,第一次运行过程并编译计划时,传入的任何值都与计划一起存储。每次执行时,直到重新编译,都将使用相同的值和计划——不管它是该值的最快计划还是最佳计划。
您可以强制 SQL Server 在每次运行时重新编译存储过程。这样做的好处是每次运行时都会创建最佳查询计划。但是,重新编译是 CPU 密集型操作。对于频繁运行的存储过程,或者在已经受 CPU 资源限制的服务器上,这可能不是一个理想的解决方案。
ALTER PROCEDURE SP_Test
@ProductID INT
WITH RECOMPILE
AS
SELECT OrderID, OrderQty
FROM SalesOrderDetail
WHERE ProductID = @ProductID
【讨论】: