2009-03-09 14 views
19

Tengo una DataTable/colección que está almacenada en la memoria caché, quiero utilizar esto como fuente para generar resultados para un cuadro de texto autocompletar (usando AJAX por supuesto). Estoy evaluando varias opciones para recuperar los datos rápidamente. El número de elementos en la colección/filas en la tabla de datos podría variar de 10000 a 2,000,000. (Para que no nos desviemos, por el momento asumo que la decisión se ha tomado, tengo una RAM amplia y usaré la caché y no la consulta de base de datos para esto)DataTable.Select vs DataTable.rows.Find vs foreach vs Find (Predicado <T>)/Lambda

Tengo un poco de lógica comercial adicional para este procesamiento ; Tengo que priorizar la lista de autocompletar según una columna priority (int) en la colección. Entonces, si alguien busca Micro y obtengo 20 resultados de palabras/oraciones que comienzan con Micro, entonces elegiría los 10 primeros elementos resultantes con mayor prioridad. (de ahí la necesidad de tener una propiedad de prioridad asociada con el valor de la cadena).

Los elementos de la colección ya están ordenados alfabéticamente.

¿Cuál sería la mejor solución en este caso?
1. Utilizando DataTable.Select (.
2. Using DataTable.Rows.Find(.
3. Uso una colección personalizada con foreach or for para iterar a través de sus valores.
4. Uso de una colección genérica con anonymous delegates o lambda (since both give same performance o not?)

Respuesta

2

podríamos especular sobre él todo el día, pero como esto no es una gran pieza de código, ¿por qué no escribir cada uno y comparar uno contra el otro?

public delegate void TestProcedure(); 

public TimeSpan Benchmark(TestProcedure tp) 
{ 
    int testBatchSize = 5; 
    List<TimeSpan> results = new List<TimeSpan>(); 
    for(int i = 0; i<testBatchSize; i++) 
    { 
     DateTime start = DateTime.Now; 
     tp(); 
     results.Add(DateTime.Now - start); 
    } 
    return results.Min(); 
} 
+0

Bueno, simplemente verificando si alguien ya 'ha estado allí'. –

+0

Si lo compara, ¡háganoslo saber! Tengo curiosidad por lo que encontrarás. –

0

Qué pasa con un Da taView? Puede aplicar su condición de filtro Y ordenar por la prioridad, y repetir fácilmente los resultados para agregar a sus resultados.

+0

Sí, la opción 2 en la pregunta hace exactamente esto. –

4

En mi autocomplete, probé primero el enfoque linq/lambda, el rendimiento es un poco lento. DataTable.Select es más rápido que linq, entonces uso esto. Todavía no he comparado el rendimiento entre datatable.Select y datatable.Find

+0

¿Tenía índice en la clave de filtrado? –

+0

La pregunta del póster es sobre el filtrado de la DataTable. Por lo tanto, el índice de la base de datos no se puede aplicar aquí. DataTable tiene un índice interno en la memoria para las filas, y solo se puede acceder a través de DataTable.Select (supongo que DataTable.Find también puede acceder a ese índice interno). Linq-to-object no puede acceder a ese índice interno, ya que el Linq-to-object bajo el capó hace un bucle de todos los elementos. A menos que alguien haga un proveedor de Linq-to-DataTable que use DataTable.Select internamente, filtrar DataRow desde DataTable usando Linq/Lambda aún será decepcionante. Arquitectura de DataTable http://j.mp/k56g37 –

+0

Mi pregunta era sobre el índice interno de DataTable. También de acuerdo con http://msdn.microsoft.com/en-us/library/dd364983.aspx "indexar la tabla proporciona una pequeña ventaja a la consulta LINQ" –

8

Los gráficos no se publican en mi entrada de blog; más detalles se pueden encontrar en http://msdn.microsoft.com/en-us/library/dd364983.aspx

Otra cosa que he descubierto es que, para grandes conjuntos de datos, el uso de un diccionario genérico encadenado funciona increíblemente bien. También ayuda a aliviar muchos de los problemas causados ​​por las operaciones de ordenamiento requeridas para las operaciones de agregación, como mínimo y máximo (con DataTable.Compute o LINQ).

Por "diccionario genérico encadenado", me refiero a Dictionary(Of String, Dictionary(Of String, Dictionary(Of Integer, List(Of DataRow)))) o técnica similar, donde la clave para cada diccionario es un término de búsqueda.

De acuerdo, esto no será útil en todas las circunstancias, pero tengo al menos un escenario en el que la implementación de este enfoque condujo a una mejora en el rendimiento de 500x.

En su caso, consideraría usar un diccionario simple con los primeros 1-5 caracteres, luego un List(Of String). Tendría que construir este diccionario una vez, agregando las palabras a las listas con los primeros 1-5 caracteres, pero después de eso podrá obtener resultados sorprendentemente rápidos.

Generalmente envuelvo cosas como esta en una clase que me permite hacer cosas como agregar palabras fácilmente. Es posible que también desee utilizar un SortedList(Of String), para obtener los resultados ordenados automáticamente. De esta manera, puede buscar rápidamente la lista de palabras que coinciden con los primeros N caracteres que se han escrito.

+0

¡Y está bastante 'Seguro' de eso! –