Considerazioni su prestazioni LINQ to object

mercoledì 11 gennaio 2012 - 13.30
Tag Elenco Tags  C#  |  .NET 3.0  |  .NET 3.5  |  .NET 4.0  |  Windows 7  |  Visual Studio 2010  |  SQL Server 2008 R2  |  SQL Server 2008

andrestu Profilo | Expert

Volevo un parere su un test effettuato su un'applicazione web che utilizza LINQ to object per manipolare dati e cioè mi spiego meglio:

Ho dei dati strutturati su diverse tabelle su database SQL, all'avvio dell'applicazione leggo con ADOnet questi dati e creo delle collection di oggetti corrispondenti alle tabelle, in modo da poterle manipolare con LINQ.
Facendo un esempio banale ho un oggetto che chiamo mioOggetto il quale racchiude 10 proprietà:

public class mioOggetto{ propietà1, propietà2... } (non fate caso alla sintassi è solo per farvi capire)

a runtime leggo con adonet la tabella sul db sql e creo una corrispondente collection di oggetti 'mioOggetto' ognuno valorizzato con i dati letti dal db. Durante questa operazione 3 delle 10 proprietà da valorizzare vengono valorizzate facendo delle query LINQ su altre collection. Quindi per farla breve se per esempio ho 1000 record sul db, per ogni recor dovrò effettuare 3 query linq per un totale di 3000 query linq.
I dati vengono alla fine visualizzati con aspnet tramite un objectdatasource.

La cosa che mi ha stupito è che la velocità di esecuzione nell'esporre i dati è pressochè identica sia che sul db ho 1 o 1000 record, il che mi fa dedurre che LINQ è veramente veloce ad effettuare 3000 query.

Premetto che le tabelle nel db le ho riempite con una SP facendo un inserimento multiplo quindi i dati sono uguali per ogni record, mi chiedo però se può cambiare qualcosa in coso di contenuto misto, come avviene nell'utilizzo reale.

Se avete pareri o test effettuati a riguardo...


Andrea Restucci - Web Developer

Jeremy Profilo | Guru

Ciao Andrea.
A dire il vero non so se cambierebbe qualcosa in caso di "contenuto misto" o di record tutti uguali .... ma sinceramente non credo.
Quello che invece credo,a mio parere, è che stai facendo un uso del tutto improprio della tecnologia Linq.
Sono sicuro che ragionandoci un pò si arriverebbe ad un uso più corretto e più performante, semplicemente strutturando il db in modo corretto ed aggiungendo un DataContext al tuo progetto.
Ma per fare questo bisognerebbe prima capire perchè hai la necessità di fare 3 query per ogni record.

Facci sapere...
Ciao

andrestu Profilo | Expert

perchè pensi che sto facendo un uso improprio di LINQ?
E' molto vantaggioso lavorare direttamente su collection tramite LINQ, cosa cè che non và secondo te?

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

Ciao Andrea.
Risponderti con un esempio pratico senza conoscere bene lo scenario è un pò difficile ... quindi ci provo solo teoricamente.
1)Innanzitutto, implementando un DataContext nel tuo progetto eviteresti di doverti creare delle Collection di Oggetti.....perchè le avresti già a disposzione e perfettamente uguali alle tabelle del DataBase semplicemente grazie al mapping generato da VisualStudio.
Vantaggio .... non devi scriverti la dichiarazione di tutte le proprietà, il quale potrebbe comportare problemi a livello di tipizzazione.
Nel senso che .... se cambi il tipo di uno o più campi nel DataBase e ti dimentichi di modificarla nella dichiarazione delle tue classi .... potresti incorrere in errori per il quale te ne accorgeresti soltanto a run-time.
2)Sono convinto che con una buona normalizzazione del DataBase(e quindi la creazione di relazioni tra tabelle) ridurresti la necessità di fare 3000 query ad una soltanto o poco più....sicuramente più articolata, sicuramente più complicata, ma pur sempre e sicuramente meno di 3000.
Facci sapere...
Ciao

andrestu Profilo | Expert

ok sicuramente l'implementazione di un DataContext sarà il mio prossimo obiettivo, devo prima però leggermi qualcosa sul MSDN perchè sono un pò a digiuno a riguardo, per ora per la creazione delle collection utilizzo del codice che riceve in input un tipo T e genera una collection di tipi T mappando tramite reflection le proprietà della tabella a quelle del tipo. Per la tipizzazione delle proprietà non cè problema perchè le imposto tutte come object, ci pensa il codice durante la trasformazione a tipizzarle opportunamente.
Ti faccio un breve quadro del perchè necessito di 3 query per ogni record così se hai un pò di pazienza riesci a darmi qualche consiglio, ovviamente semplifico il più possibile:

tabella prodotto:
id (chiave primaria) - descrizione

tabella prezzi prodotto:
id (chiave primaria) - idProdotto (chiave secondaria) - prezzo

tabella colori prodotto
id (chiave primaria) - idProdotto (chiave secondaria) - colore

tabella immagini prodotto
id (chiave primaria) - idProdotto (chiave secondaria) - immagine

quindi da come puoi dedurre ad ogni prodotto corrispondono più prezzi, più colori e più immagini.
a questo punto io vorrei avere una collection di oggetti 'prodotto'. l'oggetto prodotto deve essere così strutturato:

public class Prodotto {
id
descrizione
collection di prezzi
collection di colori
collection di immagini
}

e qui sorge la domanda:
come valorizzo le tre collection che si trovano all'interno di ogni prodotto?

Jeremy Profilo | Guru

Ciao Andrea.
<Per la tipizzazione delle proprietà non cè problema perchè le imposto tutte come
>object, ci pensa il codice durante la trasformazione a tipizzarle
>opportunamente.
a momenti ci lasciavo le penne quando ho letto questa parte .... giura che porrai rimedio stanotte stessa

>Ti faccio un breve quadro del perchè necessito di 3 query per
>ogni record così se hai un pò di pazienza riesci a darmi qualche
>consiglio, ovviamente semplifico il più possibile:
>
>tabella prodotto:
>id (chiave primaria) - descrizione
>
>tabella prezzi prodotto:
>id (chiave primaria) - idProdotto (chiave secondaria) - prezzo
>
>tabella colori prodotto
>id (chiave primaria) - idProdotto (chiave secondaria) - colore
>
>tabella immagini prodotto
>id (chiave primaria) - idProdotto (chiave secondaria) - immagine
>
>quindi da come puoi dedurre ad ogni prodotto corrispondono più
>prezzi, più colori e più immagini.
>a questo punto io vorrei avere una collection di oggetti 'prodotto'
Confermo tutto quanto detto nel precedente post.
Con una query fai tutto.

>ok sicuramente l'implementazione di un DataContext sarà il mio prossimo obiettivo, devo prima però leggermi qualcosa sul MSDN perchè sono un pò a digiuno a riguardo
Inizia da qui e se hai bisogno ... facci sapere...
Ciao

andrestu Profilo | Expert

a riguardo della tipizzazione quale potrebbe essere il problema? così facendo mi ritrovo le proprietà dichiarate come object ma a runtime sono comunque tipizzate, quindi se faccio qualche operazione sbagliata sul tipo me ne accorgo subito. sinceramente non vedo questo grave problema oppure mi sfugge qualcosa?

a riguardo di 'con una query fai tutto' sinceramente non vedo come puoi con una sola query valorizzare tutto l'oggetto prodotto correttamente, ovvero, si fa tutto con una query che comunque al suo interno contiene altre tre query che valorizzano le tre collection, altrimenti l'unica altra soluzione sarebbe fare un join che comunque restituirebbe record che per certi campi sarebbero duplicati e quindi dovrei in qualche modo rielaborare il risultato.

magari mi sbaglio ma dovrei avere qualche esempio per rendermene conto, al momento non vedo altre soluzioni e non so neanche se un datacontext riuscirebbe in automatico a restituirmi un oggetto prodotto strutturato in quel modo.

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

>a riguardo della tipizzazione quale potrebbe essere il problema?
-Conversione implicita a run-time ... causa di molti moltissimi bug(in applicazioni particolarmente complesse ... è ovvio ... ma è comunque una cattiva tecnica di programmazione)
-Inutile spreco di risorse.

>così facendo mi ritrovo le proprietà dichiarate come object ma
>a runtime sono comunque tipizzate,
appunto ... a run-time.
Che senso avrebbe lavorare in un ambiente fortemente tipizzato come .Net .... se poi dichiari tutto Object?

> quindi se faccio qualche operazione
>sbagliata sul tipo me ne accorgo subito. sinceramente non vedo
>questo grave problema oppure mi sfugge qualcosa?
Da come la prendi ... sono quasi convinto che se nelle proprietà del progetto --> Scheda Compilazione --> Imposti OptionStrict On .... ti saltano fuori un'infinita di errori del compilatore.(ma può anche darsi di no ... d'altronde il tipo Object si aspetta di tutto)

>a riguardo di 'con una query fai tutto' sinceramente non vedo
>come puoi con una sola query valorizzare tutto l'oggetto prodotto
>correttamente, ovvero, si fa tutto con una query che comunque
>al suo interno contiene altre tre query che valorizzano le tre
>collection, altrimenti l'unica altra soluzione sarebbe fare un
>join che comunque restituirebbe record che per certi campi sarebbero
>duplicati e quindi dovrei in qualche modo rielaborare il risultato.
Per come hai strutturato il database non dovrebbero esserci problemi.

>magari mi sbaglio ma dovrei avere qualche esempio per rendermene
>conto, al momento non vedo altre soluzioni e non so neanche se
>un datacontext riuscirebbe in automatico a restituirmi un oggetto
>prodotto strutturato in quel modo.
Per questo,se hai pazienza, posso vedere di produrre qualcosa nel fine settimana .... fino ad allora non credo di avere tempo ... ho formattato il Pc e devo installare tutto quanto.

Ciao.

andrestu Profilo | Expert

si ok diciamo che le mie applicazioni non sono più di tanto complesse e comunque in caso di problemi per ovviare basterebbe tipizzare le proprietà, il codice funzionerebbe ugualmente.
Vorrei focalizzarmi più sul problema della query e te ne sarei molto grato se mi facessi qualche esempio pratico, per semplificare al massimo possiamo prendere in considerazione anche solo due tabelle:

tabella prodotto:
id (chiave primaria) - descrizione

tabella prezzi prodotto:
id (chiave primaria) - idProdotto (chiave secondaria) - prezzo

Rimango dell'idea che un join restituirebbe un risultato tipo questo:

id - descrizione - idProdotto - prezzo
1 - bla bla bla - 1 - 56,00
1 - bla bla bla - 1 - 50,00
1 - bla bla bla - 1 - 23,00
2 - bla bla bla - 2 - 2,00
2 - bla bla bla - 2 - 53,00
2 - bla bla bla - 2 - 25,00

il chè necessita di un ulteriore elaborazione per poterlo trasformare in collection di tipi 'prodotto'.

Tengo aperto il post e se hai un pò di tempo puoi postarmi quando vuoi qualche esempio l'importante è che il risultato finale sia avere una collection di oggetti 'prodotto' come da post precedenti.
Per il momento ti ringrazio per il tempo dedicato a rispondermi.

aaa dimenticavo, qual'è la funzione del 'OptionStrict On' ???

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

>si ok diciamo che le mie applicazioni non sono più di tanto complesse
>e comunque in caso di problemi per ovviare basterebbe tipizzare
>le proprietà, il codice funzionerebbe ugualmente.
>Vorrei focalizzarmi più sul problema della query e te ne sarei
>molto grato se mi facessi qualche esempio pratico, per semplificare
>al massimo possiamo prendere in considerazione anche solo due
>tabelle:
>
>tabella prodotto:
>id (chiave primaria) - descrizione
>
>tabella prezzi prodotto:
>id (chiave primaria) - idProdotto (chiave secondaria) - prezzo
>
>Rimango dell'idea che un join restituirebbe un risultato tipo
>questo:
>
>id - descrizione - idProdotto - prezzo
>1 - bla bla bla - 1 - 56,00
>1 - bla bla bla - 1 - 50,00
>1 - bla bla bla - 1 - 23,00
>2 - bla bla bla - 2 - 2,00
>2 - bla bla bla - 2 - 53,00
>2 - bla bla bla - 2 - 25,00

>il chè necessita di un ulteriore elaborazione per poterlo trasformare
>in collection di tipi 'prodotto'.
>
>Tengo aperto il post e se hai un pò di tempo puoi postarmi quando
>vuoi qualche esempio l'importante è che il risultato finale sia
>avere una collection di oggetti 'prodotto' come da post precedenti.
>Per il momento ti ringrazio per il tempo dedicato a rispondermi.
>
Dammi qualche giorno di tempo e te lo faccio.
>aaa dimenticavo, qual'è la funzione del 'OptionStrict On' ???
Ti costringe ad una tipizzazione esplicita.... ti spiego tutto nell'esempio.
>
>Andrea Restucci - Web Developer
Ciao.

Jeremy Profilo | Guru

Ciao Andrea.
Stavo cominciando a vedere il progetto di test di cui ti parlavo ....
Mi hai detto che le tabelle devono essere così strutturate ..
>tabella prodotto:
>id (chiave primaria) - descrizione
>
>tabella prezzi prodotto:
>id (chiave primaria) - idProdotto (chiave secondaria) - prezzo
Le tabelle strutturate così mi fanno pensare che ogni prodotto può avere più prezzi .... è così?
Se no .... bisogna che le strutturi in modo diverso ....
Ai fini del progetto di test non mi cambia la vita .... ma ho bisogno di saperlo ....

Facci sapere...
Ciao

andrestu Profilo | Expert

si certo ogni prodotto ha più prezzi e non solo, ci sono anche altre tabelle che si relazionano alla tabella prodotto allo stesso modo (in totale 3), ma per semplificare ho preso in considerazione solo quella prezzi.
A titolo informativo ogni prodotto può avere più prezzi, più colori e più immagini...

ciao e grazie

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

Ciao.
Ok allora stasera ti allego il progettino che ho fatto ieri sera...
Ciao

andrestu Profilo | Expert

ok grazie mille, così lo vedo e ti so dire...

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

Eccomi ...

Facci sapere...
Ciao

andrestu Profilo | Expert

ok grazie,
praticamente hai utilizzato la generazione automatica di classi partendo da un db (LINQ to Sql), dovrò mettermi a studiare un pò i dettagli di questa tecnologia prima di utilizzzarla, sarà la prossima mossa. Diciamo che l'implementazione delle classi generate è automatizzata dai vari tool resi a disposizione dall'ambiente di sviluppo se non ho capito male, ma ci sarebbe anche la possibilità di interagire modificando alcuni aspetti?
Per esempio se volessi un classe un pò differente da come lui la genera in automatico è difficile effettuare eventuali cambiamenti?
Cioè in poche parole si riescono a 'customizzare' nel dettaglio i vari aspetti di questa infrastruttura?

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

Ciao
>ma ci sarebbe anche la possibilità
>di interagire modificando alcuni aspetti?
Si purchè rispetti il mapping con il DataBase ...
>Per esempio se volessi un classe un pò differente da come lui
>la genera in automatico è difficile effettuare eventuali cambiamenti?
No ... purchè rispetti il mapping con il DataBase ...
>Cioè in poche parole si riescono a 'customizzare' nel dettaglio
>i vari aspetti di questa infrastruttura?
Si purchè rispetti il mapping con il DataBase ...

In poche parole .... VisualStudio, non fa altro che generare delle classi recuperando le informazioni dal DataBase.
Tali classi sono visibili all'interno di VisualStudio e quindi liberamente modificabili a piacere o, addirittura, si ha la possibilità di crearle "a manina".....purchè rispetti il mapping con il DataBase ... altrimenti non avrebbe senso.
Nell'esempio, io ho creato la classe Result_Prodotti, all'interno del file Form1.vb .... nessuna mi avrebbe vietato di creare un'altro oggetto (con le stesse caratteristiche) nel dataContext (DB.dbml).

Ciao

andrestu Profilo | Expert

purtroppo non riesco a capirlo molto bene VB perchè ho sempre utilizzato c#.
comunque da quello che ho potuto vedere la classe Result_Prodotti è l'equivalente ad un join, e qui ritorniamo al problema principale, io volevo una risultante classe un pò diversa e cioè:

Result_Prodotti
{
Public string IdProdotto { get; set; }
Public string Descrizione { get; set; }
Public IEnumerable<Prezzo> { get; set; }
}

Prezzo
{
Public string taglia { get; set; }
Public decimal prezzo { get; set; }
}

La risultante della query quindi dev'essere una collection di oggetti Result_Prodotti ognuno dei quali all'interno ha una collection di oggetti Prezzo.
Come lo avresti fatto?

Andrea Restucci - Web Developer

Jeremy Profilo | Guru

Ciao Andrea.
>purtroppo non riesco a capirlo molto bene VB perchè ho sempre
>utilizzato c#.
Non c'è problema .... posso convertirlo in C# .... ma concettualmente il discorso rimane lo stesso.
>comunque da quello che ho potuto vedere la classe Result_Prodotti
>è l'equivalente ad un join, e qui ritorniamo al problema principale,
>io volevo una risultante classe un pò diversa e cioè:
>
>Result_Prodotti
>{
>Public string IdProdotto { get; set; }
>Public string Descrizione { get; set; }
>Public IEnumerable<Prezzo> { get; set; }
Anche per questo non ci sono problemi ..... basta modificare la query. Sempre una sola query rimane.
Basta capire come vuoi organizzare i dati in output video.

>}
>
>Prezzo
>{
>Public string taglia { get; set; }
>Public decimal prezzo { get; set; }
>}
>
>La risultante della query quindi dev'essere una collection di
>oggetti Result_Prodotti ognuno dei quali all'interno ha una collection
>di oggetti Prezzo.
>Come lo avresti fatto?
Esattamente come nell'esempio che ti ho postato .... modificando leggermente la query.

Facci sapere...
Ciao

andrestu Profilo | Expert

si certo la query rimane sempre una, anche nel mio caso era solo una, quando intendevo 3 intendevo una collection.where(...) LINQ composta che al suo interno effettua a sua volta altre 3 .where(...). Forse mi ero spiegato male, penso che il risultato sia lo stesso alla fine


Andrea Restucci - Web Developer
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2017
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5