6
votes

VB6 MS Access Base de données Édition Grand montant d'enregistrements

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


11 commentaires

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 ) 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 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 , 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.


4 Réponses :


1
votes

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 sort_value fort> pourrait être 10 valeurs différentes, toutes vos mises à jour seraient effectuées dans 10 requêtes de mise à jour. P>


Si vous nous dites où vous vous dites où vous vous dites où vous obtenez le Sort_Value strong>, nous pourrions peut-être vous aider davantage. P>


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>

  • rs (1) au lieu de Rs ("nom"). Cela a été suggéré sur un autre site et effectivement augmenté de 20% de 20%. (25 sec / 21 sec) li>
  • Begntrans / Commissturons n'a fait aucune différence sur un champ non indexé, et était de 1% plus rapide sur un champ indexé. (non indexé: 11 sec [w / trans] / 11 sec, indexé: 23 sec [W / Trans] / 25 sec) * LI>
  • déclarations SQL individuelles. (86 sec) li>
  • paramètre QueryDef. (43 secondes) li> ul>

    * 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
    


4 commentaires

+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 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.



2
votes

J'ai créé une table appelée Test avec les champs n et f (n)

omide 3 sous-mises à jour différentes - Recordset sans transaction - Recordset avec transaction - Mettre à jour la requête xxx

Ceci est essentiellement ce que vous faites, un jeu d'enregistrements droit lors de la modification d'un champ xxx 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. xxx

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.

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

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.

EDIT: Old Old Core 2 Duo Machine + Aucun indices sur les champs


4 commentaires

+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 dans le code VBA, puis vous pouvez augmenter votre commits sur à ~ 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.



1
votes

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.

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 ... xxx

Vous répétez ceci (par code) pour toutes les divisions que vous avez faites dans votre table.

Maintenant, la question est-ce que la question est- Pouvez-vous penser à une fonction d'accès qui crée la solution requise_value?

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.


0 commentaires

0
votes

Pour améliorer les performances, vous pouvez utiliser updatebatch code> méthode d'objet AdoDB. Mais pour utiliser cette fonctionnalité, elle nécessite:

  1. adopquéStatic code> CURSORType et em> li>
  2. AdlockbatchoptiMistic code> LOCKTYPE LI> ol>

    sur l'objet Recordset.
    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>

    Pour aller plus loin, abstenez-vous d'utiliser 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>

    Utilisez le code suivant comme indice: p>

    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
    


0 commentaires