2017-09-15 2 views
1

J'ai une table MS SQL avec environ 30M lignes dont j'ai besoin pour mettre à jour un champ basé sur les enregistrements précédents. Voici une mise à jour qui fonctionne, mais il prend une quantité incroyable de temps:Mise à jour de la table de base de données SQL avec des lignes 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 

Voici la pleine 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 
+0

Il n'y a pas de table (ou d'alias) 'AccountTransaction' dans votre requête. – joop

+0

combien de 'Table1Id' distincts y a-t-il dans ces 30M lignes? – SqlZim

+0

Vous mettez à jour 'table1', en utilisant une sous-requête qui somme de table1 mais qui est jointe sur table1id, si table1id est unique et ne fait que référencer la même ligne, pourquoi utilisez-vous une sous-requête? et comment 'b.createddate' peut-il être inférieur à' table1.createddate' ou 'b.date! = table1.date' s'ils font référence à la même ligne? – SqlZim

Répondre

0

Ce qui suit devrait donner de bien meilleures performances et sera en mesure de tirer profit de l'index 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;