首页 > 解决方案 > 为什么运行过程非常非常慢?

问题描述

ALTER procedure [dbo].[PSI]
    @`PartNo` nvarchar (50),
    @Customer nvarchar (50),
    @Date1 Date,
    @Date2 Date
AS

Begin
      declare @Qty int,
                  @i int,
                  @max_i int,
                  @b nvarchar(15),
                  @j int,
                  @max_j int

      IF EXISTS (SELECT * FROM tempdb.sys.sysobjects WHERE name like '#Test%')
            DROP TABLE #Test


      create table #Test(
            IDX         int identity(1,1), 
            Item      nvarchar(50)
          )   

      insert into #Test(Item) select distinct Name_Customer from Master_Products where Name like '%' + @PartNo + '%' and Customer like '%' + @Customer + '%'

      set @i=0
      set @max_i=DATEDIFF(day, @Date1, @Date2)

      Set @Qty=2
      DECLARE @SQL NVARCHAR(200)
      DECLARE @SQL1 NVARCHAR(200)
     DECLARE @x int
     DECLARE @y int
     DECLARE @z int
      while @i<=@max_i

      begin
        set @j=1
        set @max_j=(SELECT MAX(IDX) FROM #Test)
     Set @b=Dateadd(day,@i,@Date1)
     Set @SQL='alter table #Test
    add [' + cast(@b AS NVARCHAR(10)) + ']' + + 'int'
    exec [sp_executesql] @sql  WITH RECOMPILE 
    while @j<=@max_j
    Begin
    Set @x=(SELECT SUM(Qty) 
    FROM Planning_Stock_Balance 
    WHERE DateAjust<=@b and (select top 1 name from Master_Products where Name=Planning_Stock_Balance.PartNo) =(select item from #Test where IDX=@j)) 
    Set @y=(SELECT SUM(OKQTY) FROM Injection_Daily_Result WHERE PRODATE<=@b and (select top 1 name from Master_Products where Name=Injection_Daily_Result.PartNo)=(select item from #Test where IDX=@j))
    Set @z=(SELECT SUM(Qty) FROM Sales_PO WHERE DeliDate<=@b and (select top 1 name from Master_Products where Name=Sales_PO.ItemCode)=(select item from #Test where IDX=@j))

    Set @SQL1 ='update #Test 
    set [' + cast(@b AS NVARCHAR(10)) + ']=' + CAST(isnull(@x,0)+isnull(@y,0)-isnull(@z,0)
     AS NVARCHAR(10))
    + ' where idx =' + cast(@j as NVARCHAR(10)) +''

    exec [sp_executesql] @sql1  WITH RECOMPILE 

    SET @j=@j+1          
    end

    SET @i=@i+1          
    end

     Select * from #Test
     OPTION ( OPTIMIZE FOR UNKNOWN )
    -- where Item like '%' + @PartNo + '%' and (select top 1 Customer from Master_Products where Name=Item) like '%' + @Customer +'%'
     IF OBJECT_ID(N'tempdb..#Test', N'U') IS NOT NULL  
     drop table #Test 
End

标签: sqlsql-server

解决方案


这段代码非常晦涩,不清楚您要实现什么。

一些提示:

使用有意义的变量名,例如@stock_balance,而不是变量名,如@x等。这种命名约定@y的缺乏使得代码难以遵循,不仅对局外人而且对你也是如此。

通常,在设计合理的关系数据库中,您将通过ID或一些唯一键而不是像您在这里所做的那样按名称处理客户:

and Customer like '%' + @Customer + '%'

这是非常不安全的:想想如果您有多个同名或相似名称的客户会发生什么。

更不用说这样的where子句将不能使用索引,假设你甚至有一个。

如果您在运行过程时显示执行计划,它应该会显示需要很长时间的部分(或者您可以简单地print getdate()在代码中添加一些部分)。

动态 SQL 不仅危险而且很少有正当理由。必须有更好的方法来做到这一点。

您在过程中使用了许多表,其结构未知。您应该做的是发布这些表的结构,显示一些示例数据,并提供预期结果的示例。


推荐阅读