【问题标题】:SP execution time is extremely slowSP执行时间极慢
【发布时间】:2020-03-02 17:20:29
【问题描述】:

我创建了一个基于线性自调整规则计算金融点差的存储过程,完成计算需要 2 多分钟。

最终值经过多次迭代,以调整和增强它,直到找到最佳优化的最终值。 参数如下:

@input1 = 100000
@input2 = 40
@input3 = 106833


BEGIN
DECLARE @X decimal(22,6) = 0
DECLARE @Y decimal(22,6) = 0.001 
DECLARE @Z decimal(22,6)
DECLARE @r decimal(22,6)
DECLARE @v decimal(22,6) 

SET @v = POWER(1/(1+ (@Y/12)), @input2)
    SET @r = ((@Y/@input2) * input1) / (1-@v) 
    IF (@r < @input3)
        SET @Z = @Y + ABS((@X - @Y)/2)
    ELSE
        SET @Z = @Y - ABS((@X - @Y) /2)

    SET @X = @Y
    SET @Y = @Z 


WHILE (ABS(@r - @input3) > 0.001)
BEGIN
SET @v = POWER(1/(1+ (@Y/12)), @input2)
    SET @r = ((@Y/@input2) * @input1) / (1-@v) 
    IF (@r < @input3)
         SET @Z = @Y + ABS((@X - @Y)/2)
    ELSE
         SET @Z = @Y - ABS((@X - @Y) /2)
    SET @X = @Y
    IF @Y = @Z
    BREAK
    SET @Y = @Z
END

RETURN (CAST(@Y AS decimal(22,6)) * 100)



END

运行时间 = 2 分 20 秒

【问题讨论】:

  • 你用什么参数值调用这个存储过程?
  • @RaduGheorghiu input1 = 100000 input2 = 40 input3 = 106833
  • 你有一个WHILE 循环,你知道它实际上需要执行多少个循环才能中断吗?如果不了解您的实际操作,我们无法为您提供充分的理由。
  • 你为什么在你的数据库上运行这个?存储过程似乎不会访问或操作任何数据。大多数数据库引擎都针对数据访问进行了优化,而不是数学计算。
  • 不知道循环试图实现什么。然而,这更像是一个算法问题,而不是 SQL 问题。您将无法在 SQL Server 上加速此类计算,因为它们是非常简单的操作。您可以尝试更改算法本身以减少运算。

标签: sql sql-server sql-optimization


【解决方案1】:

用 TSQL 编写的存储过程的替代方案可能是用 C# 编写的 SQL CLR 函数。您必须使用 Visual Studio 并创建一个数据库项目。

    public static decimal ConvertTo6(double d)
    {
        return Math.Round(Convert.ToDecimal(d), 6, MidpointRounding.AwayFromZero);
    }

    public static decimal ConvertTo6(decimal d)
    {
        return Math.Round(d, 6, MidpointRounding.AwayFromZero);
    }


    [Microsoft.SqlServer.Server.SqlFunction]
    [return: SqlFacet(Precision = 22, Scale = 6)]
    public static SqlDecimal CalcFinancialSpreading(int input1 = 100000, int input2 = 40, int input3 = 106833)
    {
        decimal x = 0.000000m;
        decimal y = 0.001000m;
        decimal z;
        decimal r;
        decimal v;

        v = ConvertTo6(Math.Pow(1 / (1 + (Convert.ToDouble(y) / 12d)), input2));

        r = ConvertTo6(((y / input2) * input1) / (1 - v));

        if (r < input3)
        {
            z = y + Math.Abs((x - y) / 2);
            z = ConvertTo6(z);
        }
        else
        {
            z = y - Math.Abs((x - y) / 2);
            z = ConvertTo6(z);
        }

        x = y;
        y = z;

        while (Math.Abs(r - input3) > 0.001m)
        {
            v = ConvertTo6((Math.Pow(Convert.ToDouble(1 / (1 + (y / 12))), Convert.ToDouble(input2))));

            r = ((y / input2) * input1) / (1 - v);
            r = ConvertTo6(r);

            if (r < input3)
            {
                z = y + Math.Abs((x - y) / 2);
                z = ConvertTo6(z);
            }
            else
            {
                z = y - Math.Abs((x - y) / 2);
                z = ConvertTo6(z);
            }
            x = y;
            if (y == z) break;
            y = z;
        }

        decimal result = y * 100;

        return new SqlDecimal(result);
    }

作为 C# 代码执行,结果在我的机器上 45 秒内收到,而 TSQL 在 1 分 56 秒内收到。

回复this one@wikiCan 向@wikiCan致敬...

【讨论】:

  • 没关系,但是他的代码的结果,对于SQL中的相同参数,是:4273.320000
  • 你说得对,刚看到……好像是数据类型转换的问题……我去看看
  • 这可能是一个选择!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 2019-08-25
  • 1970-01-01
  • 2016-05-23
  • 1970-01-01
相关资源
最近更新 更多