SQL Server 交叉应用性能问题
Posted
技术标签:
【中文标题】SQL Server 交叉应用性能问题【英文标题】:SQL Server cross apply performance issue 【发布时间】:2015-08-27 11:22:49 【问题描述】:我的看法如下:
CREATE VIEW V1
AS
SELECT
T1.Col1, F1.Col1, T1.Col2, T2.Col2...
FROM
T1
INNER JOIN
T2 ON T1.Col2 = T2.Col1
CROSS APPLY
UDF(T1.Col1, T2.Col2) F1
内连接返回百万条记录。在这里,在这种情况下,我知道 T1.Col1
的确切值,它将从应用程序传递。
有没有办法重写上面的视图,使交叉应用可以只应用于过滤的记录(基于T1.Col1
值),而不是处理所有记录,然后再过滤?当前视图即使在 20 分钟后也不会返回任何值,而当我将值直接传递给 UDF 时,它会在不到一秒的时间内返回输出。
更新: 以下是 UDF 的结构,我根据以下 cmets 更新了问题:
CREATE FUNCTION [dbo].[UDF](@Col1 INT, @Col2 INT)
RETURNS @TBL TABLE(Col1 int, Col2 int, Col3 VARCHAR(10), Col4 int) AS
DECLARE CURSOR1 CURSOR FOR
SELECT DISTINCT Col1 FROM TBL1 WHERE Col2 = @Col1 AND Col3 = @Col2
OPEN CURSOR1
FETCH NEXT FROM CURSOR1 INTO @Col1
WHILE (@@FETCH_STATUS = 0)
BEGIN
DECLARE CURSOR2 CURSOR FOR...
INSERT INTO @TBLVAR
SELECT * FROM SRCTBL1 WHERE
CLOSE CURSOR2
DEALLOCATE CURSOR2
DECLARE CURSOR3 CURSOR FOR...
INSERT INTO @TBLVAR
SELECT * FROM SRCTBL2 WHERE
CLOSE CURSOR3
DEALLOCATE CURSOR3
DECLARE CURSOR4 CURSOR FOR...
INSERT INTO @TBLVAR
SELECT * FROM SRCTBL3 WHERE
CLOSE CURSOR4
DEALLOCATE CURSOR4
CLOSE CURSOR1
DEALLOCATE CURSOR2
SELECT Col1, Col2, Col3, Col4
【问题讨论】:
你可以将UDF代码合并到查询中sqlblog.com/blogs/hugo_kornelis/archive/2012/05/20/… 如果您可以将视图转换为内联 TVF,您将能够在 T1.Col1 上传递参数和过滤器。但是,我担心UDF本身正在扼杀性能,有没有办法内联它? 恐怕UDF不能内联。它包括 4 个游标,其中一个父游标在其中处理 3 个以上。每个游标都有一个复杂的逻辑。我想,我们需要将完整的 UDF 重写为单独的 UDF。但是,同样在这种情况下,我不确定性能改进。 你真的有 4 个光标在这个东西上?从您发布的骨架看来,您正在使用游标进行插入。更糟糕的是,听起来你有嵌套的游标。只有一种方法可以解决此问题。删除这些光标并使您的函数集基于。我愿意打赌所有这些游标都可以用基于集合的逻辑替换,性能问题也会消失。 @SeanLange Insert 在所有游标中都很常见,其中两个也具有基于条件的更新。它有 7 年历史的遗留脚本根据需要进行了更新,现在看起来像第一次面对我的怪物 :)。我只是想过滤掉连接返回的记录,如果可能的话,这样就至少没有了。对十字架的呼吁适用。我想现在我必须重写整个事情。告诉我一件事,如果我可以使每个光标内联并从父级调用它们,性能会受到严重影响吗? 【参考方案1】:创建内联表值函数而不是视图:
create function fnx (@col1 int)
returns table
as
return (
select
t1.col1, f1.col1, t1.col2, t2.col2...
from
t1
inner join
t2 on t1.col2 = t2.col1
cross apply
udf(t1.col1, t2.col2) f1
where t1.col1 = @col1
)
这样你就可以将参数传递给 t1.col1 上的过滤器了。
【讨论】:
这在这里没有帮助,因为问题是糟糕的 udf。 @sean 部分同意,我已经在 cmets 中声明自己 UDF 正在扼杀性能。但是,如果 UDF 被调用一百万次或一千次,情况就不一样了。所以,它会在一定程度上有所帮助。【参考方案2】:使用公用表表达式:
CREATE VIEW V1
AS
WITH cte(cols...) AS
(
SELECT
T1.Col1, F1.Col1, T1.Col2, T2.Col2...
FROM T1
INNER JOIN T2
ON T1.Col2 = T2.Col1
WHERE T1.col1 = ?
)
SELECT *
FROM cte c
CROSS APPLY UDF(c.Col1, c.Col2) F1
【讨论】:
CTE 只是编写查询的一种更简洁的方式,不会影响执行计划。即不保证 UDF 仅在过滤的结果集上调用。使用临时表或表变量强制结果集。 你如何将参数传递到视图中? 如果这必须是参数化视图,当然它不会起作用,作者应该使用另一个构造。如果作者事先知道 col1 的值,他仍然可以使用它。【参考方案3】:使用内存系统。如果您使用 java 或 .net 编写此代码。将产生更快的结果。
创建一个微服务来缓存结果并提供服务。
参考微服务,***,
https://en.m.wikipedia.org/wiki/Microservices
【讨论】:
我们只管理数据库,应用程序归第三方供应商所有。;暂时,我们不能这样做。以上是关于SQL Server 交叉应用性能问题的主要内容,如果未能解决你的问题,请参考以下文章
在 SQL 中将 XML 文档转换为表格数据集的有效方法,因为随着 xml 的增长,交叉应用 xml 查询的性能呈指数级下降
理解性能的奥秘——应用程序中慢,SSMS中快——SQL Server如何编译存储过程