527 messaggi dal 18 dicembre 2012
Ciao a tutti
ho realizzato un portale per la prenotazione di strutture albeghiere.
Quando un utente richiede la disponibilità di una camera eseguo un algoritmo che interroga il db(sql server) sulla disponibilità delle camere.
L'esecuzione della query è abbastanza veloce, ma ho problemi di lentezza quando vado a leggere questi valori.
In pratica, leggo le righe della query e salvo i dati in una List che passo all'algoritmo. Queste righe contengono per ogni camera trovata le tariffe per ogni giorno e per ogni livello tariffario.
Capita di dover leggere anche 1200 righe e l'operazione risulta lenta.
Non ho idea su come rendere questa operazione più veloce.
Qualcuno può darmi qualche consiglio?
Grazie mille
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
penso che il problema non sia nelle 1200 righe. Anche se è un buon numero, leggerle dal db e ciclarle con un foreach non dovrebbe richiedere così tanto tempo da destare preoccupazione (certo, se riesci a ridurne il numero è meglio).

Di solito, la lentezza dipende da query molto complesse ma tu hai detto che viene eseguita velocemente e che non è quello il problema. L'importante è che tu abbia misurato bene i tempi e che tu sia consapevole della deferred execution delle query LINQ.
https://blogs.msdn.microsoft.com/charlie/2007/12/10/linq-and-deferred-execution/
Il cronometro va avviato subito prima di invocare il .ToList() e fermato subito dopo. Quello è il tempo effettivo che impiega la tua applicazione a recuperare i dati dal db.

A questo punto passi la lista all'algoritmo. Hai misurato anche il suo tempo di esecuzione? Come si rapporta al tempo di esecuzione della query?
Se scopri che il problema è nell'algoritmo, può darsi che dipenda dal fatto che stai accedendo alle proprietà di navigazione delle 1200 entità.

Cito proprio questa tra le tante cause possibili perché è forse quella più subdola: se hai il lazy loading abilitato (lo è per default), Entity Framework ti fornirà i dati dalle proprietà di navigazione ma questo lo costringe ad effettuare almeno una query per ciascuna delle 1200 entità. E' un problema conosciuto come SELECT n+1 e lo trovi spiegato qui.
http://blogs.microsoft.co.il/gilf/2010/08/18/select-n1-problem-how-to-decrease-your-orm-performance/
Se è questo il problema, la soluzione consiste nell'aggiungere degli .Include alla tua query linq per chiedere ad EF di recuperare tutti i dati dalle entità correlate in un solo round-trip al database.

Per capire quale sia effettivamente il problema, servono altre informazioni. Usa la strumentazione di Visual Studio e/o la classe Stopwatch per misurare i tempi di esecuzione.

ciao,
Moreno

Enjoy learning and just keep making
527 messaggi dal 18 dicembre 2012
ciao Moreno e grazie
Ho utilizzato Stopwatch e confermo che il problema di velocità è nella lettura dei dati.
Grazie per gli articoli che hai girato, ma non utilizzo EF. Sto utilizzando System.Data.SqlClient

Ho trovato cosa rallentava il tutto:

giornoDB = Converti.toDateTime(dRead["giorno"])

dove Converti.toDateTime è così:
public static DateTime toDateTime(object value)
{
try
{
return FormatoDateTimeLingua(value.ToString());
}
catch (Exception ex)
{
return default(DateTime);
}
}

public static DateTime FormatoDateTimeLingua(string datetime)
{
DateTime dateResult;
CultureInfo culture = CultureInfo.CreateSpecificCulture(Lingue.getLingua());
DateTime.TryParse(datetime, culture, DateTimeStyles.None, out dateResult);

return dateResult;
}

Per rallenta tutto?
Grazie
Modificato da Svipla il 20 giugno 2016 16.52 -
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
il metodo Lingue.getLingua() accede al database?

Enjoy learning and just keep making
527 messaggi dal 18 dicembre 2012
Ciao Moreno
No, restituisce solo la lingua scelta dall'utente
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,


No, restituisce solo la lingua scelta dall'utente

ok, allora prova fargli restituire un'istanza di CultureInfo anziché la stringa "it".
Fai in modo che l'istanza restituita da Lingue.getLingua() sia sempre la stessa, così crei una sorta di cache ed eviti l'inutilità del creare ogni volta una nuova istanza con CultureInfo.CreateSpecificCulture ad ogni iterazione del ciclo.

Possibile implementazione della classe Lingua (non statica) e dei suoi due metodi getLingua e getCulture.
public class Lingue
{

    private Lazy<CultureInfo> cultureUtente;
    public Lingue()
    {
        cultureUtente = new Lazy<CultureInfo>(() =>
        {
            var linguaUtente = GetLingua();
            return CultureInfo.CreateSpecificCulture(linguaUtente);
        });
    }

    public string GetLingua()
    {
        //Sostituisci con la tua attuale implementazione
        return "it";
    }

    public CultureInfo GetCulture()
    {
        //Otteniamo la culture in maniera Lazy
        //ma una volta creata, verrà restituita
        //sempre la stessa istanza.
        return cultureUtente.Value;
    }
}


e poi la usi così:
CultureInfo culture = istanzaDiLingua.GetCulture();
DateTime.TryParse(datetime, culture, DateTimeStyles.None, out dateResult);


ciao,
Moreno
Modificato da BrightSoul il 22 giugno 2016 08.14 -

Enjoy learning and just keep making
11.886 messaggi dal 09 febbraio 2002
Contributi
Prego! E' stato sufficiente a velocizzarlo un po'?

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.