Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Access 2016)
メモリ不足の解消
投稿日時: 19/08/25 13:11:53
投稿者: k9

Access初心者です。
 
15桁のID(数字のみ)をハッシュ化するマクロを作成しています。
マクロが最後まで完了できるのは確認できているのですが、
何回か繰り返し実行していると「メモリ不足」のメッセージが
表示されて処理が完了できません。
テストでレコード件数をカウントすると最終レコードまでは
処理できているようなのですがLOOPを抜けてくれません。
 
「メモリ不足」を解消する方法はありませんでしょうか?
 
 
マクロの内容
@クエリ1 テーブルaを作成(フィールドは「ID」のみ、件数は2万件程度)
Aクエリ2 テーブルbを作成(フィールドは「ID」のみ、件数は10万件程度)
Bunionクエリ テーブルaとテーブルbを結合してテーブルcを作成
         (重複データなし、件数は5万件程度、
          フィールドは「ID」「ハッシュ値(値なし)」)
Cモジュール テーブルcの「ID」をハッシュ化して「ハッシュ値」にセット
 
  Fucntion hach()
    Dim db As Database
    Dim rs As Recordset
 
  Set db = CurrentDb
    Set rs = db.OpenRecordset("テーブルc", dbOpenTable)
 
    Do Until rs.EOF
      rs.Edit
   IDをハッシュ化して「ハッシュ値」にセット
      rs.Update
      rs.MoveNext   ← ここで「メモリ不足」となります。
    Loop
     
    rs.Close
    Set rs = Nothing
    db.Close
    Set db = Nothing
  End Fucntion
 
  ↓ いろいろ試してみましたが結果は変わりませんでした。
 
  Fucntion hach()
    Dim db As Database
    Dim rs As Recordset
    Dim TranCount AS Long
 
  Set db = CurrentDb
    Set rs = db.OpenRecordset("テーブルc", dbOpenTable)

    DBEngine.SetOption dbMaxLocksPerFile, 200000
    TranCount = 0
    DBEngine.BeginTrans

    Do Until rs.EOF
      rs.Edit
   IDをハッシュ化して「ハッシュ値」にセット
      rs.Update

      TranCount = TranCount + 1
   If TranCount = 5000 Then
         DBEngine.CommitTrans
         DBEngine.BeginTrans
         TranCount = 0
     End If

      rs.MoveNext   ← ここで「メモリ不足」となります。
    Loop

    DBEngine.CommitTrans

    rs.Close
    Set rs = Nothing
    db.Close
    Set db = Nothing
  End Fucntion

投稿日時: 19/08/29 09:30:05
投稿者: k9

いろいろ試してみたのですが、テーブルcの件数を1万件に抑えると処理が完了し、
2万件では「メモリ不足」になります。
 
そこで質問なのですが、
n万件あるテーブルcを1万件ずつに分割し、分割後のテーブルでハッシュ化を行った後、
再度テーブルを結合する方法はありますでしょうか。
(テーブルcの件数は可変)

回答
投稿日時: 19/08/30 14:58:44
投稿者: sk

引用:
15桁のID(数字のみ)をハッシュ化するマクロを作成しています。
マクロが最後まで完了できるのは確認できているのですが、
何回か繰り返し実行していると「メモリ不足」のメッセージが
表示されて処理が完了できません。

引用:
「メモリ不足」を解消する方法はありませんでしょうか?

Office Support Team Blog JAPAN より:
https://blogs.technet.microsoft.com/officesupportjp/2017/02/16/ace_memory_error/
https://blogs.technet.microsoft.com/officesupportjp/2017/02/08/ace_memory/
 
引用:
Set db = CurrentDb
Set rs = db.OpenRecordset("テーブルc", dbOpenTable)
 
DBEngine.SetOption dbMaxLocksPerFile, 200000
TranCount = 0
DBEngine.BeginTrans

Function hach()
     
    Dim ws As DAO.Workspace
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
     
    DBEngine.SetOption dbMaxLocksPerFile, 200000
    DBEngine.SetOption dbMaxBufferSize, 102400
    DBEngine.Idle dbRefreshCache
     
    Set ws = DBEngine.Workspaces(0)
    Set db = CurrentDb
    Set rs = db.OpenRecordset("テーブルc", dbOpenDynaset)
     
    ws.BeginTrans
     
    Do Until rs.EOF
        rs.Edit
        If Nz(rs![ID], "") = "" Then
            rs![ハッシュ] = Null
        Else
            rs![ハッシュ] = ハッシュ関数的な何か(rs![ID])
        End If
        rs.Update
        rs.MoveNext
    Loop
     
    ws.CommitTrans
     
    Set rs = Nothing
    Set db = Nothing
    Set ws = Nothing
 
End Sub
-------------------------------------------------------------------
 
以上のようなコードを実行してみても同様の結果となるのでしょうか。

投稿日時: 19/08/31 22:28:26
投稿者: k9

sk 様
 
ご回答頂き、ありがとうございます。
 
教えて頂いた内容で実行してみましたが、結果は変わらず
「メモリ不足」のままでした。
 
 

回答
投稿日時: 19/09/01 20:15:24
投稿者: NoLookUp

考えられることとして、ハッシュ化する仕組みのところでリソースを喰いまくってるとかはないでしょうか。
 
ハッシュ化する仕組みを得るためのVBAコードをWeb検索してみると、コールするたび CreateObject を繰り返しているコードが見当たります。
もしそのまま流用しているとしたら、それを何万回も連続して繰り返すわけですから...どうなるんでしょう?
 
というわけで改善の一つの案として、たとえば、そこでハッシュするためのオブジェクト変数を Static で宣言して、Is Nothing のときだけ CreateObject する、とかが考えられます。
 
 
あとは、クエリで更新させるとか、
逃げ案としては、フィールド「ハッシュ値」が空欄のレコードだけ対象に更新処理をして、それを1万件ずつで区切ってRecordSet更新するとかが考えられます。

投稿日時: 19/09/04 21:40:19
投稿者: k9

NoLookUp 様
 
ご回答頂き、ありがとうございます。
実行環境が勤務先のため、ご返答が遅くなり申し訳ありません。
 
自分でも試行錯誤していたのですが、
作成したデータベースにパスワードをかけたところ、
「メモリ不足」が発生しなくなりました。
 
排他環境が関係するのか、原因は不明ですが、
一旦、解決済みとさせて頂きます。
NoLookUp様に教えて頂いた内容も、今後の参考とさせて頂きます。
 
 
皆様ありがとうございました。