Say*_*emi 1 sql-server functions xp-cmdshell sql-server-2017
2 天前,我创建了一个需要INSERT
和的函数,UPDATE
我XP_CMDShell
通过运行脚本启用并执行它。
之后,SQL Server 的SELECT
命令运行速度非常慢。即使SELECT
是INSERT
通过分隔命令运行的非常简单的语句。
我在其他数据库上测试了这种行为,它SELECT
在几分钟后运行得到相同的结果。
此外,我使用 SQL Server 2014 在其他 2 台主机上对其进行了测试,结果相同。
我创建的函数是为了在另一个 select 语句中获取它的值:
ALTER FUNCTION [Prg].[intCheckDelayedProcessProgram]
(
@SalesOrderProductID INT,
@MainProductTreeID INT,
@ProductTreeID INT,
@ProcessId INT,
@additionalDays INT = 2,
@currentDateReverceString VARCHAR(10) = NULL
)
RETURNS INT
AS
BEGIN
--declare @SalesOrderProductID INT = 40957,
-- @MainProductTreeID INT = 93758,
-- @ProductTreeID INT = 93758,
-- @ProcessId INT = 4472,
-- @additionalDays INT = 2,
-- @currentDateReverceString VARCHAR(10) = null -- '30/09/1398'
DECLARE @ProduceDailyProgramProductTree_Id INT, @ProgramQuantity INT, @startDate JalaliDate,
@CurrentDate JalaliDate, @lastDate JalaliDate, @additionalDate JalaliDate, @holiDaysCount INT;
IF(@currentDateReverceString IS NULL OR @currentDateReverceString = '')
SET @CurrentDate = dbo.GetCurrentJalaliDate();
ELSE
SET @CurrentDate = Gnr.RevercePersianDate(@currentDateReverceString);
IF (@additionalDays IS NULL)
SET @additionalDays = 2;
DECLARE @allDelayedItemsCount INT = 0;
BEGIN
DECLARE @sql NVARCHAR(4000), @cmd VARCHAR(4000);
DECLARE cursor_pdppt CURSOR
FOR SELECT pdppt.ID, pdppt.ProgramQuantity, pdppt.[Date] FROM Prg.ProduceDailyProgramProductTree pdppt
WHERE pdppt.SalesOrderProductID = @SalesOrderProductID
AND pdppt.MainProductTreeID = @MainProductTreeID
AND pdppt.ProductTreeID = @ProductTreeID
AND pdppt.Process = @ProcessId
AND ISNULL(pdppt.IsDelayed, 0) = 0
OPEN cursor_pdppt;
FETCH NEXT FROM cursor_pdppt INTO @ProduceDailyProgramProductTree_Id, @ProgramQuantity, @startDate;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @lastDate = Gnr.RevercePersianDate([Prg].[intGetLastDateForDelayedProcessProgram](@startDate, @additionalDays, @CurrentDate, 1));
IF (@CurrentDate.GetDate() > @lastDate.GetDate())
BEGIN
IF ((SELECT COUNT(*) FROM Prg.ProduceDailyOperation pdo WHERE pdo.ProduceDailyProgramProductTreeID = @ProduceDailyProgramProductTree_Id AND pdo.Process = @ProcessId
AND pdo.[Date].GetDate() > @lastDate.GetDate()) = 0)
BEGIN
SET @allDelayedItemsCount = @allDelayedItemsCount + @ProgramQuantity;
END
ELSE
BEGIN
SET @allDelayedItemsCount = @allDelayedItemsCount +
(@ProgramQuantity -
(SELECT SUM(pdo.ProducedQuantity) FROM Prg.ProduceDailyOperation pdo
WHERE pdo.ProduceDailyProgramProductTreeID = @ProduceDailyProgramProductTree_Id
AND pdo.Process = @ProcessId AND pdo.[Date].GetDate() <= @lastDate.GetDate()));
END;
SELECT @sql = 'UPDATE [Prg].[ProduceDailyProgramProductTree] SET [IsDelayed] = 1 WHERE ID = ' + CONVERT(VARCHAR(10), @ProduceDailyProgramProductTree_Id);
SELECT @cmd = 'sqlcmd -S ' + @@SERVERNAME + ' -d ' + DB_NAME() + ' -Q "' + @sql + '"'
EXEC MASTER..XP_CMDSHELL @cmd , 'no_output'
END;
FETCH NEXT FROM cursor_pdppt INTO @ProduceDailyProgramProductTree_Id, @ProgramQuantity, @startDate;
END;
CLOSE cursor_pdppt;
IF (@allDelayedItemsCount > 0)
BEGIN
IF (EXISTS(SELECT 1 FROM Prg.ProduceDailyProgramProductTreeDelayed pdppt
WHERE pdppt.SalesOrderProductID = @SalesOrderProductID
AND pdppt.MainProductTreeID = @MainProductTreeID
AND pdppt.ProductTreeID = @ProductTreeID
AND pdppt.Process = @ProcessId))
BEGIN
SELECT @allDelayedItemsCount = @allDelayedItemsCount
+ (SELECT pdpptd.DelayedQuantity FROM Prg.ProduceDailyProgramProductTreeDelayed pdpptd
WHERE pdpptd.SalesOrderProductID = @SalesOrderProductID
AND pdpptd.MainProductTreeID = @MainProductTreeID
AND pdpptd.ProductTreeID = @ProductTreeID
AND pdpptd.Process = @ProcessId
AND ISNULL(pdpptd.Active, 0) = 1
AND ISNULL(pdpptd.IsDeleted, 0) = 0);
SELECT @sql = 'UPDATE [Prg].[ProduceDailyProgramProductTreeDelayed] SET DelayedQuantity = '
+ CONVERT(VARCHAR(10), @allDelayedItemsCount) + 'WHERE SalesOrderProductID = '
+ CONVERT(VARCHAR(10), @SalesOrderProductID) + 'AND MainProductTreeID = '
+ CONVERT(VARCHAR(10), @MainProductTreeID) + 'AND ProductTreeID = '
+ CONVERT(VARCHAR(10), @ProductTreeID) + 'AND Process = '
+ CONVERT(VARCHAR(10), @ProcessId) +';';
END
ELSE
BEGIN
SELECT @sql = 'INSERT INTO [Prg].[ProduceDailyProgramProductTreeDelayed] (SalesOrderProductID, MainProductTreeID, Process, ProductTreeID, DelayedQuantity, Active, IsDeleted) VALUES ('
+ CONVERT(VARCHAR(10), @SalesOrderProductID) + ', '
+ CONVERT(VARCHAR(10), @MainProductTreeID) + ', '
+ CONVERT(VARCHAR(10), @ProcessId) + ', '
+ CONVERT(VARCHAR(10), @ProductTreeID) + ', '
+ CONVERT(VARCHAR(10), @allDelayedItemsCount) + ', ''1'', ''0'')';
END;
SELECT @cmd = 'sqlcmd -S ' + @@SERVERNAME + ' -d ' + DB_NAME() + ' -Q "' + @sql + '"'
EXEC MASTER..XP_CMDSHELL @cmd , 'no_output'
END
ELSE
IF(EXISTS(SELECT 1 FROM Prg.ProduceDailyProgramProductTreeDelayed pdpptd
WHERE pdpptd.SalesOrderProductID = @SalesOrderProductID
AND pdpptd.MainProductTreeID = @MainProductTreeID
AND pdpptd.ProductTreeID = @ProductTreeID
AND pdpptd.Process = @ProcessId
AND ISNULL(pdpptd.Active, 0) = 1
AND ISNULL(pdpptd.IsDeleted, 0) = 0))
BEGIN
SELECT @allDelayedItemsCount =
(SELECT pdpptd.DelayedQuantity FROM Prg.ProduceDailyProgramProductTreeDelayed pdpptd
WHERE pdpptd.SalesOrderProductID = @SalesOrderProductID
AND pdpptd.MainProductTreeID = @MainProductTreeID
AND pdpptd.ProductTreeID = @ProductTreeID
AND pdpptd.Process = @ProcessId
AND ISNULL(pdpptd.Active, 0) = 1
AND ISNULL(pdpptd.IsDeleted, 0) = 0);
END;
END;
RETURN @allDelayedItemsCount;
END
Run Code Online (Sandbox Code Playgroud)
JalaliDate
是用户定义的类型,用于通过程序集保存波斯语日期时间。
Gnr.RevercePersianDate
函数将字符串波斯日期转换为 JalaliDate。
[Prg].[intGetLastDateForDelayedProcessProgram]
我认为没有问题的其他按假期计算指定日期的函数。
更新 1
我通过内联声明和设置测试值传递参数值来测试功能代码。然后,使用Sql Server Profiler 来检查函数的脚本,看到SET @CurrentDate = dbo.GetCurrentJalaliDate()
使用Assembly 函数的脚本停在这一行。执行运行没有任何错误并且没有响应!!注意:我测试SELECT dbo.GetCurrentJalaliDate()
响应非常快,没有错误!
更新 2
我在一个复杂的语句[Prg].[intCheckDelayedProcessProgram]
内部SP
和内部调用函数SELECT
,不能调用SP
in select
,所以我的解决方案是定义函数。代码在本地服务器上运行,与所有数据和其他 SP 和函数一起运行。如果有替代方法可以CURSOR
帮助我用它重写函数。
归档时间: |
|
查看次数: |
2729 次 |
最近记录: |