Newsgroup: it.comp.lang.visual-basic
Titolo: Passaggio records

Un saluto ai luminari del NG :)
c'è un modo più veloce di passare un record tra due tabelle, di due database 
diversi, in vb6 ed access2000?
I records sono quasi 200.000, i fields sono 24 per cui 200.000 x 24 = 
4.800.000 scritture
Io uso questa ma mi ci vogliono più di 7 minuti.
For y = 0 To DataRin.Recordset.Fields.Count - 1
    DataRout.Recordset(y) = DataRin.Recordset(y)
Next y
Ho provato anche senza l'oggetto data, semplicemente col recordset ma non 
cambia nulla.
qualche suggerimento?
grazie 

 qualche suggerimento?
1. metti i due db sullo stesso disco;
2. fai girare il programma sulla stessa macchina dove si trova il disco;
3. esegui su un mdb una istruzione INSERT INTO con la SELECT che pesca
i dati dall'altro mdb.
non mi viene in mente nient'altro che possa andare piů veloce, a parte
usare un pc ben carrozzato.
-- 
ciao, hal

 Next y
Per prima cosa prova ad ottimizzare i cursori. Il recordset di lettura 
potresti impostarlo ForwardOnly ReadOnly e, prima di aprirlo, aumentarne la 
cache.
Il recordset in scrittura impostalo Static Pessimistic.
Anzi, giusto per toglierci qualche curiosita' e ringraziarci di averti 
aiutato...fai un esperimento per noi ;-D
Prima prova il metodo descritto sopra e misura quanto ci mette.
Poi, il modo estremamente piu' veloce dovrebbe essere:
1) Apri il recordset di lettura, Static e ReadOnly
2) Settane l'activeconnection a NULL
3) Apri il recordset di destinazione, Static NonmiricordosarcazzoBatch
4) Settane l'activeconnection a NULL
5) Fai la copia
6) Riattacca la connessione al recordset di destinazione
7) UpdateBatch
Dai, poi ci dici quanta differenza c'e' tra i due metodi :-)

 non mi viene in mente nient'altro che possa andare più veloce, a parte


> Io uso questa ma mi ci vogliono più di 7 minuti.


 così imparo qualcosa di nuovo :).
No problem, stasera mi fa decisamente piacere. Pero' in caso di dubbio 
rispondimi in fretta, che poi domani parto e riento martedi' e nun te posso 
rispiega' nulla :-)
(prima le spiegazioni simil-teoriche, in fondo quelle visualbesiche)
Allora...
Al di la' di quali operazioni fai per scegliere i record dalla tabella di 
input (che probabilmente sono ottimizzabili, ma sinceramente del tuo mex di 
risposta ad hal ho capito una sillaba si e dieci no), l'ottimizzazione 
migliore che puoi fare e' quella a livello di cursori. SE non sai cosa sono 
i cursori dei dataset non e' il caso che te li spiego qui in dieci righe, 
quindi in quel caso prendi per buono quello che ti dico.
(cmq, in breve ed i puristi potrebbero impiccarmi: i cursori indicano il 
modo in cui il db deve trattare i dati)
Ti avevo proposto due metodi.
1)
Prima cosa...il recordset che pesca i dati dal db. Tu hai in sostanza 
un'elenco di record che vuoi leggere in ordine, uno dopo l'altro, e di cui 
non ti interessa se qualcuno li modifica mentre tu li leggi (perche', si 
spera, un'operazione del genere avviene mentre nessuno lavora).
La prima ottimizzazione e' quindi usare un cursore di tipo ForwardOnly. 
Questo tipo di cursore dice ad ADO che tu vuoi metterti in memoria una copia 
pari pari dei record e scorrerli SOLTANTO IN AVANTI. Solo con il movenext, 
per intenderci. Risultato, in questo modo lo scorrimento di 200.000 record 
e' molto piu' veloce.
Se poi gli dici che il recordset deve essere ReadOnly e' ancora meglio. 
Infatti ti genera un recordset ancora piu' veloce da scorrere in quanto ADO 
non si costruisce tutte le strutture che gli servono in caso tu aggiornassi 
il recordset (readonly->sola lettura)
Ora, seconda cosa: il recordset che scrive i dati.
Anche qui, si ottimizza sui cursori e sulla modalita' di accesso. In primis 
usando un cursore di tipo Static, e non mi chiedere qui di spiegarti cosa 
fa' perche' altrimenti ci stiamo una vita...diciamo solo che in questo caso 
e' piu' veloce.
Poi si indica che vuoi un recordset Pessimistic. Che significa "ADO, blocca 
la tabella che ci lavoro solo io". In questo modo ADO non sta' a 
preoccuparsi piu' di tanto di controllare che i record che vai a scrivere 
siano in qualche modo influenzati da qualche altro inserimento/modifica.
Risultato: il tutto dovrebbe essere molto piu' veloce.
Secondo metodo
2)
Si chiamano "recordset disconnessi".
In parole povere...
Tu apri un recordset per l'input dei dati. ADO legge i primi 100 record e te 
li passa (proprieta' Cache dell'oggetto ADO). Man mano che tu scorri il 
recordset, lui recupera gli altri record. Quindi, oltre ai vari tempi di 
lettura dei dati, c'e' una lentezza dovuta al fatto che ogni volta che 
recupera un blocco di recordset ADO accede al disco, gli dice che dati 
vuole, li mastruzza per metterli dentro il recordset (a cui tu stai nel 
frattempo lavorando)...
Un recordset disconnesso e' molto piu' veloce, semplicemente perche': ADO 
apre il recordset, lo copia tutto in memoria, poi si sgancia dal DB. Cosi', 
quando lo scorri, lo scorri in RAM invece che sul disco. MOOOOOLTO piu' 
veloce.
Stessa cosa, ma ancora meglio, con il recordset in scrittura: ogni volta che 
tu crei un nuovo record ADO deve scriverlo fisicamente sul disco. Se deve 
scrivere 200.000 record, significa che si trova a fare 200.000 accessi al 
disco e relative scritture.
E se invece usi i recordset disconnessi? Semplice, elabori tutto quanto in 
memoria e poi quando lo riagganci il recordset al DB ADO scrive tutti i dati 
in un colpo solo.
Sostanza...come si fa?
1) Per definire i cursori...sono i parametri che hai nella Open. Hanno dei 
nomi simili a quanto ti ho scritto sopra, solo che iniziano per ad.
In ogni caso hai i suggerimenti automatici, quindi no problem.
2) Per lavorare sui recordset disconnessi...
Ogni recordset ha una proprieta' ActiveConnection.
Dopo aver aperto il recordset, per disconnetterli ti basta usare
set recDati.ActiveConnection = Nothing
Poi, quando hai finito di fare le tue modifiche, basta che fai
set recDati.ActiveConnection = oggetto connessione da cui avevi aperto il 
recordset
e
recDati.UpdateBatch
Quest'ultima istruzione fa tutta la scrittura in un botto solo.
Spero di essermi spiegato decentemente, in ogni caso se vuoi lavorare 
seriamente con ADO procurati un buon libro o qualche tutorial...
(amo ADO, non so' se si capisce... :-D )

 ha scritto nel messaggio 
news:6aV%f.83174$PR2.1...@twister2.libero.it...
P.S., mi sono scordato un passaggio fondamentale...
Devi valutare anche l'occupazione di memoria, ed eventualmente girarci 
intorno. Abbiamo detto che quando usi un rs disconnesso, ADO lo copia 
interamente in memoria.
Con 200.000 record, anche a solo 1k a record, sono 195 mega di roba...per 
due recordset, uno in lettura ed uno in scrittura sono -teoricamente- 390 
mega.
Perche' ho scritto TEORICAMENTE?
Perche' e' qui che mi ero scordato il passaggio...
Se scrivi 200.000 records alla volta nella tabella di destinazione, a parte 
che esplode il db alla seconda scrittura, quando poi apri il recordset per 
l'output e lo disconnetti, ADO si copia in memoria TUTTI i record gia' 
presenti...magari 600.000 records, 585 mega di roba. Poi te vai ad 
aggiungercene altri 200.000 e siamo a 781 mega. Addio ottimizzazioni :-)
Quindi, quando apri il recordset di destinazione, ricordati di aprirlo con 
la condizione "WHERE 1=0"...altrimenti stai fresco
:-D

 ha scritto

dato che 7' mi sembravano molti, ho fatto qualche prova con una tabella di 
quasi 175mila righe.
vb6, access2000, dao3.6.
i campi sono meno, ma i tempi sono comunque molto diversi, vedi sotto.
il db sorgente fa piu' di 500mb, ho varie altre cose aperte, quindi in ram 
tutto non ci sta.
Option Explicit
Private Sub Command1_Click()
    Dim db1 As Database, rs1 As Recordset
    Dim db2 As Database, rs2 As Recordset
    Set db1 = OpenDatabase(App.Path & "\dc2000.mdb")
    Set rs1 = db1.OpenRecordset("dir")
    Set db2 = OpenDatabase(App.Path & "\db1.mdb")
    Set rs2 = db2.OpenRecordset("dir")
    Dim j As Long, cnt As Long
    Dim time1 As Long: time1 = Timer
    With rs1
        Do While Not .EOF
            rs2.AddNew
            For j = 0 To .Fields.Count - 1
                rs2.Fields(j) = rs1.Fields(j)
            Next
            rs2.Update
            cnt = cnt + 1
            Text1 = Format(cnt, "###,###") & " - " & Format(Timer - time1, 
"##0.00"): DoEvents
            .MoveNext
        Loop
    End With
    rs1.Close: Set rs1 = Nothing
    db1.Close: Set db1 = Nothing
    rs2.Close: Set rs2 = Nothing
    db2.Close: Set db2 = Nothing
End Sub
Private Sub Command2_Click()
    Dim time1 As Long: time1 = Timer
    Dim db1 As Database
    Set db1 = OpenDatabase(App.Path & "\dc2000.mdb")
    Dim s As String
    s = "insert into dir in 'c:\copy\db1.mdb' select * from dir"
    db1.Execute s
    Text1 = Format(Timer - time1, "##0.00")
    db1.Close: Set db1 = Nothing
End Sub
ciclo: 174.924 - 37,03 'con doevents a ogni giro
sql: 13,59
ho visto dai tuoi post successivi che in realta' la sorgente non e' * ma una 
selezione, ma in questo momento sono troppo fuso per ragionarci :)
hth, notte, a.

 una selezione, ma in questo momento sono troppo fuso per ragionarci :)
Permettimi...e' un test falsato.
Nel primo caso hai due format, due cast da variant a stringa, due 
concatenazioni di stringa e sopratutto uno switch di contesto per ogni 
ciclo.
Nel secondo caso non hai niente di tutto questo.
Ovviamente i risultati non sono paragonabili...certo, probabilmente la 
differenza rimane, ma non cosi' elevata.

 differenza rimane, ma non cosi' elevata.
se intendi che col ciclo e' piu' lento, prove (di vario tipo) in questi anni 
ne abbiamo fatte a bizzeffe, non solo io.
1. il doevents non e' detto incida. sono piu' che certo che a volte i cicli 
erano piu' veloci *con* il doevents che senza, e ho postato qui di 
conseguenza.
2. quanto alla differenza, in questo periodo ho potuto verificare che con 
query scritte bene la differenza potrebbe essere *molto* piu' marcata. cicli 
di 2' diventavano query di 2".
GeorgeDomotico ha poi detto che ha vari parametri. non ci sono stato su, ma 
nel ciclo diventerebbero parecchi if, e quelli si', rallenterebbero, molto 
piu' di una query group/when.
questo l'ho scritto poco fa, col caffe'.
ora ho provato a mettere il timing solo alla fine del ciclo, dopo end with:
174.924 - 36,63
come ti dicevo, il doevents incide poco e niente.
comunque, quello che mi premeva era che 7' per 200k righe mi sembrano tanti.
ciao, a.

 interamente in memoria.
se proprio vuoi la velocita', per due file *su disco locale*, butta via ado. 
le query dao le hai finite nel tempo che ado apre la connessione :P
ciao, a. 

 ha scritto nel messaggio 
news:4abg9gF...@individual.net...
