Entonces, tengo un proceso simple de inserción masiva para tomar datos de nuestra tabla de etapas y moverlos a nuestro datamart.
El proceso es una tarea de flujo de datos simple con la configuración predeterminada para "Filas por lote" y las opciones son "tablock" y "sin restricción de verificación".
La mesa es bastante grande. 587,162,986 con un tamaño de datos de 201GB y 49GB de espacio de índice. El índice agrupado para la tabla es.
CREATE CLUSTERED INDEX ImageData ON dbo.ImageData
(
DOC_ID ASC,
ACCT_NUM ASC,
MasterID ASC
)
Y la clave principal es:
ALTER TABLE dbo.ImageData
ADD CONSTRAINT ImageData
PRIMARY KEY NONCLUSTERED
(
ImageID ASC,
DT_CRTE_DOC ASC
)
Ahora hemos tenido un problema en el que a BULK INSERT
través de SSIS se ejecuta increíblemente lento. 1 hora para insertar un millón de filas. La consulta que llena la tabla ya está ordenada y la consulta para completar tarda menos de un minuto en ejecutarse.
Cuando el proceso se está ejecutando, puedo ver la consulta esperando en la inserción BULK, que tarda entre 5 y 20 segundos y muestra un tipo de espera de PAGEIOLATCH_EX
. El proceso solo puede realizar INSERT
aproximadamente mil filas a la vez.
Ayer, mientras probaba este proceso en mi entorno UAT, me encontraba con el mismo problema. Estuve ejecutando el proceso varias veces e intentando determinar cuál es la causa raíz de esta inserción lenta. Luego, de repente, comenzó a funcionar en menos de 5 minutos. Así que lo corrí unas cuantas veces más con el mismo resultado. Además, la cantidad de insertos masivos que esperaban 5 segundos o más se redujo de cientos a aproximadamente 4.
Ahora esto es desconcertante porque no es como si tuviéramos una gran caída en la actividad.
La CPU durante la duración es baja.
Los momentos en que es más lento parece haber menos esperas en el disco.
La latencia de disco en realidad aumenta durante el período de tiempo en que el proceso se ejecutó en menos de 5 minutos.
Y el IO fue mucho más bajo durante los tiempos en que este proceso funciona mal.
Ya lo revisé y no hubo crecimiento de archivos ya que los archivos están llenos solo en un 70%. El archivo de registro todavía tiene un 50% para ir. La base de datos está en modo de recuperación simple. DB solo tiene un grupo de archivos, pero se distribuye en 4 archivos.
Entonces, lo que me pregunto es : ¿por qué estaba viendo tiempos de espera tan largos en esos insertos a granel? B: ¿qué tipo de magia sucedió que lo hizo correr más rápido?
Nota al margen. Funciona como una mierda otra vez hoy.
ACTUALIZAR está actualmente particionado. Sin embargo, se hace en un método que es, en el mejor de los casos, tonto.
CREATE PARTITION SCHEME [ps_Image] AS PARTITION [pf_Image]
TO ([FG_Image], [FG_Image], [FG_Image], [FG_Image])
CREATE PARTITION FUNCTION [pf_Image](datetime) AS
RANGE RIGHT FOR VALUES (
N'2011-12-01T00:00:00.000'
, N'2013-04-01T00:00:00.000'
, N'2013-07-01T00:00:00.000'
);
Esto deja esencialmente todos los datos en la 4ta partición. Sin embargo, ya que todo va al mismo grupo de archivos. Los datos se dividen actualmente de manera bastante uniforme en esos archivos.
ACTUALIZACIÓN 2 Estas son las esperas generales cuando el proceso funciona mal.
Esta es la espera durante el período en que pude ejecutar el proceso.
El subsistema de almacenamiento es RAID conectado localmente, no involucra SAN. Los registros están en una unidad diferente. Raid Controller es PERC H800 con 1 GB de caché. (Para UAT) Prod es un PERC (810).
Estamos utilizando una recuperación simple sin copias de seguridad. Se restaura a partir de una copia de producción todas las noches.
También hemos configurado IsSorted property = TRUE
SSIS ya que los datos ya están ordenados.
PAGEIOLATCH_EX
y ASYNC_IO_COMPLETION
están indicando que está tardando un poco en obtener datos del disco en la memoria. Esto puede ser un indicador de un problema con el subsistema de disco, o puede ser una disputa de memoria. ¿Cuánta memoria tiene disponible SQL Server?
ASYNC_NETWORK_IO
significa que SQL Server estaba esperando enviar filas a un cliente en algún lugar. Supongo que eso muestra la actividad de SSIS que consume filas de la tabla de etapas.