Производительность удаления и слияния сервера SQL

У меня есть таблица, содержащая некоторые данные о покупке / продаже, в которых содержится около 8 миллионов записей:

CREATE TABLE [dbo].[Transactions](
[id] [int] IDENTITY(1,1) NOT NULL,
[itemId] [bigint] NOT NULL,
[dt] [datetime] NOT NULL,
[count] [int] NOT NULL,
[price] [float] NOT NULL,
[platform] [char](1) NOT NULL
) ON [PRIMARY]

Каждые X mins моя программа получает новые транзакции для каждого itemId, и мне нужно его обновить. Мое первое решение - двухэтапное DELETE + INSERT:

delete from Transactions where platform=@platform and itemid=@itemid
insert into Transactions (platform,itemid,dt,count,price) values (@platform,@itemid,@dt,@count,@price)
[...]
insert into Transactions (platform,itemid,dt,count,price) values (@platform,@itemid,@dt,@count,@price)

Проблема в том, что это состояние DELETE NT занимает в среднем 5 секунд. Это слишком долго.

Второе решение, которое я нашел, - использовать MERGE. Я создал такую ​​хранимую процедуру, которая принимает параметр с табличным значением:

CREATE PROCEDURE [dbo].[sp_updateTransactions]
@Table dbo.tp_Transactions readonly,
@itemId bigint,
@platform char(1)
AS
BEGIN
MERGE Transactions AS TARGET
USING @Table AS SOURCE  
ON (    
TARGET.[itemId] = SOURCE.[itemId] AND
TARGET.[platform] = SOURCE.[platform] AND 
TARGET.[dt] = SOURCE.[dt] AND 
TARGET.[count] = SOURCE.[count] AND
TARGET.[price] = SOURCE.[price] ) 


WHEN NOT MATCHED BY TARGET THEN 
INSERT VALUES (SOURCE.[itemId], 
                SOURCE.[dt],
                SOURCE.[count],
                SOURCE.[price],
                SOURCE.[platform])

WHEN NOT MATCHED BY SOURCE AND TARGET.[itemId] = @itemId AND TARGET.[platform] = @platform THEN 
DELETE;

END

Эта процедура занимает около 7 секунд с таблицей с 70k записями. Так что с 8M это, вероятно, займет несколько минут. Узкое место - «Когда не совпадают» - когда я прокомментировал эту строку, эта процедура длится в среднем 0,01 секунды.

Итак, вопрос: как улучшить производительность оператора удаления?

Удаление необходимо, чтобы убедиться, что таблица не содержит транзакцию, которая была удалена в приложении. Но в реальном сценарии это случается очень редко, и истинная потребность в удалении записей меньше 1 на 10000 обновлений транзакций.

Мой теоретический обходной путь - создать дополнительный столбец типа «transactionDeleted bit» и использовать UPDATE вместо DELETE, а затем выполнить очистку таблицы пакетным заданием каждые X минут или часов и выполнить

delete from transactions where transactionDeleted=1

Это должно быть быстрее, но мне понадобится обновлять все операторы SELECT в других частях приложения, использовать только записи transactionDeleted = 0, что также может повлиять на производительность приложения.

Знаете ли вы лучшее решение?

ОБНОВЛЕНИЕ: Текущие индексы:

CREATE NONCLUSTERED INDEX [IX1] ON [dbo].[Transactions] 
(
[platform] ASC,
[ItemId] ASC
) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF,   IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 50) ON [PRIMARY]


CONSTRAINT [IX2] UNIQUE NONCLUSTERED 
(
[ItemId] DESC,
[count] ASC,
[dt] DESC,
[platform] ASC,
[price] ASC
) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
7
задан Brian Tompsett - 汤莱恩 14 August 2015 в 15:39
поделиться