Tengo un problema con una gran cantidad de INSERTOS que están bloqueando mis operaciones SELECT.
Esquema
Tengo una mesa como esta:
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)
)
También tengo este pequeño procedimiento auxiliar, que me permite insertar o actualizar (actualizar en conflicto) con el comando 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
Uso
Ahora he ejecutado instancias de servicio en varios servidores que realizan actualizaciones masivas llamando [InsertOrUpdateInverterData]
rápidamente al procedimiento.
También hay un sitio web que selecciona consultas en la [InverterData]
tabla.
Problema
Si selecciono consultas en la [InverterData]
tabla, se realizan en diferentes intervalos de tiempo, dependiendo del uso de INSERT de mis instancias de servicio. Si detengo todas las instancias de servicio, SELECT es extremadamente rápido, si la instancia realiza una inserción rápida, los SELECT se vuelven muy lentos o incluso se cancela el tiempo de espera.
Intentos
He hecho algunos SELECT en la [sys.dm_tran_locks]
tabla para encontrar procesos de bloqueo, como este
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
Este es el resultado:
S = Compartido. La sesión de retención tiene acceso compartido al recurso.
Pregunta
¿Por qué los SELECT están bloqueados por el [InsertOrUpdateInverterData]
procedimiento que solo usa comandos MERGE?
¿Tengo que usar algún tipo de transacción con modo de aislamiento definido dentro [InsertOrUpdateInverterData]
?
Actualización 1 (relacionada con la pregunta de @Paul)
Base en los informes internos del servidor MS-SQL sobre la [InsertOrUpdateInverterData]
siguiente estadística:
- Tiempo promedio de CPU: 0.12ms
- Procesos de lectura promedio: 5.76 por / s
- Procesos de escritura promedio: 0.4 por / s
¡Basándome en esto, parece que el comando MERGE está ocupado principalmente con operaciones de lectura que bloquearán la tabla! (?)
Actualización 2 (relacionada con la pregunta de @Paul)
La [InverterData]
tabla tiene las siguientes estadísticas de almacenamiento:
- Espacio de datos: 26,901.86 MB
- Recuento de filas: 131,827,749
- Particionado: verdadero
- Recuento de particiones: 62
Aquí está el conjunto de resultados sp_WhoIsActive completo (casi) :
SELECT
mando
- dd hh: mm: ss.mss: 00 00: 01: 01.930
- session_id: 73
- wait_info: (12629ms) LCK_M_S
- CPU: 198
- block_session_id: 146
- lecturas: 99,368
- escribe: 0
- estado: suspendido
- open_tran_count: 0
[InsertOrUpdateInverterData]
Comando de bloqueo
- dd hh: mm: ss.mss: 00 00: 00: 00.330
- session_id: 146
- wait_info: NULL
- CPU: 3.972
- block_session_id: NULL
- lecturas: 376,95
- escribe: 126
- estado: durmiendo
- open_tran_count: 1
([TimeStamp] DESC, [InverterID] ASC)
ve como una opción extraña para el índice agrupado. Me refiero a laDESC
parte.