sql >> データベース >  >> RDS >> Oracle

AccessのODBCリンクテーブルへの一括INSERTのパフォーマンスを向上させる方法は?

    この状況は、AccessでODBCリンクテーブルへの一括INSERTを処理する場合に珍しいことではありません。次のアクセスクエリの場合

    INSERT INTO METER_DATA (MPO_REFERENCE) 
    SELECT MPO_REFERENCE FROM tblTempSmartSSP
    

    ここで、[METER_DATA]はODBCリンクテーブルであり、[tblTempSmartSSP]はローカル(ネイティブ)アクセステーブルです。ODBCは、機能が異なる可能性のあるさまざまなターゲットデータベースに対応できる必要があるため、その巧妙さには多少の制限があります。大きく。残念ながら、多くの場合、単一のAccess SQLステートメントにもかかわらず、リモート(リンクされた)データベースに実際に送信されるのは、ローカルテーブルの各行に対して個別のINSERT(または同等のもの)であるということです。 。当然のことながら、ローカルテーブルに多数の行が含まれている場合、これは非常に遅くなる可能性があります。

    オプション1:リモートデータベースへのネイティブ一括挿入

    すべてのデータベースには、データの一括読み込みのための1つ以上のネイティブメカニズムがあります。MicrosoftSQLServerには「bcp」とBULK INSERTがあります。 、およびOracleには「SQL*Loader」があります。これらのメカニズムは一括操作用に最適化されており、通常、速度が大幅に向上します。実際、リモートデータベースに転送する前にデータをAccessにインポートして「マッサージ」する必要がある場合でも、変更したデータをテキストファイルにダンプして戻し、リモートデータベースに一括インポートする方が高速です。

    オプション2:Accessでパススルークエリを使用する

    一括インポートメカニズムが実行可能なオプションでない場合、別の可能性は、Accessで1つ以上のパススルークエリを作成し、一度に複数の行を挿入できるINSERTステートメントを使用してデータをアップロードすることです。

    たとえば、リモートデータベースがSQL Server(2008以降)の場合、次のようなアクセスパススルー(T-SQL)クエリを実行できます

    INSERT INTO METER_DATA (MPO_REFERENCE) VALUES (1), (2), (3)
    

    1つのINSERTステートメントで3つの行を挿入します。

    ここでの別の以前の質問への回答によると、Oracleに対応する構文は次のようになります

    INSERT ALL
        INTO METER_DATA (MPO_REFERENCE) VALUES (1)
        INTO METER_DATA (MPO_REFERENCE) VALUES (2)
        INTO METER_DATA (MPO_REFERENCE) VALUES (3)
    SELECT * FROM DUAL;
    

    10,000行のネイティブ[tblTempSmartSSP]テーブルを使用して、SQL Serverでこのアプローチをテストしました(Oracleデータベースにアクセスできないため)。コード...

    Sub LinkedTableTest()
        Dim cdb As DAO.Database
        Dim t0 As Single
    
        t0 = Timer
        Set cdb = CurrentDb
        cdb.Execute _
                "INSERT INTO METER_DATA (MPO_REFERENCE) " & _
                "SELECT MPO_REFERENCE FROM tblTempSmartSSP", _
                dbFailOnError
        Set cdb = Nothing
        Debug.Print "Elapsed time " & Format(Timer - t0, "0.0") & " seconds."
    End Sub
    

    ...私のテスト環境で実行するのに約100秒かかりました。

    対照的に、上記のように複数行のINSERTを構築する次のコード(Microsoftがテーブル値コンストラクターと呼んでいるものを使用)...

    Sub PtqTest()
        Dim cdb As DAO.Database, rst As DAO.Recordset
        Dim t0 As Single, i As Long, valueList As String, separator As String
    
        t0 = Timer
        Set cdb = CurrentDb
        Set rst = cdb.OpenRecordset("SELECT MPO_REFERENCE FROM tblTempSmartSSP", dbOpenSnapshot)
        i = 0
        valueList = ""
        separator = ""
        Do Until rst.EOF
            i = i + 1
            valueList = valueList & separator & "(" & rst!MPO_REFERENCE & ")"
            If i = 1 Then
                separator = ","
            End If
            If i = 1000 Then
                SendInsert valueList
                i = 0
                valueList = ""
                separator = ""
            End If
            rst.MoveNext
        Loop
        If i > 0 Then
            SendInsert valueList
        End If
        rst.Close
        Set rst = Nothing
        Set cdb = Nothing
        Debug.Print "Elapsed time " & Format(Timer - t0, "0.0") & " seconds."
    End Sub
    
    Sub SendInsert(valueList As String)
        Dim cdb As DAO.Database, qdf As DAO.QueryDef
    
        Set cdb = CurrentDb
        Set qdf = cdb.CreateQueryDef("")
        qdf.Connect = cdb.TableDefs("METER_DATA").Connect
        qdf.ReturnsRecords = False
        qdf.sql = "INSERT INTO METER_DATA (MPO_REFERENCE) VALUES " & valueList
        qdf.Execute dbFailOnError
        Set qdf = Nothing
        Set cdb = Nothing
    End Sub
    

    ...同じ結果が得られるまでに1〜2秒かかりました。

    (T-SQLテーブル値コンストラクターは一度に1000行を挿入するように制限されているため、上記のコードはそれ以外の場合よりも少し複雑です。)



    1. sqlまたはphpPgAdminを使用してPostgreSQLデータベースのデータベースエンコーディングを変更するにはどうすればよいですか?

    2. 関数からレコードのセット(仮想テーブル)を返します

    3. カスケード削除の影響を受けるテーブルを一覧表示する方法

    4. OracleでASCII値を取得する方法は?