2009-05-27 30 views
6

Tengo una consulta SQL que me devuelve más de medio millón de filas para procesar ... El proceso no lleva mucho tiempo, pero me gustaría acelerarlo un poco con algunos procesos múltiples. Teniendo en cuenta el siguiente código, ¿es posible multiplesear algo así fácilmente?¿Hay alguna forma de multirreproducir un SqlDataReader?

using (SqlDataReader reader = command.ExecuteReader()) 
{ 
    while (reader.Read()) 
    { 
     // ...process row 
    } 
} 

Sería perfecto si pudiera simplemente obtener un cursor al principio y en el medio de la lista de resultados. De esa forma, podría tener dos hilos procesando los registros. Sin embargo, el SqlDataReader no me permite hacer eso ...

¿Alguna idea de cómo podría lograr eso?

+0

Si sabe cómo particionar su consulta, puede ejecutar 2 consultas en paralelo. – VVS

Respuesta

6

Configure una cola de productor/consumidor, con un proceso de productor para extraer del lector y registros de cola lo más rápido que pueda, pero no realice "procesamiento". Luego, otra cantidad de procesos (cuántos desea depende de su sistema) para quitar la cola y procesar cada registro en cola.

+0

Hmm ... extraño, pero no pude encontrar un patrón genérico de productor/consumidor ya implementado. Jugar con el mío ahora, pero la entrada aquí es apreciada: http://stackoverflow.com/questions/916863/generic-net-produce-consumer –

0

¿Es una consulta a distancia simple como WHERE id entre 1 y 500000? Si es así, puede iniciar N consultas que cada uno devuelve 1/N del rango. Pero ayuda a saber dónde está embotellado con el enfoque de rosca simple. Si realiza lecturas contiguas desde un eje de disco para completar la consulta, probablemente debería quedarse con un solo hilo. Si está dividido en husos por algún rango, entonces puede ajustar inteligentemente sus consultas para maximizar el rendimiento del disco (es decir, leer de cada disco en paralelo con consultas separadas). Si espera que todas las filas estén en la memoria, entonces puede paralelizar a voluntad. Pero si la consulta es más compleja, es posible que no pueda dividirla fácilmente sin incurrir en un montón de gastos generales. La mayoría de las veces las opciones anteriores no se aplicarán bien y el productor/consumidor que mencionó Joel será el único lugar para paralelizar. Dependiendo de cuánto tiempo dedique a procesar cada fila, esto puede proporcionar ganancias triviales.

3

No debe leer tantas filas en el cliente.

Dicho esto, puede dividir la consulta en varias consultas y ejecutarlas en paralelo. Eso significa lanzar múltiples SqlCommands en hilos separados y hacer que cada batimiento genere una partición del resultado. La A + pregunta es cómo dividir el resultado, y esto depende en gran medida o sus datos y su consulta:

  1. Se puede utilizar una variedad de teclas
  2. Usted puede utilizar un atributo (por ejemplo ID betweem 1 and 10000, ID between 10001 and 20000 etc.) (por ejemplo. RecordTypeID IN (1,2), RecordTypeID IN (3,4) etc)
  3. puede utilizar una gama sintético (es decir. ROW_NUMBER() BETWEEN 1 and 1000 etc), pero esto es muy problemático para tirar de la derecha
  4. puede utilizar un hash (por ejemplo. BINARY_CHECKSUM(*)%10 == 0, BINARY_CHECKSUM(*)%10==1 etc)

Solo tiene que tener mucho cuidado de que las consultas de partición no se superpongan y bloque durante la ejecución (es decir. escanee los mismos registros y adquiera cerraduras X), serializándose entre sí.

+0

No creo que esta sea una muy buena idea: el desarrollador no debería tener que saber mucho sobre los datos (o cómo podría verse en el futuro). Además, cualquier solución debe ser reutilizable en otros escenarios.Una verdadera solución multihilo sería mejor, como productor/consumidor mencionado anteriormente. –

Cuestiones relacionadas