查询在第二次执行中工作正常,但在第一次执行中花费太多时间

时间:2019-09-13 10:04:55

标签: sql sql-server

我正在编写一个查询,该查询接受逗号分隔的字符串并计算交易总额。这样做的结果不错,但是第一次尝试花费太多时间。我了解它的需要调整,但没有找到确切的原因可以指出我的查询出了什么问题。

Declare @IDs nvarchar(max)='1,4,5,6,8,9,43,183'

SELECT isnull(isnull(SUM(FT.PaidAmt),0) - isnull(SUM(CT.PaidAmt),0),0) [Amount], convert(char(10),FT.TranDate,126) [Date]
from FeeTransaction FT
Inner Join (
    Select max(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt]
    From Patient_Account P
    Group By P.TranMainId
) PA ON FT.Id = PA.TranMainId
Inner Join Patient_Account XP ON PA.Id = XP.Id
Inner Join Master_Fee MF ON XP.FeeId = MF.Id
INNER Join Master_Patient MP ON FT.PID = MP.Id
Inner Join Master_FeeType TY ON MF.FeeTypeId = TY.Id
Left JOIN FeeTransaction CT on FT.TransactionId = CT.TransactionId AND CT.TranDate between '2019'+'08'+'01' and '2019'+'08'+'31' and CT.[Status] <> 'A' AND isnull(CT.IsCancel,0) = 1
Where convert(nvarchar,FT.TranDate,112) between '2019'+'08'+'01' and '2019'+'08'+'31' AND FT.[Status] = 'A' AND XP.FeeId in (SELECT val FROM dbo.f_split(@IDs, ','))
AND isnull(FT.IsCancel,0) = 0 AND FT.EntryBy = 'rajan'
Group By convert(char(10),FT.TranDate,126)

3 个答案:

答案 0 :(得分:0)

我将查询改一下:

select coalesce(SUM(FT.PaidAmt), 0) - coalesce(SUM(CT.PaidAmt), 0)as [Amount],
       convert(char(10),FT.TranDate,126) [Date]
from FeeTransaction FT join
     (select xp.*,
             coalesce(sum(p.amttopay) over (TranMainId), 0) as amt
      from Patient_Account XP ON PA.Id = XP.Id
     ) xp join
     Master_Fee MF 
     on XP.FeeId = MF.Id join
     Master_Patient MP 
     on FT.PID = MP.Id join
     Master_FeeType TY 
     on MF.FeeTypeId = TY.Id left join
     FeeTransaction CT
     on FT.TransactionId = CT.TransactionId and
        CT.TranDate between '20190801' and '20190831' and
        CT.[Status] <> 'A' and
        CT.IsCanel = 1
where FT.TranDate >= '20190801' and and
      FT.TranDate < '20190901' 
      FT.[Status] = 'A' AND
      XP.FeeId in (SELECT val FROM dbo.f_split(@IDs, ',')) and
      (FT.IsCancel = 0 or FT.IsCancel IS NULL) and
      FT.EntryBy = 'rajan'
Group By convert(char(10), FT.TranDate, 126)

然后,对于此版本,您专门在FeeTransaction(EntryBy, Status, TranDate, Cancel)上建立了索引。

请注意以下更改:

  • 您不需要将Patient_Account聚合为子查询。窗口功能非常方便。
  • 您的日期比较排除了索引的使用。将日期转换为字符串通常是一种不好的做法。
  • 您过度使用了isnull()
  • 我假定已为连接准备好了适当的索引。

答案 1 :(得分:0)

我将使用STRING_SPLIT和Common Table Expressions并取消日期转换:

Declare @IDs nvarchar(max)='1,4,5,6,8,9,43,183'

;WITH CTE_ID AS
(
   SELECT value AS ID FROM STRING_SPLIT(@IDs, ',');)
),
MaxPatient 
AS
(
    SELECT MAX(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt]
    From Patient_Account P
    Group By P.TranMainId
)
SELECT  isnull(isnull(SUM(FT.PaidAmt),0) - isnull(SUM(CT.PaidAmt),0),0) As [Amount], 
        convert(char(10),FT.TranDate,126) [Date]
FROM FeeTransaction FT
INNER JOIN MaxPatient PA 
           ON FT.Id = PA.TranMainId
INNER JOIN Patient_Account XP 
           ON PA.Id = XP.Id
INNER JOIN Master_Fee MF 
           ON XP.FeeId = MF.Id
INNER Join Master_Patient MP 
           ON FT.PID = MP.Id
INNER JOIN Master_FeeType TY 
           ON MF.FeeTypeId = TY.Id
INNER JOIN CTE_ID
    ON XP.FeeId = CTE_ID.ID
LEFT JOIN FeeTransaction CT 
           ON FT.TransactionId = CT.TransactionId AND 
              CT.TranDate >= '20190801' AND CT.TranDate < '20190831' AND
              CT.[Status] <> 'A' AND isnull(CT.IsCancel,0) = 1
WHERE FT.TranDate >= '20190801' and FT.TranDate < '20190831' AND 
      FT.[Status] = 'A' AND 
      ISNULL(FT.IsCancel,0) = 0 AND 
      FT.EntryBy = 'rajan'
GROUP BY CAST(FT.TranDate AS Date)

答案 2 :(得分:0)

不仅查询速度很慢,而且显示的输出不正确。

i)如果您没有在resultset中使用Select max(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt] From Patient_Account P Group By P.TranMainId 的任何列,那么为什么要编写此子查询?

<>

ii)避免使用Status。因此'A'必须为'I'CT.[Status] = 'I'      所以改写为isnull(CT.IsCancel,0) = 1

iii)TranDate的正确数据类型是什么?请勿在where条件下使用函数。

iv)不需要CT.IsCancel = 1,而是写Declare @IDs nvarchar(max)='1,4,5,6,8,9,43,183' create table #temp(id int) insert into #temp(id) SELECT val FROM dbo.f_split(@IDs, ',') declare @FromDate Datetime='2019-08-01' declare @toDate Datetime='2019-08-31' -- mention all column of FeeTransaction that you need in this query along with correct data type -- Store TranDate in this manner convert(char(10),FT.TranDate,126) in this table create table #Transaction() select * from FeeTransaction FT where FT.TranDate>=@FromDate and FT.TranDate<@toDate and exists(select 1 from #temp t where t .val=ft.id) -- mention all column of Patient_Account that you need in this query along with correct data type create table #Patient_Account() Select max(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt] From Patient_Account P where exists(select 1 from #Transaction T where t.id=PA.TranMainId) Group By P.TranMainId SELECT isnull(isnull(SUM(FT.PaidAmt),0) - isnull(SUM(CT.PaidAmt),0),0) [Amount], TranDate [Date] from #Transaction FT Inner Join #Patient_Account XP ON PA.Id = XP.Id Inner Join Master_Fee MF ON XP.FeeId = MF.Id INNER Join Master_Patient MP ON FT.PID = MP.Id Inner Join Master_FeeType TY ON MF.FeeTypeId = TY.Id Left JOIN #Transaction CT on FT.TransactionId = CT.TransactionId AND CT.[Status] = 'I' AND CT.IsCancel = 1 Where AND FT.[Status] = 'A' AND XP.FeeId in (SELECT val FROM #temp t) AND FT.IsCancel = 0 AND FT.EntryBy = 'rajan' Group By TranDate

所以我的脚本只是大纲,但很容易理解。

{{1}}