У меня проблема с огромным количеством INSERT, которые блокируют мои операции SELECT.
схема
У меня есть такая таблица:
CREATE TABLE [InverterData](
[InverterID] [bigint] NOT NULL,
[TimeStamp] [datetime] NOT NULL,
[ValueA] [decimal](18, 2) NULL,
[ValueB] [decimal](18, 2) NULL
CONSTRAINT [PrimaryKey_e149e28f-5754-4229-be01-65fafeebce16] PRIMARY KEY CLUSTERED
(
[TimeStamp] DESC,
[InverterID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON)
)
У меня также есть эта маленькая вспомогательная процедура, которая позволяет мне вставлять или обновлять (обновлять при конфликте) с помощью команды MERGE:
CREATE PROCEDURE [InsertOrUpdateInverterData]
@InverterID bigint, @TimeStamp datetime
, @ValueA decimal(18,2), @ValueB decimal(18,2)
AS
BEGIN
MERGE [InverterData] AS TARGET
USING (VALUES (@InverterID, @TimeStamp, @ValueA, @ValueB))
AS SOURCE ([InverterID], [TimeStamp], [ValueA], [ValueB])
ON TARGET.[InverterID] = @InverterID AND TARGET.[TimeStamp] = @TimeStamp
WHEN MATCHED THEN
UPDATE
SET [ValueA] = SOURCE.[ValueA], [ValueB] = SOURCE.[ValueB]
WHEN NOT MATCHED THEN
INSERT ([InverterID], [TimeStamp], [ValueA], [ValueB])
VALUES (SOURCE.[InverterID], SOURCE.[TimeStamp], SOURCE.[ValueA], SOURCE.[ValueB]);
END
использование
Теперь я запускаю экземпляры служб на нескольких серверах, которые выполняют масштабные обновления, [InsertOrUpdateInverterData]
быстро вызывая процедуру.
Существует также веб-сайт, который выполняет запросы SELECT на [InverterData]
столе.
проблема
Если я выполняю запросы SELECT к [InverterData]
таблице, они выполняются в разные промежутки времени, в зависимости от использования INSERT моих экземпляров службы. Если я приостанавливаю все экземпляры службы, SELECT работает молниеносно, если экземпляр выполняет быструю вставку, SELECT становятся очень медленными или даже отменяют тайм-аут.
попытки
Я сделал несколько SELECT на [sys.dm_tran_locks]
столе, чтобы найти процессы блокировки, как это
SELECT
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingText,
tl.request_mode
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
Это результат:
S = Shared. Для проведения сеанса предоставляется общий доступ к ресурсу.
Вопрос
Почему SELECT блокируется [InsertOrUpdateInverterData]
процедурой, которая использует только команды MERGE?
Нужно ли использовать какую-то транзакцию с определенным режимом изоляции внутри [InsertOrUpdateInverterData]
?
Обновление 1 (связано с вопросом от @Paul)
База данных внутреннего сервера MS-SQL о [InsertOrUpdateInverterData]
следующей статистике:
- Среднее время процессора: 0,12 мс
- Среднее число процессов чтения: 5,76 чел / с
- Среднее число процессов записи: 0,4 за / с
Исходя из этого, похоже, что команда MERGE в основном занята операциями чтения, которые блокируют таблицу! (?)
Обновление 2 (связано с вопросом от @Paul)
[InverterData]
Таблица , как имеет следующие хранения статистики:
- Объем данных: 26 901,86 МБ
- Количество строк: 131 827 749
- Разделен: правда
- Количество разделов: 62
Вот (почти все) полный набор результатов sp_WhoIsActive :
SELECT
команда
- дд чч: мм: сс.мсс: 00 00: 01: 01.930
- session_id: 73
- wait_info: (12629мс) LCK_M_S
- Процессор: 198
- blocking_session_id: 146
- читает: 99,368
- пишет: 0
- статус: приостановлено
- open_tran_count: 0
[InsertOrUpdateInverterData]
Команда блокировки
- дд чч: мм: сс.мсс: 00 00: 00: 00.330
- идентификатор_сессии: 146
- wait_info: NULL
- Процессор: 3972
- blocking_session_id: NULL
- читает: 376,95
- пишет: 126
- статус: спит
- open_tran_count: 1
([TimeStamp] DESC, [InverterID] ASC)
выглядит как странный выбор для кластерного индекса. Я имею в видуDESC
часть.