944 messaggi dal 11 febbraio 2013
Ciao a tutti,

Data la mia poca esperienza non riesco ad ottimizzare un metodo che scorre
una tabella ed assegna le esistenze di magazzino agli ordini.

il metodo è il seguente

public class AssegnaEsistenze
    {

        public Double QuantitaAssegnataProgressiva { get; set; }
public void AssegnaEistenza()
        {
            using (Entities db = new Entities())
            {
                
                Int32 rows = db.DETTAGLIO_ORDINE_SELEZIONATO.Select(o => o.DOS_Anno).Count() -1 ;

                List<DETTAGLIO_ORDINE_SELEZIONATO> listaOrdini = (from o in db.DETTAGLIO_ORDINE_SELEZIONATO
                                                                  select o).OrderBy(o=>o.DOS_Codart).ThenBy(o=>o.DOS_Codvar).ThenBy(o=>o.DOS_Priorita).ToList();
               for (int index = 0; index < rows; index++)
                {
                   string currentCodArt = listaOrdini[index].DOS_Codart;
                   string currentCodVar = listaOrdini[index].DOS_Codvar;
                   string NextCodart = listaOrdini[index + 1].DOS_Codart;
                   string NextCodvar = listaOrdini[index + 1].DOS_Codvar;
                 
                    TABELLA_ESISTENZE tabesiste = new TABELLA_ESISTENZE ();
                    double esistenza = tabesiste.LeggiEsistenzePerArticoloVariante(currentCodArt, currentCodVar) - QuantitaAssegnataProgressiva;
                    
                    if(esistenza > 1) // TOLLERANZA
                    {
                        if(esistenza >= listaOrdini[index].DOS_QuantitaOrdinata)
                        {
                            listaOrdini[index].DOS_QuantitaAssegnata = listaOrdini[index].DOS_QuantitaOrdinata;
                        }
                        else
                        {
                            listaOrdini[index].DOS_QuantitaAssegnata = esistenza;
                        }
                    }
                    else
                    {
                        listaOrdini[index].DOS_QuantitaAssegnata = 0;
                    }

                    if (currentCodArt== NextCodart && currentCodVar==NextCodvar)
                    {
                        QuantitaAssegnataProgressiva += listaOrdini[index].DOS_QuantitaAssegnata;
                    }
                    else
                    {
                        QuantitaAssegnataProgressiva = 0;
                    }

                    db.SaveChanges();
                }

                
            }
        }
}


Il metodo impiega circa 9 minuti ad aggiornare 12000 record...

spero in un vostro aiuto.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
prova ad impostare AutoDetectChangesEnabled a false prima di eseguire il loop, e poi riabilitalo al termine, nei pressi del SaveChanges.
Trovi un esempio qui:
https://msdn.microsoft.com/en-us/data/jj556205.aspx


If you are tracking a lot of entities in your context and you call one of these methods many times in a loop, then you may get significant performance improvements by turning off detection of changes for the duration of the loop.


ciao,
Moreno

Enjoy learning and just keep making
944 messaggi dal 11 febbraio 2013
Grazie Moreno
avevo già provato ad impostare quella proprietà (anche se erroneamente non la riabilitavo alla fine...percui grazie del link) ma non ottengo miglioramenti sensibili: forse ho guadagnato un minuto.

mi chiedo allora se non sia il metodo da rivedere.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
verifica quante e quali query SQL sta inviando Entity Framework a causa del tuo algoritmo. La lentezza potrebbe dipendere da un eccessivo invio di query. Verifichiamo se è questo il caso.

Subito dentro il blocco using, metti questo:
db.Database.Log = query => { File.AppendAllText(Server.MapPath("/App_Data/querylog.txt"), query); }

Ecco la documentazione:
https://msdn.microsoft.com/en-us/data/dn469464.aspx



ciao,
Moreno

Enjoy learning and just keep making
944 messaggi dal 11 febbraio 2013
Ho potuto controllare solo ora...(tra l'altro questa mattina non riuscivo ad accedere ad aspitalia.com)

comunque se excel non mi tradisce
(=CONTA.SE(A2:A196827;"UPDATE [dbo].[DETTAGLIO_ORDINE_SELEZIONATO]"))

ottengo 10.933 comandi UPDATE e un comando SELECT (che coincide con la prima query del metodo dove faccio l'ordinamento)
Connessione a 12/10/2016 14:47:39 +02:00
 apertaSELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[DETTAGLIO_ORDINE_SELEZIONATO] AS [Extent1]
    )  AS [GroupBy1]
-- Esecuzione in 12/10/2016 14:47:39 +02:00
-- Completato in 4 ms con risultato: SqlDataReader

Connessione a 12/10/2016 14:47:39 +02:00
 chiusaConnessione a 12/10/2016 14:47:39 +02:00
 apertaSELECT 
    [Extent1].[DOS_NumeroRiga] AS [DOS_NumeroRiga], 
    [Extent1].[DOS_Anno] AS [DOS_Anno], 
    [Extent1].[DOS_Codcen] AS [DOS_Codcen], 
    [Extent1].[DOS_Coddep] AS [DOS_Coddep], 
    [Extent1].[DOS_Tipord] AS [DOS_Tipord], 
    [Extent1].[DOS_Numord] AS [DOS_Numord], 
    [Extent1].[DOS_Tipdoc] AS [DOS_Tipdoc], 
    [Extent1].[DOS_Distinzione] AS [DOS_Distinzione], 
    [Extent1].[DOS_Codart] AS [DOS_Codart], 
    [Extent1].[DOS_Codvar] AS [DOS_Codvar], 
    [Extent1].[DOS_QuantitaAssegnata] AS [DOS_QuantitaAssegnata], 
    [Extent1].[DOS_QuantitaOrdinata] AS [DOS_QuantitaOrdinata], 
    [Extent1].[DOS_Priorita] AS [DOS_Priorita]
    FROM [dbo].[DETTAGLIO_ORDINE_SELEZIONATO] AS [Extent1]
    ORDER BY [Extent1].[DOS_Codart] ASC, [Extent1].[DOS_Codvar] ASC, [Extent1].[DOS_Priorita] ASC
-- Esecuzione in 12/10/2016 14:47:39 +02:00
-- Completato in 28 ms con risultato: SqlDataReader

Connessione a 12/10/2016 14:47:39 +02:00
 chiusaConnessione a 12/10/2016 14:47:40 +02:00
 apertaTransazione avviata in 12/10/2016 14:47:40 +02:00
UPDATE [dbo].[DETTAGLIO_ORDINE_SELEZIONATO]
SET [DOS_QuantitaAssegnata] = @0
WHERE ((((((([DOS_NumeroRiga] = @1) AND ([DOS_Anno] = @2)) AND ([DOS_Codcen] = @3)) AND ([DOS_Coddep] = @4)) AND ([DOS_Tipord] = @5)) AND ([DOS_Numord] = @6)) AND ([DOS_Distinzione] = @7))
-- @0: '1' (Type = Double)
-- @1: '43366' (Type = Int32)
-- @2: '2016' (Type = Int16)
-- @3: '003' (Type = AnsiString, Size = 3)
-- @4: '300' (Type = AnsiString, Size = 3)
-- @5: '5' (Type = Int16)
-- @6: '1588' (Type = Int32)
-- @7: '00001' (Type = AnsiString, Size = 255)
-- Esecuzione in 12/10/2016 14:47:40 +02:00
-- Completato in 134 ms con risultato: 1

Transazione sottoposta a commit in 12/10/2016 14:47:40 +02:00
Connessione a 12/10/2016 14:47:40 +02:00
 chiusaConnessione a 12/10/2016 14:47:40 +02:00
 apertaTransazione avviata in 12/10/2016 14:47:40 +02:00
UPDATE [dbo].[DETTAGLIO_ORDINE_SELEZIONATO]
SET [DOS_QuantitaAssegnata] = @0
WHERE ((((((([DOS_NumeroRiga] = @1) AND ([DOS_Anno] = @2)) AND ([DOS_Codcen] = @3)) AND ([DOS_Coddep] = @4)) AND ([DOS_Tipord] = @5)) AND ([DOS_Numord] = @6)) AND ([DOS_Distinzione] = @7))
-- @0: '1' (Type = Double)
-- @1: '43367' (Type = Int32)
-- @2: '2016' (Type = Int16)
-- @3: '003' (Type = AnsiString, Size = 3)
-- @4: '300' (Type = AnsiString, Size = 3)
-- @5: '5' (Type = Int16)
-- @6: '1588' (Type = Int32)
-- @7: '00001' (Type = AnsiString, Size = 255)
-- Esecuzione in 12/10/2016 14:47:40 +02:00
-- Completato in 1 ms con risultato: 1

Quindi qual'e il prossimo passo ?

grazie Moreno
Modificato da jjchuck il 12 ottobre 2016 15.29 -
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,


ottengo 10.933 comandi UPDATE e un comando SELECT

Ok, allora niente di anomalo, è semplicemente un'operazione di lunga durata e va eseguita in background. Cioè, non lasciare che l'utente debba attendere dei minuti per vedere la pagina caricarsi ma usa (per esempio) Hangfire per lanciarla, proprio come vedevamo in quest'altra discussione.
http://forum.aspitalia.com/forum/post/412306/DataSet.ReadXml-Valori-Consentiti.aspx

Detto questo, penso che si possa certamente velocizzarne l'esecuzione (ma resterà sempre un'operazione di "lunga durata").
La prima cosa che farei è verificare il piano di esecuzione di una di quelle UPDATE, che sono le dirette responsabili della lentezza dell'algoritmo. Forse otterrai vantaggi mettendo degli indici su una o più delle colonne coinvolte nella clausola WHERE della UPDATE.

Inoltre, potresti avere altri benefici parallelizzando il lavoro: anziché estrarre le 12000 entità con un unico DbContext, creati 4-8 thread e in ciascuno istanza un DbContext che estrarrà un subset di risultati.
Attenzione perché vedo che vai a controllare anche i valori dell'entità successiva a quella corrente:
listaOrdini[index + 1]

quindi occhio a parallelizzare correttamente secondo ciò che deve fare il tuo algoritmo.

ciao,
Moreno

Enjoy learning and just keep making
11.886 messaggi dal 09 febbraio 2002
Contributi
PS. Aggiungo quest'altra cosa importante: non eseguire db.SaveChanges ad ogni iterazione del ciclo. Mettilo fuori dal for o eseguilo solo dopo un certo numero di elementi, così mandi le istruzioni UPDATE al database in batch e questo ti ridurrà il "costo" di inviare comandi al db.

Enjoy learning and just keep making
944 messaggi dal 11 febbraio 2013
Grazie...
cmq per l'ultimo consiglio già me ne ero accordo con le add(INSERT) ...
infatti nella creazione di 12k record ci mette un attimo mettendo savechanges fuori dal ciclo !

però con questo metodo non posso perchè quando cambia l'articolo debbo azzerare la quantitaProgressiva assegnata altrimenti ottengo risultati sbagliati.

cmq grazie per tutto...inizio a pensare che non sei umano :)


PS: il metodo Log raddoppia il tempo di esecuzione...casomai a qualcuno interessasse...no perchè io mi sono spaventato :)
Modificato da jjchuck il 13 ottobre 2016 17.16 -

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.