none
query linq con problemi di performance RRS feed

  • Domanda

  • Salve a tutti!

    Ho scritto la seguente query linq che prende i dati da 3 file XML:

    Dim xd1 As XDocument = XDocument.Load("C:\doc1.xml")
    Dim xd2 As XDocument = XDocument.Load("C:\doc2.xml")
    Dim xd3 As XDocument = XDocument.Load("C:\doc3.xml")

    Dim q = From a In xd1...<row>, b In xd2...<row>, c In xd3...<row> Where
            a.@Campo1 = "pippo" AndAlso b.@Campo2 = a.@RifCampo2 AndAlso c.@Campo3 = a.@RifCampo3 Select
            b.@Campo4, b.@Campo5, c.@Campo6

    Dim s As String = ""
    For Each a In q
        s &= a.Campo4 & " - " & a.Campo5 & " - " & a.Campo6 & vbCrLf
    Next

    TextBlock1.Text = s

    Ma quel codice impiega circa 5 secondi ad essere eseguito. Avrei senz'altro proceduto a rifare la query in altro modo per migliorare le performance, magari spezzandola in 3 query distinte, ma poi mi sono accorto di una cosa:

    Andando in debug ho visto che la riga

    Dim q = From ...

    ci impiega un istante ad essere eseguita, e tutto procede speditamente fin quando il ciclo For Each non ha finito gli items da scorrere e deve uscire. Allora si mette a "pensare" per qualche secondo e poi esce.

    Questa attesa la ottengo anche se scrivo

    Dim q = (From ... ).ToArray

    oppure se scrivo:

    Dim i As Long = q.Count

    La cosa più strana è che occorra così tanto per capire che la lista di items è finita e occorre uscire dal ciclo. Aggiungo un particolare: la query q contiene soltanto 8 items.

    Avreste qualche consiglio da darmi?

    Pileggi

    • Spostato Irina Turcu lunedì 30 aprile 2012 03:30 Topic più adatto per il forum dedicato al LINQ. (Da:Microsoft Visual Basic Forum)
    venerdì 27 aprile 2012 16:58

Risposte

  • ciao

    non consiglio di non usare LINQ2XML, ma questo va usato per le estrazioni, e non per i calcoli in cicli di grandi dimensioni perchè l'estrazione dei dati avviene sempre tramite il DOM sull'XML

    motivo per cui quando fai un XDocument.Descendants("tagX"), ti consiglio di fare anche un .Select(x=> new { x.@attr1, x.@attr2, ...})

    e mettere i calcoli in una variabile, così da lavorare poi li dentro tramite, come hai notato, LINQ2Objects

    questo dovrebbe aiutarti molto

    a presto

    Allora, innanzi tutto ti ringrazio molto per la spiegazione. Però nel mio caso non ottengo miglioramento, anzi un leggero peggioramento, questa è la query iniziale rifatta con le tue indicazioni (ho sostituito i nomi dei campi reali con Campo1, Campo2, ma la sostanza non cambia):

    Dim q = From a In xd1...<row>.Select(Function(f) New With {f.@Campo1, f.@RifCampo2, f.@RifCampo3}),
            b In xd2...<row>.Select(Function(f) New With {f.@Campo2, f.@Campo4, f.@Campo5}),
            c In xd3...<row>.Select(Function(f) New With {f.@Campo3, f.@Campo6})
            Where a.Campo1 = "pippo" AndAlso b.Campo2 = a.RifCampo2 AndAlso c.Campo3 = a.RifCampo3
            Select b.Campo4, b.Campo5, c.Campo6

    Nel frattempo però ho trovato (grazie ad un suggerimento pervenutomi per altre vie), un modo facile per accellerare la query. Faccio il where sul primo insieme prima di unirlo agl'altri 2 insiemi:

    Dim q = From a In xd1...<row>.Where(Function(f) f.@Campo1 = "pippo"), b In xd2...<row>, c In xd3...<row>
            Where b.@Campo2 = a.@RifCampo2 AndAlso c.@Campo3 = a.@RifCampo3
            Select b.@Campo4, b.@Campo5, c.@Campo6

    Io a questo punto sono a posto, però non ti sembra curioso che il delay debba avvenire quando occorre uscire dal ciclo anzichè all'esecuzione della query?

    Pileggi

    • Contrassegnato come risposta pileggi giovedì 3 maggio 2012 08:39
    giovedì 3 maggio 2012 08:38

Tutte le risposte

  • Ciao Pileggi,

    Per poter avere un supporto migliore, ti ho spostato la domanda sul forum dedicato a LINQ.

    Saluti,


    Irina Turcu - Microsoft

    [Manifesto] Regole e Aspetti generali all'uso dei forum MSDN

    Questo contenuto è distribuito “as is” e non implica alcuna responsabilità da parte di Microsoft. L'azienda offre questo servizio gratuitamente, allo scopo di aiutare gli utenti e approfondire la loro conoscenza dei prodotti e tecnologie Microsoft.

    LinkedIn

    lunedì 30 aprile 2012 03:33
  • ciao

    il mio consiglio è di non usar il DOM di XDocument per fare filtri e proiezioni, leggiti le proprietà in un tipo anonimo tutto tuo (http://msdn.microsoft.com/en-us/library/bb384767.aspx)

    alla fine lavora con una query linq su questo resultset di dati temporanei

    se non hai miglioramenti, prova a darci degli esempi di codice un po più realistici per porteri aiutare

    a presto


    Antonio Esposito [MCT, MCPD, MCTS, MCP]
    dotnetlombardia.org | blog | web | @tonyexpo
    Italy
     

    lunedì 30 aprile 2012 09:33
  • Ciao Antonio,

    ti ringrazio molto della risposta. Se ho capito bene mi consigli di non usare Linq to XML ma solo Linq to Object. Ma con quale tecnica mi consigli di leggere i dati dal file XML? Potresti anche dirmi qualcosa sul perchè di questa necessità? Da una parte sono contento di risolvere i problemi di performance, ma dall'altra dovrei scrivere molto più codice... :-)

    Pileggi

    mercoledì 2 maggio 2012 08:33
  • ciao

    non consiglio di non usare LINQ2XML, ma questo va usato per le estrazioni, e non per i calcoli in cicli di grandi dimensioni perchè l'estrazione dei dati avviene sempre tramite il DOM sull'XML

    motivo per cui quando fai un XDocument.Descendants("tagX"), ti consiglio di fare anche un .Select(x=> new { x.@attr1, x.@attr2, ...})

    e mettere i calcoli in una variabile, così da lavorare poi li dentro tramite, come hai notato, LINQ2Objects

    questo dovrebbe aiutarti molto

    a presto


    Antonio Esposito [MCT, MCPD, MCTS, MCP]
    dotnetlombardia.org | blog | web | @tonyexpo
    Italy
     

    mercoledì 2 maggio 2012 11:03
  • ciao

    non consiglio di non usare LINQ2XML, ma questo va usato per le estrazioni, e non per i calcoli in cicli di grandi dimensioni perchè l'estrazione dei dati avviene sempre tramite il DOM sull'XML

    motivo per cui quando fai un XDocument.Descendants("tagX"), ti consiglio di fare anche un .Select(x=> new { x.@attr1, x.@attr2, ...})

    e mettere i calcoli in una variabile, così da lavorare poi li dentro tramite, come hai notato, LINQ2Objects

    questo dovrebbe aiutarti molto

    a presto

    Allora, innanzi tutto ti ringrazio molto per la spiegazione. Però nel mio caso non ottengo miglioramento, anzi un leggero peggioramento, questa è la query iniziale rifatta con le tue indicazioni (ho sostituito i nomi dei campi reali con Campo1, Campo2, ma la sostanza non cambia):

    Dim q = From a In xd1...<row>.Select(Function(f) New With {f.@Campo1, f.@RifCampo2, f.@RifCampo3}),
            b In xd2...<row>.Select(Function(f) New With {f.@Campo2, f.@Campo4, f.@Campo5}),
            c In xd3...<row>.Select(Function(f) New With {f.@Campo3, f.@Campo6})
            Where a.Campo1 = "pippo" AndAlso b.Campo2 = a.RifCampo2 AndAlso c.Campo3 = a.RifCampo3
            Select b.Campo4, b.Campo5, c.Campo6

    Nel frattempo però ho trovato (grazie ad un suggerimento pervenutomi per altre vie), un modo facile per accellerare la query. Faccio il where sul primo insieme prima di unirlo agl'altri 2 insiemi:

    Dim q = From a In xd1...<row>.Where(Function(f) f.@Campo1 = "pippo"), b In xd2...<row>, c In xd3...<row>
            Where b.@Campo2 = a.@RifCampo2 AndAlso c.@Campo3 = a.@RifCampo3
            Select b.@Campo4, b.@Campo5, c.@Campo6

    Io a questo punto sono a posto, però non ti sembra curioso che il delay debba avvenire quando occorre uscire dal ciclo anzichè all'esecuzione della query?

    Pileggi

    • Contrassegnato come risposta pileggi giovedì 3 maggio 2012 08:39
    giovedì 3 maggio 2012 08:38