J'ai besoin de traiter des centaines de milliers d'enregistrements avec VB6 et une base de données d'accès MS. I ITERER à travers le jeu d'enregistrement et modifiez chaque enregistrement. Cependant, il faut beaucoup de temps pour le faire. Création d'une base de données avec le même montant d'enregistrements à l'aide des méthodes AddNew et Mettre à jour fonctionne beaucoup plus vite.
Je vais apprécier grandement si quelqu'un me montre un échantillon de code ou juste une stratégie. P>
Voici le code
Data1(1).RecordSource = "Select * from TABLE order by Field_A ASC" Data1(1).Refresh If Data1(1).Recordset.RecordCount > 0 Then Data1(1).Recordset.MoveFirst Do Data1(1).Recordset.Edit Data1(1).Recordset.Fields("FIELD") = Sort_Value Data1(1).Recordset.Update Data1(1).Recordset.MoveNext Loop Until Data1(1).Recordset.EOF = True End If
4 Réponses :
Ma seule suggestion, qui peut ne pas fonctionner dans votre cas, est de faire des mises à jour de masse à l'aide d'une requête de mise à jour.
Trois cas où cela pourrait fonctionner: p>
si sort_value strong> peut être calculé à partir des autres champs, c'est une simple requête de mise à jour, mais je suis sûr que vous auriez déjà vu que. p> si sort_value strong> peut être calculé à partir d'autres enregistrements (comme l'enregistrement précédent), vous pouvez probablement écrire une requête de mise à jour plus complexe (j'ai vu des requêtes assez complexes postées Ici). P> enfin, si le même sort_value strong> est appliqué à beaucoup d'enregistrements, vous pouvez émettre une requête de mise à jour basée sur ces enregistrements. Donc, si Si vous nous dites où vous vous dites où vous vous dites où vous obtenez le Voici quelques éléments qui forts> ne fonctionnent pas forts> pour accélérer les commandes d'édition / mise à jour, en fonction de mes tests. Cela a été fait à l'aide d'une table de 10 000 enregistrements, avec 1 000 000 mises à jour. P> * Résultat corrigé. p> code pour le test de BegNtrans / commissions. P>
Sub CommitTest()
Dim C As String
Dim I As Long
Dim J As Long
Dim RS As Recordset
Dim BegTime As Date
Dim EndTime As Date
BegTime = Now()
Set RS = CurrentDb.OpenRecordset("tblTest")
For J = 1 To 200
RS.MoveFirst
DBEngine.Workspaces(0).BeginTrans
For I = 1 To 5000
C = Chr(Int(Rnd() * 26 + 66))
RS.Edit
RS("coltest") = C
RS.Update
RS.MoveNext
Next I
DBEngine.Workspaces(0).CommitTrans
Next J
EndTime = Now()
Debug.Print DateDiff("s", BegTime, EndTime)
End Sub
+1 pour les tests, mais ymmv. Pour mon étui d'essai particulier - une mise à jour de jeu d'enregistrements DAO pour chaque ligne d'une table avec 1 million de lignes - à l'aide d'une transaction toujours améliorée des performances, mais seulement d'environ 17%.
Merci. J'ai effectivement corrigé mes résultats car je n'ai pas fait un test équitable (accidentellement) avec les Begntrans / CommitTrans. Toujours seulement 1% plus rapide sur un champ indexé. J'ai posté le code que j'ai utilisé ci-dessus. Faites-moi savoir si vous voyez pourquoi votre test était tellement plus rapide.
Vous pensez essentiellement que cela revient pour éviter les joints et utiliser des requêtes lorsque cela est possible. Peu importe la façon dont nous optimisons les joints d'enregistrement ne s'approche pas de Querydefs.
Je suis d'accord. Je ne peux pas penser à aucun cas où Sort_Value B> ne peut pas être calculé d'une manière ou d'une autre dans une requête, même si elle appelle une fonction extérieure.
J'ai créé une table appelée omide 3 sous-mises à jour différentes
- Recordset sans transaction
- Recordset avec transaction
- Mettre à jour la requête p> Ceci est essentiellement ce que vous faites, un jeu d'enregistrements droit lors de la modification d'un champ P> Ceci est la même idée mais avec des transactions. Je vous engageons 5000 enregistrements à la fois car il y avait une limite établie autour de 9k-10k par commit. Vous pouvez modifier cela, je crois en entrant dans le registre. P> Ceci est plus rapide que l'une des méthodes d'enregistrement. Par exemple. Sur environ 2 millions d'enregistrements, il a fallu environ 20 secondes sans transactions, ~ 18-19 secondes avec transactions, ~ 14 secondes avec la requête de mise à jour. p> Tout cela est sous l'hypothèse que le champ à mettre à jour dépend des valeurs calculées à partir d'autres fiends dans ce document P> pour accélérer ce type d'actions, parfois elle dépend parfois de La situation et plus de détails sont nécessaires si cela ne s'applique pas. P> EDIT: Old Old Core 2 Duo Machine + Aucun indices sur les champs P> P> Test code> avec les champs
n code> et
f (n) code>
+1 pour suggérer une transaction. Si le champ étant mis à jour avait un indice à ce sujet, je m'attendrais à une amélioration significative. Vous pouvez également éviter d'éditer le registre à l'aide d'une instruction comme dbengine.setoption dbmaxlocksperfile, 300000 code> dans le code VBA, puis vous pouvez augmenter votre
commits sur code> à ~ 250 000.
@Gord, en fait, l'inverse était vrai. Je joue avec cela depuis quelques heures maintenant et j'ai déjà passé plusieurs tests différents. Pour un million d'enregistrements, aucun index, je reçois 11 secondes avec ou sans utiliser des transactions. Pour un champ indexé (texte), j'obtiens 27 secondes à l'aide de transactions et 25 secondes sans transactions. BTW, la taille de validation était de 5000.
Merci d'avoir pris l'effort d'Eve Testez votre code. j'apprécie beaucoup. Mais une question - quelle est la taille de validation maximale disponible?
Je n'ai pas essayé de voir quel est le niveau maximal. Le commentaire de Gordthompson indique que 250k est possible. Personnellement, je ne pense pas qu'il y ait un avantage aux transactions d'un point de vue de vitesse et que le principal avantage est la capacité de faire rouler des changements de retour, etc.
Bien que cela puisse être nécessaire dans certains cas, itérant à travers des recumettes afin de mettre à jour un champ doit être évité.
La chose sensible à faire, ce qui est beaucoup plus efficace, serait d'écrire une requête de mise à jour SQL. < / p>
Si votre table est si grosse, vous devez faire attention à l'élection de vos index, spécialement la clé principale. P>
Ensuite, vous pouvez diviser les données en fonction de votre PK et de mettre à jour Tous les enregistrements de la première série, puis dans la seconde, troisième ... p> Vous répétez ceci (par code) pour toutes les divisions que vous avez faites dans votre table. P> Maintenant, la question est-ce que la question est- Pouvez-vous penser à une fonction d'accès qui crée la solution requise_value? p> Notez que si le champ_a est votre clé principale, vous ne devez pas le changer. Sinon, toute votre table serait réarrangée chaque fois que vous avez mis à jour quelques enregistrements, ce qui serait beaucoup de travail pour votre HD / processeur. Dans ce cas, vous devez avoir un PK différent et créer un index sur champ_a, pas pk. P> p>
Pour améliorer les performances, vous pouvez utiliser sur l'objet Recordset. Pour aller plus loin, abstenez-vous d'utiliser Utilisez le code suivant comme indice: p> updatebatch code> méthode d'objet AdoDB. Mais pour utiliser cette fonctionnalité, elle nécessite:
adopquéStatic code> CURSORType et em> li>
AdlockbatchoptiMistic code> LOCKTYPE LI>
ol>
De plus, vous pouvez également utiliser aduseclient code> cursorlocation pour avoir une charge sur le client au lieu du serveur pendant l'opération. P>
rec.eof Code> Test. Vous devriez plutôt utiliser une boucle à partir de
1 à rec.recordcount code> p>
mérite d'être mentionné: code> Il n'est pas fiable à lire
rec.recordcount code> jusqu'à ce que ADODB ait parcouru tous les enregistrements. Donc, un
movelast code> et
mobilefirst code> pour assurer un enregistrement correct. P>
blockQuote>
set con = Server.CreateObject("ADODB.Connection")
con.Provider = "Microsoft.Jet.OLEDB.4.0"
con.Open(Server.Mappath("MyShopDB.mdb"))
set rec = Server.CreateObject("ADODB.recordset")
sql = "SELECT * FROM Employees"
rec.CursorLocation = adUseClient
rec.CursorType = adOpenStatic
rec.LockType = adLockBatchOptimistic
rec.Open sql, con
if not rec.EOF then ' rescue no records situation
rec.moveLast ' let it see all records
rec.moveFirst
end if
cnt = rec.RecordCount ' avoid reading each time in loop test
if cnt > 0 then
for i = 1 to cnt
rec.Fields("FIELD").value = Sort_Value
'...
'...
'...
rec.MoveNext
next i
rec.UpdateBatch
end if
rec.Close
con.Close
Partage de votre code, de la déclaration de mise à jour, etc. sera utile
Utilisation d'une transaction plutôt que de rédiger les mises à jour à chaque fois sera beaucoup plus rapide, voir mon exemple de réponse ici: Stackoverflow.com/Questtions/12930603/...
J'ai commencé une générosité pour vous parce que je suis curieux de cela moi-même. Si vous pouvez modifier votre message pour inclure le code que vous utilisez actuellement, cela pourrait aider les personnes à trouver les faiblesses de votre code.
Il est vraiment difficile de dire comment vous devriez améliorer la vitesse de ce que vous faites si vous ne montrez pas (ou au moins dites i>) nous ce que vous faites en premier lieu. "Comment puis-je faire mon code plus vite? Je ne vais pas vous le montrer, ni même vous dire ce que ça fait exactement. Pouvez-vous m'aider?"
Juste une question; Pouvez-vous nous dire si la table présente des index ou des champs clés et, dans l'affirmative, quels domaines sont-ils?
+1 pour utiliser une transaction comme @Mattdonnan suggère. Les résultats du test ici sont pour les inserts, mais un La transaction peut également accélérer les lots de mises à jour.
Apparemment, vous utilisez un contrôle de données avec DAO pour mettre à jour vos enregistrements. Débarrassez-vous de ce contrôle de données et utilisez simplement des joints simples. Supprimez également la commande
par code> si nécessaire. Puis réessayez.
BALLYMARK - Pouvez-vous vérifier la réponse de Shareeef et voir s'il accélère votre processus? Si oui, donnez-lui la coche de réponse acceptée afin que je puisse attribuer la prime. Sinon, s'il vous plaît laissez-nous savoir que cela aussi. Merci!
@Johnny, j'ai le sentiment que nous n'entendrons pas de lui avant de retourner au travail dans quelques heures. Une fois que nous avons plus de détails sur l'endroit où il obtient Sort_Value B>, mieux nous pouvons l'aider.
Salut encore! Désolé pour l'interruption, mais quelque chose m'a gardé loin. J'ai oublié deux choses importantes à mentionner: 1. L'indexation ne fonctionne pas très bien pour moi, car il y a vraiment beaucoup de données, généré de manière dynamique, donc une fois qu'un ensemble de données est traité, il revient rarement. 2. Plus important, je m'excuse à nouveau d'avoir oublié de mentionner, c'est que les enregistrements doivent être itératés, car la tâche consiste à prendre en compte les valeurs d'enregistrements adjacents.
Vous pouvez mettre à jour en fonction des valeurs d'enregistrement adjacentes à l'aide d'une requête aussi. En fonction des données, cela peut nécessiter une sous-requête cependant. Je pense que cela vaudrait la peine pour vous de poster un exemple de données et de résultats que vous recherchez.