问题
I created a stored procedure that calculates a financial spreading based on a linear self adjusting rule and it takes more than 2 minutes to finish the calculations.
The final value goes through multiple iterations in order to adjust and enhance it till finding the optimal optimized final value. The parameters are the following:
@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
run time = 2 mins and 20 seconds
回答1:
An alternative to your stored procedure written in TSQL might be a SQL CLR function written in C#. You have to use Visual Studio and create a Database Project.
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);
}
Executed as C# code the result is received in 45 seconds on my machine vs. TSQL in 1 Min 56 seconds.
Kudos to @wikiCan by answering this one...
来源:https://stackoverflow.com/questions/58726514/sp-execution-time-is-extremely-slow