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.
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.PAGEIOLATCH_EX
yASYNC_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?Respuestas:
No puedo señalar la causa, pero creo que las filas por lote predeterminadas para una operación BULK INSERT son "todas". Establecer un límite en las filas podría hacer que la operación sea más digerible: por eso es una opción. (Aquí y adelante, estoy mirando la documentación de Transact-SQL "BULK INSERT", por lo que podría estar muy lejos de SSIS).
Tendrá el efecto de dividir la operación en múltiples lotes de X filas, cada una operando como una transacción separada. Si hay un error, los lotes que terminaron permanecerán confirmados en la tabla de destino y el lote que se detuvo se revertirá. Si eso es tolerable en lo que está haciendo, es decir, puede volver a ejecutarlo más tarde y ponerse al día, intente eso.
No está mal tener una función de partición que coloque todas las inserciones actuales en una partición de tabla, pero no veo cómo es útil particionar en absoluto con particiones en el mismo grupo de archivos. Y usar datetime es pobre, y en realidad está un poco roto para datetime y 'YYYY-MM-DD' sin la fórmula CONVERT explícita desde SQL Server 2008 (SQL puede tratar esto alegremente como YYYY-DD-MM: no es broma: no se asuste, simplemente cámbielo a 'AAAAMMDD', fijo: o CONVERTIR (fecha y hora, 'AAAA-MM-DDT00: 00: 00', 126), creo que es así). Pero creo que usar un proxy para el valor de fecha (año como int, o año + trimestre) para particionar funcionará mejor.
Tal vez es un diseño copiado de otro lugar, o duplicado en varios datamarts. Si esto -es- un verdadero datamart, un volcado del almacén de datos para darles a los gerentes de departamento algunos datos con los que jugar, eso (no lo envías) a otro lugar, y probablemente sea de solo lectura en lo que respecta a los usuarios de datos , entonces, me parece que podría eliminar la función de partición -o- cambiarla para poner explícitamente todos los datos nuevos en la cuarta partición sin importar qué, y a nadie le importaría. (Tal vez deberías comprobar que a nadie le importa).
Se siente como un diseño en el que el plan es eliminar el contenido de la partición 1 en algún momento en el futuro y crear otra nueva partición para obtener más datos nuevos, pero no parece que eso esté sucediendo aquí. Al menos no ha sucedido desde 2013.
fuente
He visto esta misma lentitud extrema esporádica en insertos en grandes tablas particionadas en ocasiones. ¿Has intentado actualizar las tablas de destino Estadísticas y luego volver a ejecutarlas? El tiempo de espera extremo podría deberse a estadísticas deficientes, y si se activó una actualización de estadísticas en algún momento durante la prueba, eso explicaría el aumento de la velocidad. Solo un pensamiento y una prueba fácil de verificar.
fuente