7

Access にクエリを実行し、データを Excel (2003) に入力するために、このコードをオンラインで見つけましたが、本来よりもはるかに遅いです。

Sub DataPull(SQLQuery, CellPaste)
Dim Con As New ADODB.Connection
Dim RST As New ADODB.Recordset
Dim DBlocation As String, DBName As String
Dim ContractingQuery As String

If SQLQuery = "" Then

Else
    DBName = Range("DBName")
    If Right(DBName, 4) <> ".mdb" Then DBName = DBName + ".mdb"

    DBlocation = ActiveWorkbook.Path
    If Right(DBlocation, 1) <> "\" Then DBlocation = DBlocation + "\"

    Con.ConnectionString = DBlocation + DBName
    Con.Provider = "Microsoft.Jet.OLEDB.4.0"
    Con.Open

    Set RST = Con.Execute(SQLQuery)
    Range(CellPaste).CopyFromRecordset RST

    Con.Close
End If

End Sub

問題は、このコードが非常に長くかかることです。Access を開いてそこでクエリを実行すると、約 1/10 の時間がかかります。これをスピードアップする方法はありますか?または、これに時間がかかる理由は何ですか? 私のすべてのクエリは、単純な where ステートメントと結合のない単純な選択クエリです。クエリでさえ、select * from [test]必要以上に時間がかかります。

編集:私はその行を指定する必要があります

Range(CellPaste).CopyFromRecordset RST

時間がかかった方です。

4

10 に答える 10

3

私は専門家ではありませんが、ほぼ同じコードを実行すると、良い結果が得られます。1 つの違いは、Commandオブジェクトだけでなくオブジェクトも使用するConnectionことです。どこで

Set RST = Con.Execute(SQLQuery)

Dim cmd As ADODB.Command
Set cmd.ActiveConnection = con
cmd.CommandText = SQLQuery
Set RST = cmd.Execute

それが役立つかどうか、またはなぜ役立つかはわかりませんが、役立つでしょうか?:-)

于 2009-10-15T19:08:50.457 に答える
2

似たようなものを比較しているとは思いません。

Access でクエリのデータビューを表示すると、次のようになります。

  • 既存の開いている接続が使用されます (開いたままになります)。
  • レコードセットは、最初の数行だけで部分的に埋められます (開いたままになります)。
  • 部分的な結果セットは、タスク専用のグリッドに表示され、Access が採用するネイティブ データ アクセス方法 (おそらく Access データベース エンジン DLL の直接使用) 用に最適化されています。

VBA コードで:

  • 新しい接続が開かれます (その後、閉じられて解放されます)。
  • レコードセットは、すべての行を使用して完全に取り込まれます (その後、閉じられて解放されます)。
  • 非ネイティブ データ アクセス コンポーネントを使用して、結果セット全体が Excel の汎用 UI に読み込まれます。

最も重要な点は、Access のデータビューは、通常は結果セットの最後の行に移動して、要求するまで結果セット全体をフェッチしないことです。ADO は常に結果セット内のすべての行をフェッチします。

2 番目に重要なのは、フェッチされた行 (完全な結果セットを想定) を UI 要素に読み込むのにかかる時間と、Excel がジョブ用に最適化されていないという事実です。

接続とレコードセットの開始、終了、および解放は重要ではありませんが、依然として要因です。

ボトルネックを見つけるには、プロセスの各ステップでタイミングを合わせる必要があると思います。Access と比較する場合は、返された行数を確認するなど、完全な結果セットを取得していることを確認してください。

于 2009-10-16T07:49:58.600 に答える
1

Recordsetメソッドを暗黙的に使用するのではなく、明示的 に作成することをお勧めしますExecute。明示的に作成する場合、パフォーマンスに影響を与える CursorType および LockType プロパティを設定できます。

私が見たところ、Excel にデータを読み込んでから、レコードセットを閉じています。更新したり、レコードを数えたりする必要はありません...したがって、私のアドバイスはRecordsetwithを作成することCursorType = adOpenForwardOnly & LockType = adLockReadOnlyです:

...
RST.Open SQLQuery, Con, adOpenForwardOnly, adLockReadOnly
Range(CellPaste).CopyFromRecordset RST
...

Recordset Object (ADO)

于 2009-10-15T19:09:18.503 に答える
1

Access 2003 を使用しているため、代わりに DAO を使用してください。Jet エンジンを使用すると高速になります。

サンプル コードについては、 http://www.erlandsendata.no/english/index.php?d=envbadacexportdaoを参照してください。

「As New」キーワードは使用しないでください。予期しない結果が生じる可能性があることに注意してください。

于 2009-10-15T19:10:43.180 に答える
1

私はあなたのコードを使用して、38 列と 63780 行のテーブルを 7 秒未満で取り込みました。

これはあなたが経験しているようなパフォーマンスですか?もしそうなら、それは Excel から MDB バックエンドへの ADO 接続で私が期待するものと一致しています。

これよりもはるかに遅いパフォーマンスが見られる場合は、ローカル環境の条件が影響しているに違いありません。

于 2009-10-16T06:21:55.393 に答える
1

多くの数式がクエリを参照する場合があります。マクロで手動計算を一時的にオンにし、すべてのクエリの更新が完了したらオフにしてみてください。

これにより、速度が少し向上するはずですが、根本的な問題は解決されません。

于 2009-10-20T15:03:49.230 に答える
0

Range(CellPaste)多くのレコードを取得すると、時間がかかる理由が説明されます。(Access でクエリを実行すると、すべてのレコードが取得されるわけではありませんが、CopyFromRecordset を実行すると、すべてのレコードが必要になります。)

CopyFromRecordset の MaxRows パラメータがあります。

Public Function CopyFromRecordset ( _
    Data As Object, _
    <OptionalAttribute> MaxRows As Object, _
    <OptionalAttribute> MaxColumns As Object _
) As Integer

これを低い値 (10 程度など) に設定するとパフォーマンスが変わるかどうか試してください。

于 2009-10-15T20:28:53.900 に答える
0

10 回中 9 回の問題は、使用しているカーソルの種類/場所に関係しています。

ネットワーク接続で動的カーソルを使用すると、クエリが非常に高速に実行された場合でも、データの取得が遅くなる可能性があります。

大量のデータを非常に迅速に取得したい場合は、接続で CursorLocation = adUseClient を使用する必要があります。これは、静的なローカル カーソルしか持たないことを意味するため、他のユーザーからライブ更新を受けることはありません。

ただし、データを読み取るだけの場合は、ADO を保存して、個々のレコードごとに DB に戻って変更を確認します。

リスト項目を入力する単純なループがあり、各ループに約0.3秒かかっていたため、最近これを変更しました。遅くはありませんが、1,000 レコードでも 30 秒です! カーソル位置だけを変更すると、プロセス全体が 1 秒以内に完了します。

于 2015-04-29T14:03:19.193 に答える
0

次のターンアラウンドまたは改善についてはどうですか。

  1. 開いたら、レコードセットを xml ファイル (rst.saveToFile xxx) として保存し、Excel で再度開きます。
  2. 開いたら、レコードセット データを配列 (rst.getRows xxx) に入れ、その配列をアクティブ シートにコピーします。
  3. そして、いつでもすべてのメモリ/アクセス要件を最小限に抑えます: レコードセットを読み取り専用、転送専用として開き、データが手元にある場合は接続を閉じます。
于 2009-10-15T20:32:47.053 に答える