我有一个大约有2400条记录的大型数据库表,当我运行以下功能时:
SELECT (SELECT EXP(SUM(LOG((cast(t1.NAT as float) + ISNULL(cast(t1.Dist as float),0))/cast(t1.NAT as float)))) FROM Test t1 where t1.CODE = t2.CODE AND t1.DATE <= t2.DATE) as Distro FROM Test t2
上面的代码遍历每一行都会导致性能问题。有没有优化的方法?我有什么错误吗?
我使用此函数的表没有按DATE排序的数据,因此无法对其进行排序。
答案 0 :(得分:0)
尝试使用以下JOIN版本的查询
SELECT
Distro=EXP(SUM(LOG( 1 + ISNULL(cast(t1.Dist as float)/cast(t1.NAT as float),0))))
FROM
Test t1
JOIN
Test t2
On t1.CODE = t2.CODE AND t1.DATE <= t2.DATE
如果您的问题是函数,您也可以使用
获得相同的结果DECLARE @result float=1
SELECT
@result=@result*( 1 + ISNULL(cast(t1.Dist as float)/cast(t1.NAT as float),0))
FROM
Test t1
JOIN
Test t2
On t1.CODE = t2.CODE AND t1.DATE <= t2.DATE
SELECT Distro=@result
答案 1 :(得分:0)
是否有一种优化方法?我有什么错误吗?
是的。
这是一个三角形联接。
您说该表有2,400行。为了简单起见,假设只有一个CODE
,那么即使CODE, DATE
上有一个索引,子查询平均也需要处理一半的表(日期最低的外排只会导致一行进行求和,但是到遇到最高日期时,它需要对整个2,400
行进行求和。
因此,总计的总行数将为2,881,200
(2400 * 2401 / 2
)。
您的情况可能不会那么糟-取决于您实际上拥有多少CODE
以及他们分布得如何,但是仍然使用窗口函数会更有效,因为它们可以用一个传递数据。
假设CODE, DATE
是唯一的,则可以使用
SELECT CASE
WHEN Min(Abs(input))
OVER (
PARTITION BY Code ORDER BY DATE) = 0 THEN 0
ELSE CASE
WHEN Sum(Sign(CASE
WHEN input < 0 THEN 1
ELSE 0
END))
OVER (
PARTITION BY Code ORDER BY DATE) % 2 = 1 THEN -1
ELSE 1
END * Exp(Sum(Log(Abs(NULLIF(input, 0))))
OVER (
PARTITION BY Code ORDER BY DATE))
END
FROM Test t1
CROSS APPLY (VALUES (( CAST(t1.NAT AS FLOAT) + ISNULL(CAST(t1.Dist AS FLOAT), 0) ) / CAST(t1.NAT AS FLOAT))) V(input)