需要提高查询效率

时间:2013-07-02 13:24:15

标签: performance sql-server-2008 query-performance

我有一个查询,我需要提高效率。

我将其分解为各个部分以查看效率楼层的位置,我目前有几个嵌套Select语句,这些是性能问题吗?

以下是其中一个示例:

SELECT AgreementID,
       DueDate,
       UpdatedAmountDue AS AmountDue,
       COALESCE((SELECT SUM(UpdatedAmountDue)
                 FROM RepaymentBreakdown AS B
                 WHERE CONVERT(datetime, CONVERT(varchar, DueDate, 103), 103) <= 
                       CONVERT(datetime, CONVERT(varchar, R.DueDate, 103), 103)
                 AND B.AgreementID = R.AgreementID),0) AS DueTD,
       RN=ROW_NUMBER() OVER (Partition BY R.AgreementID ORDER BY DueDate)
FROM RepaymentBreakdown AS R

是否有更简洁有效的方法来获取DueTD的数据?

基本上,对于还款计划结果的每一行,我想得到:

AgreementID,
DueDate,
AmountDue,
AmountDueToDate (DueTD)
RowNumber.

我查询的表格结构如下:

AgreementID (int), 
DueDate (datetime),
AmountDue (decimal(9,2)),
UpdatedAmountDue (decimal(9,2))*

* UpdatedAmountDue始终被引用,因为它是移动的数字,AmountDue始终是固定的,作为参考值。

2 个答案:

答案 0 :(得分:1)

所以,我认为你可以通过删除转换来提升性能,就像这样:

select
    AgreementID,
    DueDate,
    UpdatedAmountDue as AmountDue,
    (
        select sum(B.UpdatedAmountDue)
        from RepaymentBreakdown as B
        where B.DueDate <= R.DueDate and B.AgreementID = R.AgreementID
    ) as UpdatedAmountDue 
from RepaymentBreakdown AS R

我知道在SQL Server 2008中计算运行总计的最快方法是使用递归CTE,请参阅我的答案Calculate a Running Total in SqlServer。在您的情况下,查询将是这样的:

create table #t (....., primary key (AgreementID, ord))

insert into #t (AgreementID, DueDate, UpdatedAmountDue, ord)
select AgreementID, DueDate, UpdatedAmountDue, row_number() over (partition by AgreementID, DueDate order by DueDate asc)

;with 
CTE_RunningTotal
as
(
    select T.ord, T.AgreementID, T.DueDate, T.UpdatedAmountDue as T.AmountDue, T.UpdatedAmountDue
    from #t as T
    where T.ord = 1
    union all
    select T.ord, T.AgreementID, T.DueDate, T.UpdatedAmountDue as T.AmountDue, T.UpdatedAmountDue + C.UpdatedAmountDue as UpdatedAmountDue
    from CTE_RunningTotal as C
        inner join #t as T on T.ord = C.ord + 1 and T.AgreementID = C.AgreementID
)
select AgreementID, DueDate, AmountDue, UpdatedAmountDue
from CTE_RunningTotal as C
option (maxrecursion 0)

答案 1 :(得分:-1)

您将日期时间转换为日期有几个问题。

首先,根据您的服务器语言设置,无法保证始终生成正确的结果。如果需要对日期时间值执行字符串操作,请始终使用CONVERT(,, 126)。

但更重要的是,它会阻止索引使用。而是使用CAST(DueDate AS DATE),因为优化器会将转换识别为索引安全。

之后您可能希望在AgreementId,DueDate和INCLUDE UpdatedAmountDue上添加索引,或者更好地使其成为群集。

假设UpdatedAmountDue不能为NULL,你也可以摆脱COALESCE,因为总和总是包含当前行。