Performance SQL Server:相同的存储过程在1dB上运行正常,但在2dB上运行缓慢

Performance SQL Server:相同的存储过程在1dB上运行正常,但在2dB上运行缓慢,performance,stored-procedures,sql-server-2012,Performance,Stored Procedures,Sql Server 2012,我在两个数据库中有相同的存储过程。在第一个数据库中工作正常,但在另一个数据库中需要10秒以上。我把它提取出来进行查询,得到了类似的东西。这是我的问题。任何专家的帮助都将不胜感激 SELECT dbo.Installment.Id, dbo.Installment.InstallmentNo, dbo.Installment.InstallmentOrder, dbo.Installment.Amount, dbo.Installment.DueDate, d

我在两个数据库中有相同的存储过程。在第一个数据库中工作正常,但在另一个数据库中需要10秒以上。我把它提取出来进行查询,得到了类似的东西。这是我的问题。任何专家的帮助都将不胜感激

SELECT     
    dbo.Installment.Id, dbo.Installment.InstallmentNo, 
    dbo.Installment.InstallmentOrder, dbo.Installment.Amount, 
    dbo.Installment.DueDate, dbo.Installment.AmountPaid, 
    dbo.Installment.PaidOn, dbo.Installment.PlotId, 
    dbo.Installment.SurchargePaid, dbo.Installment.surchargePaidOn, 
    dbo.Installment.PartialInstallmentId, dbo.Installment.Is_Lumpsum, 
    dbo.Plot.PlotNo, dbo.Plot.PhaseId, dbo.Plot.InstallmentPlanId, 
    dbo.InstallmentPlan.StartDate, dbo.InstallmentPlan.InstSurchargeDueMonth, 
    dbo.GetInstPlanDueDate(dbo.InstallmentPlan.StartDate, 
                           ISNULL(dbo.Installment.DueDate, GETDATE()), 
                           ISNULL(dbo.Installment.PaidOn, GETDATE()), 
                           dbo.InstallmentPlan.InstSurchargeDueMonth, 
                           dbo.Installment.InstallmentOrder, 
                           ISNULL(dbo.Installment.Is_Lumpsum, 0), 
                           InstallmentStartDate.DueDate, dbo.Installment.PlotId) AS Sutcharge_Start_From, 
    dbo.CalculateSurchargableDays(dbo.Installment.DueDate, 
                                  ISNULL(dbo.Installment.PaidOn, GETDATE()), 
                                  dbo.GetInstPlanDueDate(dbo.InstallmentPlan.StartDate, 
                                      ISNULL(dbo.Installment.DueDate, GETDATE()), 
                                      ISNULL(dbo.Installment.PaidOn, GETDATE()), 
                                      dbo.InstallmentPlan.InstSurchargeDueMonth, 
                                      dbo.Installment.InstallmentOrder, 
                                      ISNULL(dbo.Installment.Is_Lumpsum, 0), 
                                      InstallmentStartDate.DueDate, 
                                      dbo.Installment.PlotId), 
                        dbo.Installment.InstallmentOrder) AS days, 
                      case isnull(dbo.Installment.SurchargePaid,0) when 0 then
                  dbo.CalculateSurchargableDays(dbo.Installment.DueDate, ISNULL(dbo.Installment.PaidOn, GETDATE()), 
                  dbo.GetInstPlanDueDate(dbo.InstallmentPlan.StartDate, ISNULL(dbo.Installment.DueDate, GETDATE()), isnull(dbo.Installment.PaidOn,getdate()), dbo.InstallmentPlan.InstSurchargeDueMonth, dbo.Installment.InstallmentOrder, 
                  ISNULL(dbo.Installment.Is_Lumpsum, 0), InstallmentStartDate.DueDate, dbo.Installment.PlotId),dbo.Installment.InstallmentOrder) * (ISNULL(dbo.Installment.Amount, 0) * (dbo.InstallmentPlan.InstSurchargePercentage / 365 / 100))
                  else
                    isnull(dbo.Installment.Surcharge,0)
                  end
                  AS surcharge_calculated, case isnull(dbo.Installment.AmountPaid,0) when 0 then 0 else 0 end as Payment_Status,dbo.Installment.InstallmentOrder%6 as t


FROM           
    dbo.Installment 
INNER JOIN
    dbo.Plot ON dbo.Installment.PlotId = dbo.Plot.Id 
INNER JOIN
    dbo.InstallmentPlan ON dbo.Plot.InstallmentPlanId = dbo.InstallmentPlan.Id 
INNER JOIN
    (SELECT PlotId, MIN(DueDate) AS DueDate
     FROM dbo.Installment
     GROUP BY InstallmentOrder, PlotId
     HAVING (InstallmentOrder = 0)) AS InstallmentStartDate ON InstallmentStartDate.plotid = dbo.installment.plotid
WHERE     
    ((dbo.Plot.InstallmentPlanId > 0))
统计IO的一个工作正常

(5089 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Installment'. Scan count 2, logical reads 109228, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Plot'. Scan count 1, logical reads 218, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'InstallmentPlan'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
慢一点:

(64577 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Installment'. Scan count 2, logical reads 2842959, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Plot'. Scan count 1, logical reads 272, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'InstallmentPlan'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)
我的实际执行计划在这里


这里的问题是,两个数据库之间的数据量不同,虽然查询在较小的数据库上执行得可以接受,但在较大的数据库上执行得很慢

查看这两个执行计划,我们可以看到优化器必须执行完整的聚集索引扫描来执行连接,因为没有合适的索引。对我来说,主要的问题似乎是对
分期
表执行了2316次CI扫描,导致读取5583876行(针对较大的数据库)。相同的操作在较小数据库的查询中读取395505行。您的
统计IO
输出告诉我们这是2733731次读取差异。这是8KB的页面,因此这是一个2.6GB-相当重要,可能是执行时间变化的罪魁祸首

您可以通过在
分期付款
表上创建非聚集索引来消除此扫描:

CREATE INDEX IX_Installment_InstallmentOrder ON Installment
(
    InstallmentOrder
)
INCLUDES
(
    DueDate,
    PlotId
)
这将减少读取次数并加快查询速度

即使这样做有效,我怀疑如果由于
SELECT
语句中的两个标量函数-
GetInstPlanDueDate
calculatesourceabledays
而导致数据集继续增长,您将来可能会遇到更多问题

标量函数是逐行处理的,不能很好地扩展到更大的数据集,因此将来可能需要删除它们并用基于集合的方法(表值函数、联接、视图、派生表等)替换


话虽如此,如果SQL Server 2019中的标量函数是可内联的,则该函数的性能已得到改善

执行时间的差异可以通过不同的数据大小、表索引、数据库配置的差异来解释,服务器或其他服务器的差异我使用的是SQL server 2012-Microsoft SQL server管理研究两个数据库中所有表中的数据是否相同?数据库在同一个实例上吗?数据不同,但表、列是相同的,这可能就是问题所在。优化器将在不同的数据集上表现出不同的行为。我假设运行时间较长的查询的表中有更多的数据?您需要为两个数据库上的查询提供(实际的)执行计划,以便能够进一步调查。您可以将它们粘贴到工作正常的DB和懒惰的DB