Oracle
 sql >> база данни >  >> RDS >> Oracle

Как да повишите производителността за групови INSERT към ODBC свързани таблици в Access?

Тази ситуация не е необичайна, когато се работи с групови INSERT към ODBC свързани таблици в Access. В случай на следната заявка за достъп

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP

където [METER_DATA] е ODBC свързана таблица и [tblTempSmartSSP] е локална (родна) таблица за достъп, ODBC е донякъде ограничена в това колко интелигентна може да бъде, тъй като трябва да може да побере широк спектър от целеви бази данни, чиито възможности могат да варират значително. За съжаление, това често означава, че въпреки единичния SQL оператор на Access, това, което всъщност се изпраща към отдалечената (свързана) база данни, е отделен INSERT (или еквивалент) за всеки ред в локалната таблица . Разбираемо е, че това може да се окаже много бавно, ако локалната таблица съдържа голям брой редове.

Опция 1:Групови вмъквания в собствена база към отдалечената база данни

Всички бази данни имат един или повече естествени механизми за групово зареждане на данни:Microsoft SQL Server има "bcp" и BULK INSERT , а Oracle има "SQL*Loader". Тези механизми са оптимизирани за групови операции и обикновено предлагат значителни предимства в скоростта. Всъщност, ако данните трябва да бъдат импортирани в Access и „масажирани“ преди да бъдат прехвърлени към отдалечената база данни, все пак може да бъде по-бързо да изхвърлите модифицираните данни обратно в текстов файл и след това групово да ги импортирате в отдалечената база данни.

Опция 2:Използване на преходна заявка в Access

Ако механизмите за групово импортиране не са осъществима опция, тогава друга възможност е да се изградят една или повече преминаващи заявки в Access за качване на данните с помощта на оператори INSERT, които могат да вмъкват повече от един ред наведнъж.

Например, ако отдалечената база данни беше SQL Server (2008 или по-нова версия), тогава бихме могли да изпълним заявка за достъп (T-SQL) като тази

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

за да вмъкнете три реда с един израз INSERT.

Според отговор на друг по-ранен въпрос тук съответният синтаксис за 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;

Тествах този подход със SQL Server (тъй като нямам достъп до база данни на Oracle), използвайки собствена таблица [tblTempSmartSSP] с 10 000 реда. Кодът ...

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да посочите IN клауза в динамична заявка с помощта на променлива?

  2. UNPIVOT върху неопределен брой колони

  3. JDBC ResultSet getDate губи прецизност

  4. Как да използвам Oracle Ref Cursor от C# ODP.NET като параметър на ReturnValue, без да използвам съхранена функция или процедура?

  5. Функция CAST() в Oracle