2009-04-22 18 views

Respuesta

73

Tengo una utilidad de importación instalada en el mismo servidor físico que mi instancia de SQL Server. Usando un IDataReader personalizado, analiza archivos planos y los inserta en una base de datos usando SQLBulkCopy. Un archivo típico tiene aproximadamente 6M filas calificadas, promediando 5 columnas de texto decimal y corto, aproximadamente 30 bytes por fila.

Dado este escenario, encontré que un tamaño de lote de 5.000 es el mejor compromiso de velocidad y consumo de memoria. Empecé con 500 y experimenté con más grande. Encontré que 5000 es 2,5 veces más rápido, en promedio, que 500. Insertar las 6 millones de filas lleva unos 30 segundos con un tamaño de lote de 5000 y aproximadamente 80 segundos con un tamaño de lote de 500.

10,000 no fue mucho más rápido. Mover hasta 50,000 mejoró la velocidad en algunos puntos porcentuales, pero no vale la pena aumentar la carga en el servidor. Más de 50,000 no mostraron mejoras en la velocidad.

Esto no es una fórmula, pero es otro punto de datos para su uso.

+2

Una cosa a considerar es si la tabla está vacía y tiene índices. En esos casos, es posible que desee cargar todo en un lote como se menciona aquí: https://technet.microsoft.com/en-us/library/ms177445(v=sql.105).aspx "Si realiza una importación masiva de datos en un tabla vacía con índices y especifica el tamaño del lote, la tabla se vuelve no vacía después del primer lote. Comenzando con el segundo lote, los datos están completamente registrados. Para las tablas indexadas vacías, considere realizar la importación masiva en un solo lote. " – Sal

3

Todo esto depende de su implementación.

¿Qué tipo de velocidad puede esperar en su red? ¿Lo está usando en Forms o ASP.Net? ¿Necesita alertar al usuario del progreso? ¿Cuál es el tamaño del trabajo total?

En mi experiencia, ejecutar la copia masiva sin un tamaño de lote especificado causará problemas de tiempo de espera. Me gusta comenzar con algo así como 1000 registros y hacer algunos ajustes a partir de ahí.

+0

Velocidad: Varía, WebForms: Sí, ASP.NET: Sí, Tablas anchas: Sí, Tablas estrechas, Sí. Miles de filas: sí. Millones de filas: sí. Si puedes pensar en un escenario, probablemente lo esté haciendo. –

+1

Tengo que seguir mi respuesta anterior, entonces. No creo que haya una bala de plata. – Jeremy

24

Este es un problema que también he dedicado a investigar. Estoy buscando optimizar la importación de grandes archivos CSV (16+ GB, más de 65 millones de registros y en crecimiento) en una base de datos de SQL Server 2005 utilizando una aplicación de consola C# (.Net 2.0). Como Jeremy tiene already pointed out, tendrá que hacer algunos ajustes para sus circunstancias particulares, pero le recomendaría que tenga un tamaño de lote inicial de 500 y valores de prueba tanto por encima como por debajo.

Recibí la recomendación de probar valores entre 100 y 1000 para el tamaño del lote de este MSDN forum post, y era escéptico. Pero cuando probé para tamaños de lotes entre 100 y 10,000, encontré que 500 era el valor óptimo para mi aplicación. El valor 500 para SqlBulkCopy.BatchSize también se recomienda here.

Para optimizar aún más su operación SqlBulkCopy, revise este MSDN advice; Encuentro que usar SqlBulkCopyOptions.TableLock ayuda a reducir el tiempo de carga.

+0

Reconozco que ejecutar el comando de copia masiva en el servidor mismo probablemente sería más rápido. –

12

Como han indicado otros, depende de su entorno, específicamente el volumen de fila y la latencia de la red.

Personalmente, comenzaría por establecer la propiedad BatchSize en 1000 filas y ver cómo funciona. Si funciona, sigo duplicando el número de filas (por ejemplo, hasta 2000, 4000, etc.) hasta que obtengo un tiempo de espera.

De lo contrario, si se produce un tiempo de espera en 1000, disminuyo el número de filas a la mitad (por ejemplo, 500) hasta que funcione.

En cada caso, sigo doblando (si tiene éxito) o reduciendo a la mitad (si no se pudo) la diferencia entre cada uno de los últimos dos tamaños de lote intentados hasta encontrar un punto óptimo.

El otro factor a considerar es cuánto tiempo se tarda en copiar un lote único de filas. Los tiempos de espera se producirán si el lote de filas que se está copiando supera la propiedad BulkCopyTimeout, que de forma predeterminada es de 30 segundos. Puede intentar doblar la propiedad BulkCopyTimeout a 60 segundos. Esto permite un período de tiempo más largo para que se copie un conjunto mayor de filas de lotes. Por ejemplo, un lote de 50,000 filas puede tomar alrededor de 40 segundos, excediendo el límite de tiempo de 30 segundos, por lo que aumentarlo hasta 60 segundos podría ayudar con el rendimiento.

Cuestiones relacionadas