使用30M行更新SQL数据库表

时间:2017-09-15 12:17:13

标签: sql sql-server sql-server-2016

我有一个MS SQL表,大约有30M行,我需要根据以前的记录更新字段。这是一个有效的更新,但需要花费大量时间:

UPDATE AccountTransaction
SET EndingBalance = (SELECT COALESCE(SUM(b.amount), 0)
FROM AccountTransaction AS b
WHERE b.AccountId = AccountTransaction.AccountId 
and b.Date <= AccountTransaction.Date 
and (b.Date != AccountTransaction.Date 
     or b.CreatedDate < AccountTransaction.CreatedDate)) 
+ Amount

这是完整的DDL:

CREATE TABLE [dbo].[AccountTransaction](
    [AccountTransactionId] [uniqueidentifier] NOT NULL,
    [AccountId] [uniqueidentifier] NOT NULL,
    [Amount] [decimal](16, 2) NOT NULL,
    [EndingBalance] [decimal](16, 2) NOT NULL,
    [Date] [date] NOT NULL,
    [CreatedDate] [datetime2](3) NOT NULL,
 CONSTRAINT [PkAccountTransaction] PRIMARY KEY CLUSTERED 
(
    [AccountTransactionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE NONCLUSTERED INDEX [IxAccountTransaction_AccountId_Date_CreatedDate] ON [dbo].[AccountTransaction]
(
    [AccountId] ASC,
    [Date] ASC,
    [CreatedDate] ASC
)
INCLUDE ([AccountTransactionId],
    [Amount],
    [EndingBalance]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IxAccountTransaction_AccountId] ON [dbo].[AccountTransaction]
(
    [AccountId] ASC
)
INCLUDE ([AccountTransactionId],
    [Amount],
    [EndingBalance],
    [Date],
    [CreatedDate]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

1 个答案:

答案 0 :(得分:0)

以下应该会产生更好的性能,并且能够利用IxAccountTransaction_AccountId_Date_CreatedDate索引......

WITH 
    cte_Runningtotal AS (
    SELECT 
        at1.EndingBalance, 
        NewEB = SUM(at1.Amount) OVER (PARTITION BY at1.AccountId ORDER BY at1.[Date] ROWS UNBOUNDED PRECEDING)
    FROM
        dbo.AccountTransaction at1
    )
UPDATE rt SET 
    rt.EndingBalance = rt.NewEB
FROM
    cte_Runningtotal rt;