Ricerca 
it-ITen-US
Registrazione
Accedi
In-Vesti Dotnetwork
IN-VESTI DNW!!!
Sono finalmente arrivate le nuovissime T-Shirt di DotNetWork!!! Con soli 15,00 € ci sosterrai nelle spese di gestione della Community e ti invieremo a casa una splendida maglietta.
Se vuoi contribuire al mantenimento di DotNetWork.it Vai sulla pagina Iscrizioni
Effettua il pagamento usando IWBank
Click per andare alla pagina di Iscrizione
Oppure un Bonifico bancario (le coordinate sono sulla pagina Iscrizioni), inviaci una mail a support@dotnetwork.it indicandoci la tua taglia e l'indirizzo di spedizione.  Non appena verificata la ricezione del pagamento provvederemo a spedirti la tua T-Shirt.  Le magliette sono disponibili nelle taglie S-M-L-XL-XXL (in caso di esaurimento di una delle taglie, indica quella di "Backup"). Grazie per IN-VESTIRTI con NOI!!!
.:DotNetWork Founders:.
    Stampa     


DotNetWork Forums
SQL Query e impatto prestazioni
Ultimo Post 31 ago 2009 11.47 by Roberto Pajalunga. 15 Risposte.
Stampa immediata
Ordina:
PrevPrev ProssimoProssimo
Non sei autorizzato ad inviare una risposta.
Autore Messaggi Informativo

Posts:14

--
10 ago 2009 11.08  
Ciao a tutti!
Sono un newbie del sito e spero possiate aiutarmi.

Vengo subito al problema: ho un database molto "pesante" (siamo circa a 20 GB) dal quale la mia applicazione genera un DataSet con 3 tabelle contenenti ciascuna almeno un campo matrice di byte (file per intenderci). In una di queste tabelle il campo immagine contiene per ciascun record un file di circa 7,50 MB di media.

Per necessità posso scegliere quali gruppi omogenei di dati posso "acquisire" dal database, come pure posso acquisirli tutti in una sola fase.

Il problema è proprio qui: supponendo che il database sia ora composto da circa 3000 articoli come posso evitare che il software mi restituisca una OutOfMemoryException durante l'esecuzione del metodo Fill() sul dataAdapter? (Tutti i metodi e gli oggetti a cui faccio riferimento appartengono al namespace "OleDb")

Su piccole quantità di dati il software funziona egregiamente.

Su un volume come quello citato (che è destinato ad aumentare ) come posso risolvere? Avevo pensato ad alleggerire la query escludendo il campo immagine ed acquisire la singola "al volo" usando magari il metodo ExecuteScalar dell'oggetto Command ma le prestazioni lato server e lato client?


Qualcuno mi può aiutare? Grazie in anticipo!

Posts:662

--
10 ago 2009 13.22  
Tempo fa scrissi qualcosa al riguardo che ti riassumo:
1) Inserisci un nuovo campo nella tabella delle immagini di tipo testo 40 caratteri
2) Tutte le volte che aggiorni il campo BLOB contenente l'immagine calcolati l'HASH dell'immagine e salvalo in quel campo
3) Quando hai necessità di recuperare l'immagine verifica se sul PC client hai un'immagine il cui nome file è uguale all'HASH salvato nel campo
4) Se hai l'immagine carica quella
5) Se non hai l'immagine recuperala da DB, salvala sul client locale e utilizzala.
6) Se hai problemi ad interpretare questo consiglio fai un fischio!
HTH
Alberto

Posts:14

--
10 ago 2009 14.27  
Ciao Alberto!

Innanzitutto volevo ringraziarti per la risposta così celere!

Forse è meglio che faccia più chiarezza sulla situazione generale.

Il software che ho realizzato genera cataloghi, volantini, ecc.

Data la quantità di immagini che ho la necessità di gestire e il numero di persone che possono usare il software è maggiore di 2 (per cui potrebbero usare anche una sola postazione o un landisk) ho optato per l'archiviazione su DB.

La lettura delle immagini è quindi un'operazione molto pesante e non occasionale. La possibilità di generare un catalogo completo (allo stato attuale circa 3000 articoli) è pressoché uno standard circa una volta al mese.

I client non hanno però particolari problemi di spazio per l'archiviazione anche se sarebbe abbastanza traumatico per il server estrarre tutte le immagini dal db e quindi escludere il campo.

La mia perplessità principale vergeva sullo stress del server ospitante il database se usassi la funzione ExecuteScalar dell'oggetto OleDbCommand. In pratica: può essere una soluzione valida ai fini della risoluzione (anche solo temporanea) della mia problematica senza un impatto negativo sul server oppure devo ripiegare necessariamente su archiviazione locale?

Grazie!

Posts:662

--
10 ago 2009 14.45  
La mia perplessità principale vergeva sullo stress del server ospitante il database se usassi la funzione ExecuteScalar dell'oggetto OleDbCommand. In pratica: può essere una soluzione valida ai fini della risoluzione (anche solo temporanea) della mia problematica senza un impatto negativo sul server oppure devo ripiegare necessariamente su archiviazione locale?
Richiamare la funzione ExecuteScalar per n volte equivale (all'incirca) a richiamare una query con n righe eccetto per errori di timeout. Da un punto di vista di stress di Db non penso che cambi molto. Quello che io ti consigliavo nn è tanto la memorizzazione su una condivisa quanto il "portare lato client" le immagini solo quando ce ne dovesse essere bisogno, ovvero attraverso una verifica sull'hash del file da trasportare. Quindi le immagini sono sempre memorizzate lato server sul database (p.s.... in sql 2008 i campi immagine sono ottimizzati, chiedi a sabri che è l'esperta) solo che l'operazione dilettura avviene solo dietro verifica di modifiche da parte di altri utenti, altrimenti è assurdo tutte le volte trasportare in memoria tonnellate di byte da e su un db solo perchè qualcuno ha modificato un'immagine.
HTH
Alberto.

Posts:662

--
10 ago 2009 14.45  
La mia perplessità principale vergeva sullo stress del server ospitante il database se usassi la funzione ExecuteScalar dell'oggetto OleDbCommand. In pratica: può essere una soluzione valida ai fini della risoluzione (anche solo temporanea) della mia problematica senza un impatto negativo sul server oppure devo ripiegare necessariamente su archiviazione locale?
Richiamare la funzione ExecuteScalar per n volte equivale (all'incirca) a richiamare una query con n righe eccetto per errori di timeout. Da un punto di vista di stress di Db non penso che cambi molto. Quello che io ti consigliavo nn è tanto la memorizzazione su una condivisa quanto il "portare lato client" le immagini solo quando ce ne dovesse essere bisogno, ovvero attraverso una verifica sull'hash del file da trasportare. Quindi le immagini sono sempre memorizzate lato server sul database (p.s.... in sql 2008 i campi immagine sono ottimizzati, chiedi a sabri che è l'esperta) solo che l'operazione dilettura avviene solo dietro verifica di modifiche da parte di altri utenti, altrimenti è assurdo tutte le volte trasportare in memoria tonnellate di byte da e su un db solo perchè qualcuno ha modificato un'immagine.
HTH
Alberto.

Posts:662

--
10 ago 2009 14.45  
La mia perplessità principale vergeva sullo stress del server ospitante il database se usassi la funzione ExecuteScalar dell'oggetto OleDbCommand. In pratica: può essere una soluzione valida ai fini della risoluzione (anche solo temporanea) della mia problematica senza un impatto negativo sul server oppure devo ripiegare necessariamente su archiviazione locale?
Richiamare la funzione ExecuteScalar per n volte equivale (all'incirca) a richiamare una query con n righe eccetto per errori di timeout. Da un punto di vista di stress di Db non penso che cambi molto. Quello che io ti consigliavo nn è tanto la memorizzazione su una condivisa quanto il "portare lato client" le immagini solo quando ce ne dovesse essere bisogno, ovvero attraverso una verifica sull'hash del file da trasportare. Quindi le immagini sono sempre memorizzate lato server sul database (p.s.... in sql 2008 i campi immagine sono ottimizzati, chiedi a sabri che è l'esperta) solo che l'operazione dilettura avviene solo dietro verifica di modifiche da parte di altri utenti, altrimenti è assurdo tutte le volte trasportare in memoria tonnellate di byte da e su un db solo perchè si presume che qualcuno abbia modificato un'immagine.
HTH
Alberto.

Posts:14

--
10 ago 2009 15.18  
Ho capito quello che mi dici.

Il "portare lato client" le immagini solo quando ce ne dovesse essere bisogno comporta il salvataggio di tutte le immagini del db sul client e poi successivamente di aggiornarle qualora ce ne fosse la necessità.

lavorando in ambiente di dominio ho notato qualche problema a livello di autenticazione sulle cartelle è un altro motivo per cui ho lasciato le immagini sul server.

Comunque in teoria tu mi consigli di tenerle in locale (visto il multi-user preferirei su una condivisione così da non sovraccaricare i client) e richiamarle da lì.

Per l'accesso a cartelle di dominio come faccio per le autorizzazioni. Avevo trovato qualcosa in giro riguardo alla possibilità di impersonare un altro utente dall'applicazione. Però con questa domanda penso di essere OT.

Posts:662

--
10 ago 2009 15.32  
Per l'accesso a cartelle di dominio come faccio per le autorizzazioni. Avevo trovato qualcosa in giro riguardo alla possibilità di impersonare un altro utente dall'applicazione. Però con questa domanda penso di essere OT.
Hai provato a scrivere nella cartella MyPicture dell'utente? A meno che tu non abbia un amministratore di dominio che lavorava ad Alcatraz (ed ione conosco uno che almeno a Regina Coeli ha lavorato ) dovresti poterci scrivere... altrimenti non so cosa dirti... impersonificare un utente può essere più rognoso che non salvare le immagini in locale quando si lavora in un dominio... indubbiamente salvandole in locale puoi salvare le modifiche temporanee senza dover per forza inviare le modifiche a database...
Non saprei cosa dirti oltre, non conoscendo chiaramente tutta l'architettura della soluzione...
Se ci dai maggiori elementi riguardo all'architettura, vediamo se riusciamo fra tutti a consigliarti per il meglio.
Alberto.

Posts:14

--
10 ago 2009 15.58  
Uhm... vediamo se riesco a dare tutte le informazioni:

->Server di dominio (non PDC) con SQL Server 2005 Standard
--->Database con utente specifico (autenticazione sql server) per l'accesso
----->Tabelle contenenti gli articoli e le categorie e relative immagini

Lato client l'applicazione registra e modifica le categorie e gli articoli (con le relative immagini) ciclicamente e max 10 art. al mese (tranne in fase di startup ovviamente). I client sono al momento due ma dovrebbero aumentare in un futuro prossimo.
La procedura più pesante è la generazione del catalogo: questa può essere fatta anche settimanalmente per alcune categorie; mensilmente o con periodicità meno frequente per il catalogo completo.

Per cataloghi piccoli il software funziona perfettamente da database. Per il catalogo completo (che è quello fondamentale) il programma restituisce (usando un backgroundworker) OutOfMemoryException.
La generazione del catalogo si compone di varie fasi:
1. generazione del dataset contenente categorie selezionate e articoli (con immagini);
2. stampa attraverso un printdocument personalizzato in grado di elaborare le immagini contenute nel dataset che gli viene passato (stampa su file *.ps);
3. altre fasi eseguite da un applicazione esterna.

Finito viene generato un file (es.: pdf) con il catalogo pronto per la stampa.

L'eccezione viene generata proprio sul primo punto.

L'applicazione in teoria è già predisposta per leggere le immagini da un percorso specifico ma in termini di tempo ho visto dei rallentamenti notevoli oltre a problemi di scrittura (penso derivanti dalle autorizzazioni).

Se hai bisogno di altre informazioni sono qui.

Posts:662

--
10 ago 2009 16.07  
Se hai bisogno di altre informazioni sono qui.
Soltanto una: con che frequenza viene generato il catalogo generale?

Posts:14

--
10 ago 2009 16.10  
Teoricamente una volta al mese, però potrebbero anche decidere di farlo con frequenza maggiore...

Posts:662

--
10 ago 2009 16.39  
Allora non hai grossi problemi io credevo che fosse un aggiornamento molto + frequente... a questo punto, secondo me, la cosa migliore da fare è recuperare i dati in due tempi, caso mai usando un'elaborazione asincrona per non bloccare il thead principale. Quindi:
1) Recuperi tutti i campi in una datatable dataset eccetto il campo BLOB
2) Esegui un for each sulle Rows della datatable richiamando un executescalar parametrizzato sull'ID di riga per caricare nella DataRows del foreach il campo BLOB dal db
3) Su ogni DataRow aggiorni il campo BLOB.
Occhio a non caricare dei DataSet immensi in locale... altrimenti l'outofmemory ce l'hai lato client...
Se così dovesse accadere allora stampati il catalogo dividendolo in due
HTH
Alberto.

Posts:662

--
10 ago 2009 16.41  
P.S. Quando leggi il campo BLOB con l'execute scalar c'è un parametro da passare (Behaviour) per dirgli di leggere il campo (che poi recuperi copn GetBytes) in maniera sequenziale... usa questa modalità che è ottimizzata per i dati di grosse dimensioni.
Spero sia tutto...
P.S.S.... Benvenuto tra di noi!
Alberto.

Posts:14

--
10 ago 2009 17.03  
Grazie per l'aiuto, per la pazienza e per l'accoglienza!

Spero di poter aiutare anch'io con la mia umile e modesta esperienza!

Mi metto subito a fare i test.

Posts:14

--
12 ago 2009 18.18  
Ciao a tutti....

Ho risolto un errore ma ora se ne presenta un altro.

Ora quando arrivo su ExecuteScalar (il parametro behavior da impostare probabilmente nell'oledb non c'è ) ora mi restituisce il seguente "Errore non specificato".

Leggendo lo stack (di cui sotto) e sapendo come si deve comportare il programma (deve cioè ciclare i DataRow ed ottenere il campo immagine direttamente) mi pare di capire che non abbia il tempo di completare l'operazione andando in errore.

Lo stralcio di codice che uso lo metto dopo lo stack.

---------------- INIZIO: STACK --------------------------
SOURCE: Microsoft OLE DB Provider for SQL Server
MESSAGE: Errore non specificato.
STACK: in System.Data.OleDb.OleDbDataReader.ProcessResults(OleDbHResult hr) in System.Data.OleDb.OleDbDataReader.GetRowHandles() in System.Data.OleDb.OleDbDataReader.ReadRowset() in System.Data.OleDb.OleDbDataReader.Read() in System.Data.OleDb.OleDbDataReader.HasRowsRead() in System.Data.OleDb.OleDbDataReader.NextResult() in System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method) in System.Data.OleDb.OleDbCommand.ExecuteScalar() in rpPrinting.rpPrintDocument.PrintCustomObjects(Point coord, Object custom, PrintPageEventArgs e, String tablename, rpPrintableTable baseobject) in F:\eCatalog\rpPrinting\clsPrintDocument.vb:riga 2613 in rpPrinting.rpPrintDocument.PrintObjects(Object container, PrintPageEventArgs e, String tablename) in F:\eCatalog\rpPrinting\clsPrintDocument.vb:riga 2272 in rpPrinting.rpPrintDocument.PrintingControl(Object sender, PrintPageEventArgs e) in F:\eCatalog\rpPrinting\clsPrintDocument.vb:riga 1785
----------------  FINE: STACK  --------------------------

---------------- INIZIO: CODICE ------------------------
If .ContentType = rpContentType.Immagine Then
If Not .DBDirectAccessKey Is Nothing And String.IsNullOrEmpty(_connstr) = False Then
Dim _dbdaksql As String = "SELECT {0} FROM {1} WHERE {2} = {3}"
_dbdaksql = String.Format(_dbdaksql, .Value, .DBDirectAccessKey.TableName, .DBDirectAccessKey.IDFieldName, Me.DataSource.Tables(tablename).Rows(progrRec).Item(.DBDirectAccessKey.IDFieldName))
If _oleconn.State = ConnectionState.Broken Then
_oleconn.Close()
End If
If _oleconn.State = ConnectionState.Closed Or _oleconn.State = ConnectionState.Broken Then
_oleconn.Open()
End If
Dim _dbdakcmd As New OleDb.OleDbCommand(_dbdaksql, _oleconn)
Dim _dbdakobj As Object
_dbdakobj = _dbdakcmd.ExecuteScalar
Application.DoEvents()
_bytes = CType(_dbdakobj, Byte()).Length
_img = GetImageFromByte(_dbdakobj)
Application.DoEvents()
_dbdakcmd.Dispose()
Application.DoEvents()
GC.Collect()
End If
End If
----------------  FINE: CODICE  ------------------------

Posts:14

--
31 ago 2009 11.47  
Nessuno mi sa aiutare?
Non sei autorizzato ad inviare una risposta.

Active Forums 4.1
       
Articoli
Unit testing del codice (parte 2)
Generiamo alcuni unit test per la libreria Helper base ADO.NET
2008/03/09 | Autore: Sabrina Cosolo
Fritto Misto - Classi di uso comune(parte 4)
Helper: Una classe per il log di eventi, con evento, event handler, enumerazione.
2007/10/24 | Autore: Sabrina Cosolo
.NET e l'Interoperabilità COM
Come utilizzare Dll non referenziabili per convertire un documento Word in PDF
2008/07/05 | Autore: Massimo Lofrano
Codedom Introduzione all'uso parte3
La classe Helper per le funzionalità CodeDom
2009/11/07 | Autore: Sabna Cosolo
Briciole di ereditarietà
Come aggiungere ulteriori funzionalità alla TreeView personalizzata
2009/06/05 | Autore: Francesca Mazzoni
ADO.NET Funzionalità di base
Effettuare una ricerca su recordset disconnessi tramite DataView
2007/12/02 | Autore: Andrea Zingoni
L'Albero degli elementi
Come iniziare a capire com'è fatto WPF (parte 3)
2007/08/13 | Autore: Patrizia Cosolo
Iniziare da zero con Visual Studio
Introduzione a .NET e Visual Studio
2007/07/29 | Autore: Sabrina Cosolo
    Stampa     
Home|Forums|Blogs|Mappa del sito
© 2007-2012 by DotNetWork  .:.  Condizioni d'uso  .:.  Privacy  .:.  Accedi  .:.