Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

VB6 : performance des recordsets avec ADO ?

4 réponses
Avatar
teddy
Bonjour à tous,

J'ai de sérieux problème de performance avec un programme écrit en VB6 qui
donne satisfaction dès lors qu'on manipule des tables de moins de 30000
enregistrements.

J'ai depuis peu des tables de 300000 enregistrements et là, le temps de
traitement n'est pas multiplié par 10 mais plutôt par 50 !!
Ca marche, mais c'est d'une lenteur à mourir :-((

Mon traitement est simple : je parcours un recordset qui est une vue des
champs utiles d'une table.
Dans chaque enregistrement, je mets à jour un champ particulier en tenant
compte des 14 enregistrements précédents préalablement mémorisés dans un
tableau.

Le traitement met 7 à 8 minutes pour parcourir et mettre à jour (si les
conditions sont remplies) les 30000 enregistrements stockés dans une table
de base Access créée par l'application elle-même via ADOX.
Il faut une nuit maintenant (6 à 8 heures) pour 300000.

J'utilise juste les champs nécessaires, un curseur ForwardOnly (le +
rapide), une requête SQL de mise à jour avec un Connection.Execute MaRequête
: les champs sont repérés par leur numéros RecordSet.Field(NoChamp), pas
d'affichage de bargraph ou autre...

Auriez-vous eu ce genre de soucis, faut-il remplacer la base Access par SQL
SERVER par exemple (c'est faisable puisque mon programme se connecte via ADO
à la base).
Merci beaucoup pour vos suggestions.

Teddy

4 réponses

Avatar
parci
On 22 jan, 00:16, "teddy" wrote:
Bonjour à tous,

J'ai de sérieux problème de performance avec un programme écrit en VB6 qui
donne satisfaction dès lors qu'on manipule des tables de moins de 30000
enregistrements.

J'ai depuis peu des tables de 300000 enregistrements et là, le temps de
traitement n'est pas multiplié par 10 mais plutôt par 50 !!
Ca marche, mais c'est d'une lenteur à mourir :-((

Mon traitement est simple : je parcours un recordset qui est une vue des
champs utiles d'une table.
Dans chaque enregistrement, je mets à jour un champ particulier en tena nt
compte des 14 enregistrements précédents préalablement mémorisé s dans un
tableau.

Le traitement met 7 à 8 minutes pour parcourir et mettre à jour (si l es
conditions sont remplies) les 30000 enregistrements stockés dans une ta ble
de base Access créée par l'application elle-même via ADOX.
Il faut une nuit maintenant (6 à 8 heures) pour 300000.

J'utilise juste les champs nécessaires, un curseur ForwardOnly (le +
rapide), une requête SQL de mise à jour avec un Connection.Execute Ma Requête
:  les champs sont repérés par leur numéros RecordSet.Field(NoCha mp), pas
d'affichage de bargraph ou autre...

Auriez-vous eu ce genre de soucis, faut-il remplacer la base Access par S QL
SERVER par exemple (c'est faisable puisque mon programme se connecte via ADO
à la base).
Merci beaucoup pour vos suggestions.

Teddy



Bonjour,

si je comprends bien tu es obligé de parcourir toute la table parce
que la mise à jour d'un enregistrement dépend des 14 enregistrements
précédents. Je crains que ce type de contrainte ne soit trop
pénalisant, quelque soit la base relationnelle ou les optimisations du
code (curseur ForwardOnly + Sql Update c'est très bien). Est-ce qu'on
peut avoir une idée du modèle de données ?
Avatar
teddy
C'est 1 table unique qui est une sorte de LOG d'événements triés selon 2
champs codes numériques et selon la Date/Heure d'évènement.

Donc pas de schéma compliqué avec des jointures dans tous les sens, de
contraintes sur des champs, de triggers, d'interdépendance de tables,
etc...

Je parcours le recordset en mémorisant les valeurs de 3 champs dans les 14
précédents enregistrements (tableau de 14 lignes "glissant"). C'est comme
une "fenêtre de visualisation" de 14 enregistrements que je déplace dans le
recordset du début à la fin.

Je pense que le fait de comparer des valeurs avec celles du tableau et faire
des mises à jour indépendantes du recordset via Cnx.Execute "MaRequête de
MAJ" n'est pas performant mais si j'utilise un recordset dynamique, le temps
de traitement sera encore plus long non ?

Y a-t-il une limite pour la taille d'un recordset ?

Teddy


a écrit dans le message de
news:
On 22 jan, 00:16, "teddy" wrote:
Bonjour à tous,

J'ai de sérieux problème de performance avec un programme écrit en VB6 qui
donne satisfaction dès lors qu'on manipule des tables de moins de 30000
enregistrements.

J'ai depuis peu des tables de 300000 enregistrements et là, le temps de
traitement n'est pas multiplié par 10 mais plutôt par 50 !!
Ca marche, mais c'est d'une lenteur à mourir :-((

Mon traitement est simple : je parcours un recordset qui est une vue des
champs utiles d'une table.
Dans chaque enregistrement, je mets à jour un champ particulier en tenant
compte des 14 enregistrements précédents préalablement mémorisés dans un
tableau.

Le traitement met 7 à 8 minutes pour parcourir et mettre à jour (si les
conditions sont remplies) les 30000 enregistrements stockés dans une table
de base Access créée par l'application elle-même via ADOX.
Il faut une nuit maintenant (6 à 8 heures) pour 300000.

J'utilise juste les champs nécessaires, un curseur ForwardOnly (le +
rapide), une requête SQL de mise à jour avec un Connection.Execute
MaRequête
: les champs sont repérés par leur numéros RecordSet.Field(NoChamp), pas
d'affichage de bargraph ou autre...

Auriez-vous eu ce genre de soucis, faut-il remplacer la base Access par
SQL
SERVER par exemple (c'est faisable puisque mon programme se connecte via
ADO
à la base).
Merci beaucoup pour vos suggestions.

Teddy



Bonjour,

si je comprends bien tu es obligé de parcourir toute la table parce
que la mise à jour d'un enregistrement dépend des 14 enregistrements
précédents. Je crains que ce type de contrainte ne soit trop
pénalisant, quelque soit la base relationnelle ou les optimisations du
code (curseur ForwardOnly + Sql Update c'est très bien). Est-ce qu'on
peut avoir une idée du modèle de données ?
Avatar
parci
On 22 jan, 23:40, "teddy" wrote:
C'est 1 table unique qui est une sorte de LOG d'événements triés se lon 2
champs codes numériques et selon la Date/Heure d'évènement.

Donc pas de schéma compliqué avec des jointures dans tous les sens, d e
contraintes sur des champs, de triggers,  d'interdépendance de tables ,
etc...

Je parcours le recordset en mémorisant les valeurs de 3 champs dans les 14
précédents enregistrements (tableau de 14 lignes "glissant"). C'est c omme
une "fenêtre de visualisation" de 14 enregistrements que je déplace d ans le
recordset du début à la fin.

Je pense que le fait de comparer des valeurs avec celles du tableau et fa ire
des mises à jour indépendantes du recordset via Cnx.Execute "MaRequ ête de
MAJ" n'est pas performant mais si j'utilise un recordset dynamique, le te mps
de traitement sera encore plus long non ?



Bon, j'ai fait un test dans l'environnement xp, ado 2.7, access 2000,
vb5. Une table "t1" avec une clé primaire "id" auto incrémentée et 5
champs type long (f1 à f5). Environ 900 000 lignes. Le code suivant a
fait plus de 60 000 update le temps de prendre un café. Je lis les
valeurs de tous les enregistrements dans un tableau et tout les 14
enregistrements je fais un update sans utiliser les données lues (ce
qui doit prendre un peu plus de temps suivant le calcul que tu fais).
Je suis certain d'avoir toujours des données, donc pas de test pour
traiter les null. Ma machine est puissante mais rien de comparable
avec les temps que tu annonces : il faudrait voir comment tu fais.

Voilà le code que j'ai utilisé :

Sub zozozozo()

Dim cn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim sDbPath As String
Dim sSql As String
Dim n As Long
Dim t(1 To 14, 1 To 5) As Long
Dim i As Long

sDbPath = "d:userdbTest.mdb"
sSql = "Select * From T1;"

Set cn = New ADODB.Connection

With cn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = sDbPath
.Open
End With

Set rst = New ADODB.Recordset

With rst
Set .ActiveConnection = cn
.CursorLocation = adUseServer
.CursorType = adOpenForwardOnly
.LockType = adLockReadOnly
.Open sSql
End With

n = 1
i = 0
With rst
If Not (.EOF) Then
.MoveFirst
End If

Do While Not .EOF
If (n Mod 14) = 0 Then
i = 1
sSql = "Update T1 Set f1=-1 Where id=" & .Fields
("id").Value & ";"
cn.Execute sSql
Else
i = i + 1
End If

t(i, 1) = .Fields("f1").Value
t(i, 2) = .Fields("f2").Value
t(i, 3) = .Fields("f3").Value
t(i, 4) = .Fields("f4").Value
t(i, 5) = .Fields("f5").Value

n = n + 1
.MoveNext
Loop
End With


If Not rst Is Nothing Then
If rst.State = adStateOpen Then
rst.Close
End If
Set rst = Nothing
End If

If Not cn Is Nothing Then
If cn.State = adStateOpen Then
cn.Close
End If
Set cn = Nothing
End If

End Sub
Avatar
teddy
Merci pour ce test.
Je pense que c'est ma requête SQL de mise à jour d'un enregistrement qui
pose problème.
Je compare et calcule des différences en jours entre des dates et des heures
et je prends en compte la valeur partielle d'un champ (extrait par un
Mid()).
Cela doit ralentir le traitement.
Je vais chercher un peu plus.
Si je trouve la raison exacte de cet effondrement des performances passé le
seuil de 30000 enregistrements, je reviendrai pour commenter.
Teddy


a écrit dans le message de
news:
On 22 jan, 23:40, "teddy" wrote:
C'est 1 table unique qui est une sorte de LOG d'événements triés selon 2
champs codes numériques et selon la Date/Heure d'évènement.

Donc pas de schéma compliqué avec des jointures dans tous les sens, de
contraintes sur des champs, de triggers, d'interdépendance de tables,
etc...

Je parcours le recordset en mémorisant les valeurs de 3 champs dans les 14
précédents enregistrements (tableau de 14 lignes "glissant"). C'est comme
une "fenêtre de visualisation" de 14 enregistrements que je déplace dans
le
recordset du début à la fin.

Je pense que le fait de comparer des valeurs avec celles du tableau et
faire
des mises à jour indépendantes du recordset via Cnx.Execute "MaRequête de
MAJ" n'est pas performant mais si j'utilise un recordset dynamique, le
temps
de traitement sera encore plus long non ?



Bon, j'ai fait un test dans l'environnement xp, ado 2.7, access 2000,
vb5. Une table "t1" avec une clé primaire "id" auto incrémentée et 5
champs type long (f1 à f5). Environ 900 000 lignes. Le code suivant a
fait plus de 60 000 update le temps de prendre un café. Je lis les
valeurs de tous les enregistrements dans un tableau et tout les 14
enregistrements je fais un update sans utiliser les données lues (ce
qui doit prendre un peu plus de temps suivant le calcul que tu fais).
Je suis certain d'avoir toujours des données, donc pas de test pour
traiter les null. Ma machine est puissante mais rien de comparable
avec les temps que tu annonces : il faudrait voir comment tu fais.

Voilà le code que j'ai utilisé :

Sub zozozozo()

Dim cn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim sDbPath As String
Dim sSql As String
Dim n As Long
Dim t(1 To 14, 1 To 5) As Long
Dim i As Long

sDbPath = "d:userdbTest.mdb"
sSql = "Select * From T1;"

Set cn = New ADODB.Connection

With cn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = sDbPath
.Open
End With

Set rst = New ADODB.Recordset

With rst
Set .ActiveConnection = cn
.CursorLocation = adUseServer
.CursorType = adOpenForwardOnly
.LockType = adLockReadOnly
.Open sSql
End With

n = 1
i = 0
With rst
If Not (.EOF) Then
.MoveFirst
End If

Do While Not .EOF
If (n Mod 14) = 0 Then
i = 1
sSql = "Update T1 Set f1=-1 Where id=" & .Fields
("id").Value & ";"
cn.Execute sSql
Else
i = i + 1
End If

t(i, 1) = .Fields("f1").Value
t(i, 2) = .Fields("f2").Value
t(i, 3) = .Fields("f3").Value
t(i, 4) = .Fields("f4").Value
t(i, 5) = .Fields("f5").Value

n = n + 1
.MoveNext
Loop
End With


If Not rst Is Nothing Then
If rst.State = adStateOpen Then
rst.Close
End If
Set rst = Nothing
End If

If Not cn Is Nothing Then
If cn.State = adStateOpen Then
cn.Close
End If
Set cn = Nothing
End If

End Sub