SQL Server 2014存储过程速度较慢

SQL Server 2014存储过程速度较慢,sql,sql-server,loops,stored-procedures,Sql,Sql Server,Loops,Stored Procedures,我有一个存储过程来计算收据,直到今天我还没有遇到任何问题,直到我不得不在一个有100000行的数据库中执行它。它太慢了,至少运行了3个小时,但还没有完成 有没有办法优化这一点 代码如下: Declare @sousTotal numeric(16,2), @TotalTx1 numeric(18,4), @TotalTx2 numeric(18,4), @TotalTx3 numeric(18,4), @Taux1 numeric(18,4), @Taux

我有一个存储过程来计算收据,直到今天我还没有遇到任何问题,直到我不得不在一个有100000行的数据库中执行它。它太慢了,至少运行了3个小时,但还没有完成

有没有办法优化这一点

代码如下:

Declare @sousTotal numeric(16,2),
    @TotalTx1 numeric(18,4),
    @TotalTx2 numeric(18,4),
    @TotalTx3 numeric(18,4),
    @Taux1 numeric(18,4),
    @Taux2 numeric(18,4),
    @Taux3 numeric(18,4),
    @totalEscompte numeric(16,2),
    @totalFacture numeric(16,2),
    @MontantPaiement numeric(16,2)
Begin
BEGIN TRANSACTION;

BEGIN TRY

    select top 1 @Taux1 = TauxTaxe1,@Taux2 = TauxTaxe2  ,@Taux3 = TauxTaxe3 from tbFactureEntete where ID = @IdFacture and IDCompagnie = @IDCie 
      select @sousTotal =sum(sousTotal),@TotalTx1 = sum(totalTx1),@TotalTx2 = sum(totalTx2),@TotalTx3 = sum(totalTx3),
    @totalEscompte = sum(totalEscompte ),@totalFacture = sum(totalFacture)    from(
    select  SUM(isnull(A.TotalLigne,0)) AS sousTotal   ,
    case taxe1 when  0 then 0
                 when  1 then SUM(isnull(A.TotalLigne,0)) * @Taux1 / 100
                 end AS totalTx1,
    case taxe2 when 0 then 0
                 when 1 then SUM(isnull(A.TotalLigne,0)) * @Taux2 / 100
                 end AS totalTx2,
    case taxe3 when 0 then 0
                 when 1 then SUM(isnull(A.TotalLigne,0)) * @Taux3 / 100
                 end AS totalTx3,                                
     sum(isnull(MontantEscompte,0))  as totalEscompte ,sum(isnull(TotalLigne,0)) + case taxe1 when  0 then 0
                 when  1 then SUM(isnull(A.TotalLigne,0)) * @Taux1 / 100
                 end +
    case taxe2 when 0 then 0
                 when 1 then SUM(isnull(A.TotalLigne,0)) * @Taux2 / 100
                 end +
    case taxe3 when 0 then 0
                 when 1 then SUM(isnull(A.TotalLigne,0)) * @Taux3 / 100
                 end as totalFacture
    from tbfactureDetail A
    where IdFacture = @IdFacture  and A.IDCompagnie = @IDCie 
    group by taxe1,taxe2,taxe3) as AA

    select @MontantPaiement = SUM(MontantPaiement) from tbFacturePaiement 
    where IdFacture = @IdFacture 

    update tbFactureEntete 
    set Total_AvantTaxe = @sousTotal,
        totalTaxe1 = @TotalTx1, 
        totalTaxe2 = @TotalTx2,
        totalTaxe3 = @TotalTx3, 
        TotalEscompte = isnull(@totalEscompte,0), 
        TotalFacture = isnull(@totalFacture,0),
        TotalPaiementCR = isnull(@MontantPaiement,0) ,
        TotalSolde = isnull(@totalFacture,0) - isnull(@MontantPaiement,0) 
    where ID = @IdFacture and IDCompagnie = @IDCie




END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_PROCEDURE() AS ErrorProcedure
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
return
End

再次感谢

根据表TBFactoryDetail中IdFacture和IDCompagnie的基数,如果缺少索引,则索引将有助于解决问题

如果存在许多不同的IdCompagnie值,则许多不同的IDFacture值

CREATE NONCLUSTERED INDEX IX_NewIdx_Name
  ON tbfactureDetail (IdFacture,IdCompagnie)
如果每个IDfacture的idcompagni相对较少,则可以使用Include

CREATE NONCLUSTERED INDEX IX_NewIdx_Name
ON tbfactureDetail (IdFacture)
INCLUDE (IdCompagnie)
我认为这在数学上是相同的,对于代码来说更为优化

BEGIN TRY

select top 1 @Taux1 = TauxTaxe1
,            @Taux2 = TauxTaxe2
,            @Taux3 = TauxTaxe3
from tbFactureEntete
where ID = @IdFacture and IDCompagnie = @IDCie


select @sousTotal =sum(isnull(A.TotalLigne,0))
,      @TotalTx1 = sum(taxe1 * isnull(A.TotalLigne,0) * @Taux1 / 100)
,      @TotalTx2 = sum(taxe2 * isnull(A.TotalLigne,0) * @Taux2 / 100)
,      @TotalTx3 = sum(taxe3 * isnull(A.TotalLigne,0) * @Taux3 / 100)
,      @totalEscompte = sum(isnull(MontantEscompte,0) )
,      @totalFacture = 
 sum(taxe1 * isnull(A.TotalLigne,0) * @Taux1 / 100) +
 sum(taxe2 * isnull(A.TotalLigne,0) * @Taux2 / 100) +
 sum(taxe3 * isnull(A.TotalLigne,0) * @Taux3 / 100)
from tbfactureDetail A
where IdFacture = @IdFacture and A.IDCompagnie = @IDCie


select @MontantPaiement = SUM(MontantPaiement)
from tbFacturePaiement
where IdFacture = @IdFacture

update tbFactureEntete
set Total_AvantTaxe = @sousTotal
,   totalTaxe1      = @TotalTx1
,   totalTaxe2      = @TotalTx2
,   totalTaxe3      = @TotalTx3
,   TotalEscompte   = isnull(@totalEscompte,0)
,   TotalFacture    = isnull(@totalFacture,0)
,   TotalPaiementCR = isnull(@MontantPaiement,0)
,   TotalSolde      = isnull(@totalFacture,0) - isnull(@MontantPaiement,0)
where ID = @IdFacture and IDCompagnie = @IDCie
END TRY

您是否尝试使用运行查询?是否检查了锁?表结构是什么?你的表上有什么索引?这里也有一些逻辑问题。前1名,无订购人。似乎还存在一些潜在的正常化问题。当您开始看到重复组(TauxTaxe1、TauxTaxe2、TauxTaxe3)时,这是一个红旗,表明该表可能违反了1NF。@SeanLange不要真的不同意您的第一点,但如果任何ID/IDCompagnie组合只有一个唯一的Taxe 1、2、3组合,则使用TOP是有意义的,而无需订购人。要达到同一个目标,总比不一样好。如果是这样的话,你的第二点就更有道理了。