2009-03-09 12 views
19

Ho un DataTable/raccolta che è memorizzato nella cache, voglio usarlo come sorgente per generare risultati per una casella di testo completa automatica (usando AJAX ovviamente). Sto valutando varie opzioni per recuperare rapidamente i dati. Il numero di elementi nella raccolta/righe nel datatable può variare da 10000 a 2.000.000. (In modo da non essere deviato, per il momento supponiamo che la decisione sia stata presa, ho molta RAM e userò la cache e non la query del database per questo)DataTable.Select vs DataTable.rows.Find vs foreach vs Trova (Predicato <T>)/Lambda

Ho qualche logica di business aggiuntiva per questa elaborazione ; Devo dare la priorità alla lista di completamento automatico come da una colonna priority (int) nella raccolta. Quindi se qualcuno cerca Micro e dico 20 risultati di parole/frasi che iniziano con Micro, sceglierei i primi 10 articoli risultanti con la massima priorità. (da qui la necessità di avere una proprietà di priorità associata al valore di stringa).

Gli elementi della raccolta sono già ordinati in ordine alfabetico.

Quale sarebbe la soluzione migliore in questo caso.
1. Utilizzando DataTable.Select (.
2. Using DataTable.Rows.Find(.
3. Utilizzare una raccolta personalizzata con foreach or for per scorrere attraverso i suoi valori.
4. Utilizzare un insieme generico con anonymous delegates o lambda (since both give same performance o not?)

risposta

2

potremmo speculare su di esso tutto il giorno, ma dal momento che non si tratta di un enorme pezzo di codice, perché non scrivere ciascuno e li punto di riferimento contro l'altro?

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

Beh, basta controllare se qualcuno è già stato lì! –

+0

Se lo fai un benchmark, faccelo sapere! Sono curioso di cosa troverai. –

0

che dire di un DA taView? È possibile applicare la condizione del filtro E ordinare in base alla priorità e scorrere facilmente i risultati per aggiungerli ai risultati.

+0

Sì, l'opzione 2 nella domanda fa esattamente questo. –

4

Sul mio autocomplete, ho provato prima l'approccio linq/lambda, le prestazioni sono un po 'lente. DataTable.Select è più veloce di linq, quindi lo uso. Non ho ancora confrontato le prestazioni tra il datatable.Select e datatable.Find

+0

Hai un indice sulla chiave di filtro? –

+0

La domanda del poster riguarda il filtraggio del DataTable. Quindi l'indice del database non può essere applicato qui. DataTable ha un indice interno in memoria per le righe ed è accessibile solo tramite DataTable.Select (suppongo che DataTable.Find possa accedere anche a quell'indice interno). Linq-to-object non può accedere a quell'indice interno, poiché Linq-to-object sotto il cappuccio circonda tutti gli elementi. A meno che qualcuno non crei un provider Linq-to-DataTable che utilizza DataTable.Select internamente, il filtraggio di DataRow da DataTable utilizzando Linq/Lambda sarà ancora deludente. Architettura DataTable http://j.mp/k56g37 –

+0

La mia domanda riguardava l'indice interno DataTable. Inoltre, secondo http://msdn.microsoft.com/en-us/library/dd364983.aspx "l'indicizzazione della tabella fornisce un vantaggio minore alla query LINQ" –

8

I grafici non sono pubblicati sul mio post di blog; maggiori dettagli possono essere trovati a http://msdn.microsoft.com/en-us/library/dd364983.aspx

Un'altra cosa che ho scoperto è che, per i set di dati di grandi dimensioni, l'utilizzo di un dizionario generico incatenato si comporta incredibilmente bene. Inoltre, aiuta ad alleviare molti dei problemi causati dalle operazioni di ordinamento richieste per le operazioni di aggregazione come min e max (con DataTable.Compute o LINQ).

Per "dizionario generico concatenato", intendo una tecnica Dictionary(Of String, Dictionary(Of String, Dictionary(Of Integer, List(Of DataRow)))) o simile, in cui la chiave per ogni dizionario è un termine di ricerca.

Concesso, ciò non sarà utile in tutte le circostanze, ma ho almeno uno scenario in cui l'implementazione di questo approccio ha comportato un miglioramento delle prestazioni 500x.

Nel tuo caso, prenderei in considerazione l'utilizzo di un dizionario semplice con i primi 1-5 caratteri, quindi un List(Of String). Dovresti creare questo dizionario una volta, aggiungendo le parole agli elenchi con i primi 1-5 caratteri, ma dopo potrai ottenere risultati incredibilmente veloci.

Generalmente avvolgo cose come questa in una classe che mi consente di fare cose come aggiungere parole facilmente. Potresti anche voler usare uno SortedList(Of String), per ordinare automaticamente i risultati. In questo modo, puoi rapidamente consultare l'elenco di parole che corrispondono ai primi N caratteri che sono stati digitati.

+0

E tu sei piuttosto "certo" a riguardo! –