Iniciar sesión con Microsoft
Iniciar sesión o crear una cuenta
Hola:
Seleccione una cuenta diferente.
Tiene varias cuentas
Elija la cuenta con la que desea iniciar sesión.

Síntomas

Considere los escenarios siguientes:

  • Tiene una columna que incluye valores secuenciales, como una columna Identity o una columna DateTime, que se insertan a través de la función getDate () .

  • Tiene un índice agrupado que tiene la columna secuencial como columna inicial. Nota El escenario más común es una clave principal agrupada en una columna de identidad. Con menos frecuencia, este problema se puede observar en los índices no agrupados.

  • La aplicación realiza operaciones frecuentes de inserción o actualización en la tabla.

  • Tiene muchas CPU en el sistema. Por lo general, el servidor tiene 16 CPU o más. Esto permite que varias sesiones realicen las operaciones de inserción en la misma tabla al mismo tiempo.

En esta situación, puede experimentar una disminución en el rendimiento de su aplicación. Al examinar los tipos de espera en Sys.dm_exec_requests, observa esperas en el tipo de espera de PAGELATCH_EX y en muchas de las sesiones que esperan en este tipo de espera.

Se produce otro problema si ejecuta la siguiente consulta de diagnóstico en su sistema:

select session_id, wait_type, wait_time, wait_resource from sys.dm_exec_requests
where session_id > 50 and wait_type = 'pagelatch_ex'

En esta situación, es posible que obtenga resultados similares a los siguientes.

session_id wait_type              wait_time         wait_resource
---------- ---------------------- ---------------  ------------------------
60         PAGELATCH_EX           100               5:1:4144
75         PAGELATCH_EX           123               5:1:4144
79         PAGELATCH_EX           401               5:1:4144
80         PAGELATCH_EX           253               5:1:4144
81         PAGELATCH_EX           312               5:1:4144
82         PAGELATCH_EX           355               5:1:4144
84         PAGELATCH_EX           312               5:1:4144
85         PAGELATCH_EX           338               5:1:4144
87         PAGELATCH_EX           405               5:1:4144
88         PAGELATCH_EX           111               5:1:4144
90         PAGELATCH_EX           38                5:1:4144
92         PAGELATCH_EX           115               5:1:4144
94         PAGELATCH_EX           49                5:1:4144
101        PAGELATCH_EX           301               5:1:4144
102        PAGELATCH_EX           45                5:1:4144
103        PAGELATCH_EX           515               5:1:4144
105        PAGELATCH_EX           39                5:1:4144

Observa que varias sesiones están esperando el mismo recurso, que es similar a lo siguiente:

database_id = 5, file_id = 1, database page_id = 4144

Nota El database_id debe ser una base de datos de usuario (el número de identificación es mayor o igual que 5). Si el database_id es 2, es posible que experimente el problema que se describe en el siguiente artículo del blog de equipo de MSSQL Tiger:

Causa

PAGELATCH (bloqueo en una página de índice o datos) es un mecanismo de sincronización de subprocesos. Se usa para sincronizar el acceso físico a corto plazo a páginas de base de datos que se encuentran en la caché del búfer.

PAGELATCH difiere de un PAGEIOLATCH. Este último se usa para sincronizar el acceso físico a las páginas cuando se leen o se escriben en el disco.

Los pestillos de página son comunes en todos los sistemas porque garantizan la protección física de la página. Un índice agrupado ordena los datos por la columna de clave principal. Por este motivo, al crear el índice en una columna secuencial, se producen todas las inserciones de datos nuevas en la misma página al final del índice hasta que se rellena esa página. Sin embargo, en la carga alta, las operaciones de inserción simultáneas pueden causar contención en la última página del árbol B. Este contenido puede producirse en índices agrupados y no agrupados. Esto se debe a que el índice no agrupado ordena las páginas de nivel hoja por la tecla de relleno. Este problema también se conoce como la contención de la inserción de la última página.

Para obtener más información, consulte las siguientes notas del producto:

Diagnosticar y resolver la contención de pestillos en SQL Server

Resolución

Para resolver esta contención, la estrategia general es evitar que todas las operaciones de inserción simultánea tengan acceso a la misma página de base de datos. En su lugar, haga que cada operación de inserción tenga acceso a una página diferente y aumente la simultaneidad. Por lo tanto, cualquiera de los siguientes métodos que organiza los datos por una columna distinta de la columna secuencial logra este objetivo.

En SQL Server 2019, se ha agregado una nueva opción de índice (OPTIMIZE_FOR_SEQUENTIAL_KEY) que puede ayudar a resolver este problema sin usar ninguno de los métodos siguientes. Para obtener más información, consulta en segundo plano en OPTIMIZE_FOR_SEQUENTIAL_KEY .

Método 1

Haga que la columna que contiene los valores secuenciales tenga un índice no agrupado y, a continuación, mueva el índice agrupado a otra columna. Por ejemplo, para una clave principal en una columna de identidad, quite la clave principal agrupada y, a continuación, vuelva a crearla como una clave principal no agrupada. Este es el método más sencillo para hacer y directamente logra el objetivo. Por ejemplo, supongamos que tiene la siguiente tabla que se definió usando una clave principal agrupada en una columna de identidad.

CREATE TABLE Customers
(
CustomerID bigint identity(1,1) not null Primary Key CLUSTERED,
CustomerLastName varchar (32) not null,
CustomerFirstName varchar(32) not null
)

Para cambiar esto, puede quitar el índice de clave principal y redefinirlo.

ALTER TABLE Customers
DROP CONSTRAINT PK__Customer__A4AE64B98819CFF6

ALTER TABLE Customers
add constraint pk_Cust1
primary key NONCLUSTERED (CustomerID)

Método 2

Reordene la definición de índice agrupado de manera tal que la columna inicial no sea la columna secuencial. Esto requiere que el índice agrupado sea un índice compuesto. Por ejemplo, en una tabla Customer, puede hacer que una columna CustomerLastName sea la columna inicial, seguida del CustomerID. Le recomendamos que pruebe minuciosamente este método para asegurarse de que cumple con los requisitos de rendimiento.

ALTER TABLE Customers
add constraint pk_Cust1
primary key clustered (CustomerLastName, CustomerID) 

Método 3

Agregue un valor de hash no secuencial como clave de índice inicial. Esto también distribuirá las inserciones. Un valor hash se puede generar como un módulo que coincida con el número de CPU del sistema. Por ejemplo, en un sistema de 16 CPUS, puede usar un módulo de 16. Este método extiende las operaciones de inserción uniformemente con varias páginas de base de datos.

CREATE TABLE Customers
(
CustomerID bigint identity(1,1) not null,
CustomerLastName varchar (32) not null,
CustomerFirstName varchar(32) not null
)
go
ALTER TABLE Customers
ADD [HashValue] AS (CONVERT([tinyint], abs([CustomerID])%16)) PERSISTED NOT NULL
go
ALTER TABLE Customers
ADD CONSTRAINT pk_table1
PRIMARY KEY CLUSTERED (HashValue, CustomerID)

Método 4

Use un GUID como la columna de clave principal de un índice para garantizar la distribución uniforme de las inserciones.

Nota Aunque logra el objetivo, no recomendamos este método porque presenta varios desafíos, entre ellos, una gran clave de índice, las divisiones de página frecuentes, la densidad de página baja, etc.

Método 5

Use el particionamiento de tabla y una columna calculada que tiene un valor hash para distribuir las operaciones de inserción. Dado que este método usa la partición de tabla, solo se puede usar en las ediciones empresariales de SQL Server. Nota puede usar tablas con particiones en SQL Server 2016 SP1 Standard Edition. Para obtener más información, consulte la descripción dePartición de tabla e índice "en las ediciones de artículo y características compatibles de SQL Server 2016. El siguiente es un ejemplo de un sistema que tiene 16 CPU.

CREATE TABLE Customers
(
CustomerID bigint identity(1,1) not null,
CustomerLastName varchar (32) not null,
CustomerFirstName varchar(32) not null
)
go
ALTER TABLE Customers
ADD [HashID] AS CONVERT(tinyint, ABS(CustomerID % 16)) PERSISTED NOT NULL)
go
CREATE PARTITION FUNCTION pf_hash (tinyint) AS RANGE LEFT FOR VALUES (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
GO
CREATE PARTITION SCHEME ps_hash AS PARTITION pf_hash ALL TO ([PRIMARY])
GO
ALTER TABLE Customers
DROP CONSTRAINT PK__Customer__A4AE64B98819CFF6
CREATE UNIQUE CLUSTERED INDEX CIX_Hash
ON Customers (CustomerID, HashID) ON ps_hash(HashID)
GO

Método 6

Como alternativa, use un OLTP en memoria especialmente si la contención de pestillo es muy alta. Esta tecnología elimina la contención de pestillos en general. Sin embargo, debe rediseñar y migrar las tablas específicas en las que se observa la contención de los pestillos de página en una tabla de OLTP en memoria. Puede usar el Asistente de optimización de memoria y el informe de análisis de rendimiento de transacciones para determinar si la migración es posible y el esfuerzo implicado en realizar la migración. Para obtener más información sobre cómo OLTP en memoria elimina la contención de bloqueo temporal, descargue y revise el documento en OLTP en memoria: patrones comunes de carga de trabajo y consideraciones de migración.

Referencias

¿Necesita más ayuda?

Ampliar sus conocimientos

Explorar los cursos >

Obtener nuevas características primero

UNIRSE A MICROSOFT 365 INSIDERS >

¿Le ha sido útil esta información?

¿Cuál es tu grado de satisfacción con la calidad del lenguaje?
¿Qué ha afectado a su experiencia?

¡Gracias por sus comentarios!

×