Newsgroup: it.comp.lang.visual-basic
Titolo: Velocizzare routine

Ciao a tutti,
ho scritto una routine ricorsiva che mi va a sommare le quantità di alcuni
articoli che sono composti a sua volta di articoli.
La tabella è FDBASE così composta
IDDBASE numeric(indicizzato)
NART numeric(indicizzato)
NARTBASE come sopra
CODDB string
QTA decimal
Ed è così composta
NARTBASE	NART	QTA
1		55	1
1		56	2
1		57	0.5
55		105	1
55		106	2
105		999	3
In pratica se parto con l'articolo 1 qta=1 mi trova
56x2
57x0.5
106x2
999x3
E non considera quelli che hanno sotto livelli cioè
1x1
55x1
105x1	
Il fatto è che è una routine molto lenta, circa 45secondi per 4000
iterazioni. Avete qualche idea per far meglio? Ho già provato con parametri
per il recordset (adcmdtable ecc), a sostituire la connection.execute con
un command, ma niente.
L'apertura di RS è comunque istantanea, come fare un i=i+1, quindi non
penso sia lì il problema
Grazie a tutti
Public Sub Esplodi(idArt As String, qtaMadre As Currency, ByVal Level As
Integer)
'Routine ricorsiva che mi prende tutti i righi
'di dBase per ogni Articolo
Dim qtaDB As Currency
Dim Rs As ADODB.Recordset
Set Rs = New ADODB.Recordset
Rs.ActiveConnection = ADOCn
If Val(idArt) = 0 Then Exit Sub
Level = Level + 1
Rs.Source = "SELECT FDBASE.NART,FDBASE.QTA AS QTADBASE FROM FDBASE WHERE
CODDB='MP' AND FDBASE.NARTBASE=" & Val(idArt$)
Rs.Open
If Not Rs.EOF Then
  Do Until Rs.EOF
    If idArt$ <> NoNull(Rs("NART")) Then
      qtaDB = Val(UsaPunto(NoNull(Rs("QTADBASE"))))'formatto decimal
      qtaDB = qtaDB * qtaMadre
      If qtaDB <> 0 Then
        Call Esplodi(NoNull(Rs("NART")), qtaDB, Level)
      End If
    End If
    Rs.MoveNext
  Loop
Else
  ADOCn.Execute "INSERT INTO STAMPA" & NODO & " (IDART,QTAR) VALUES (" & _
    Val(idArt) & "," & VerificaNull(UsaPunto(Val(str(qtaMadre)))) & _
    ");"
End If
Rs.Close
Set Rs = Nothing
End Sub

 iterazioni. Avete qualche idea per far meglio? 
Utilizzare la ricorsione è già per definizione più lenta della sua 
versione iterativa, poi usarla in VB significa peggiorare le condizioni
ancora di più!
Usa la versione iterativa e vedrai già di quanto migliora il tempo.

 Usa la versione iterativa e vedrai già di quanto migliora il tempo.
Scusa l'ignoranza ma come sarebbe iterativa?
Il fatto è che con la mia funzione scandisco N livelli senza limiti, se mi
fermo a 2/3 livelli potrebbe non bastarmi in qualche caso (immagino
iterativa sia in questo senso).
Il problema di quella sub è che fa una select per ogni ultimo livello che
non ha sottolivelli, per verificare che non ne abbia, quindi il Rs.EOF=true
e procede alla INSERT INTO.
Probabilmente dovrei trovare il modo di caricare in memoria tutta la
tabella FDBASE e vedere se con la adors.filter migliora qualche cosa...

 iterativa sia in questo senso).
Iterativa non significa statica...
Significa senza richiamare se stessa, ma è lo stesso dinamica.
VB non è fatto per funzioni ricorsive, se non per pochi
livelli o per poche sempici operazioni.

 penso sia lì il problema
Io non lo escluderei a priori...
Prova a non ricreare gli oggetti Recordset ad ogni "iterazione". Fallo una volta
sola, dichiarando la variabile a livello di modulo.
Il RS lo riempi una volta per tutte dopo averlo creato con una query senza la
condizione su FDBASE.NARTBASE.
Infine, all'interno della routine ricorsiva, per selezionare di volta in volta
le righe con il FDBASE.NARTBASE che ti interessa, usa la proprietà Filter del
recordset.
HTH
Raf

 105		999	3
Come ti hanno suggerito prova la soluzione iterativa e non solo.
Dovresti delegare il maggior lavoro possibile al db, perchè è
ottimizzato per lavorare sulle ricerche.
In questo senso puoi provare la routine che qui di seguito ti esplicito
senza garanzia di funzionamento (non l'ho provata).
In pratica prima fa eseguire la somma delle quantità di ciascun
NARTBASE al DB e poi colleziona i relativi NART per prepararsi alla
ricerca successiva.
Il codice sarà sicuramente più esplicativo (a partire dal tuo
proposto).
------------------------------------------------------------------------------------------
Public Function Esplodi(idArt As String) as Currency
	Dim qtaDB As Currency
	Dim listaId as String
	Dim Rs As ADODB.Recordset
	If Val(idArt) = 0 Then Exit Sub
	qtaDB=0
	listaId=idArt;
	do while (listaId<>"")
		' *** Raccolgo la somma delle quantità per tutti i prodotti che
hanno NART nella listaId
		strSQL="SELECT NARTBASE,SUM(QTA) as QTATOTALE FROM FDBASE WHERE
NARTBASE IN (" & listaId & ") GROUP BY NARTBASE"
		set Rs=ADOCn.Execute(strSQL)
		qtaDB=qtaDB+Rs.Fields("QTATOTALE").value
		' *** Raccolgo tutti gli NART che hanno NARTBASE nella listaId
		listaId=""
		strSQL="SELECT NART FROM FDBASE WHERE NARTBASE IN (" & listaId & ")"
		set Rs=ADOCn.Execute(strSQL)
		Do while not rs.eof
			if (listaId="") then
				listaId=rs.fields("NART").value
			else
				listaId=listaId & "," & rs.fields("NART").value
			end if
			call rs.movenext
		Loop
	loop
	Set Rs = Nothing
	Esplodi=qtaDB
End Sub
------------------------------------------------------------------------------------------------------
Fammi sapere.
Ciao,
     Fabrizio

 un command, ma niente.
Scusate se rispondo solo ora.
Ho keepato i messaggi, purtroppo per ora ho accantonato il programma causa
urgenze, dato che mi è stato detto che quel tipo di stampa viene fatta su
1/10 documenti alla volta, e quindi in 5/10 secondi se la cava per ora.
Non appena ho tempo vedrò di modificarla come mi avete consigliato.
Grazie ancora a tutti