2014-09-16 9 views
7

Mam pliki CSV i TXT do zaimportowania. Importuję pliki do programu Access, a następnie wstawiam rekordy do połączonej tabeli Oracle. Każdy plik ma około 3 miliony wierszy, a proces ten zajmuje dużo czasu.Jak zwiększyć wydajność zbiorczego INSERTs do tabel połączonych ODBC w programie Access?

Importowanie do programu Access jest bardzo szybkie, ale wstawianie do połączonej tabeli Oracle zajmuje wyjątkowo dużo czasu.

Oto proces Obecnie używam:

DoCmd.TransferText acImportFixed, "BUSSEP2014 Link Specification", "tblTempSmartSSP", strFName, False 
db.Execute "INSERT INTO METER_DATA ([MPO_REFERENCE]) SELECT MPO_REFERENCE FROM tblTempSmartSSP;"` 

tblTempSmartSSP jest Tabela dostępu i METER_DATA jest połączone Oracle tabela

Próbowałem również bezpośredni import do połączonej tabeli i to było również bardzo powolny .

Jak mogę przyspieszyć proces?

+0

Meter_Data jest stół bazie wyrocznią –

Odpowiedz

7

Ta sytuacja nie jest niczym niezwykłym gdy ma do czynienia z luzem wstawki ODBC tabel połączonych w programie Access. W przypadku następującego zapytania dostępu

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP 

gdzie [METER_DATA] jest ODBC połączone stół i [tblTempSmartSSP] jest lokalnym (Ojczysty) tabeli Access ODBC jest nieco ograniczona w sposób mądry to może być dlatego, że ma być w stanie pomieścić szeroki zakres docelowych baz danych, których możliwości mogą się znacznie różnić. Niestety, często oznacza to, że pomimo pojedynczej instrukcji Access SQL to, co faktycznie jest wysyłane do zdalnej (połączonej) bazy danych, to osobny INSERT (lub odpowiednik) dla każdego wiersza w lokalnej tabeli. Zrozumiałe jest, że może się to okazać bardzo powolne, jeśli lokalna tabela zawiera dużą liczbę wierszy.

Wariant 1: Native wkładki luzem do zdalnej bazy danych

Wszystkie bazy danych mają jeden lub więcej natywnych mechanizmów załadunku luzem danych: Microsoft SQL Server ma „BCP” i BULK INSERT, a Oracle ma „SQL *Ładowarka". Te mechanizmy są zoptymalizowane pod kątem operacji masowych i zwykle oferują znaczące zalety szybkości. W rzeczywistości, jeśli dane muszą być importowane do programu Access i "masowane" przed przeniesieniem do zdalnej bazy danych, nadal można szybciej zrzucić zmodyfikowane dane z powrotem do pliku tekstowego, a następnie zbiorczo zaimportować je do zdalnej bazy danych.

Opcja 2: Za pomocą kwerendy przekazującej w dostępie

Jeśli mechanizmy importu luzem nie są realną opcją, to inną możliwością jest stworzenie jednego lub więcej kwerend przekazujących w dostępie do przesłania dane za pomocą instrukcji INSERT, które mogą wstawiać więcej niż jeden wiersz naraz.

Na przykład, jeśli zdalna baza danych była SQL Server (2008 lub później), to możemy uruchomić dostęp pass-through (T-SQL) kwerendy jak ten

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

wstawić trzy wiersze z jednej INSERT komunikat.

Zgodnie z odpowiedzią na innym wcześniejszym pytaniu here odpowiednia składnia Oracle byłoby

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; 

testowałem tej metody z SQL Server (jak nie mam dostępu do bazy danych Oracle), używając rodzimego Tabela [tblTempSmartSSP] z 10 000 wierszy. Kod ...

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 

... wykonano około 100 sekund w moim środowisku testowym.

Natomiast poniższy kod, który buduje wstawia wielorzędowe jak opisano powyżej (przy użyciu co nazywa Microsoft Table Value Constructor) ...

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 

... trwało od 1 do 2 sekund, aby produkować takie same wyniki.

(T-SQL tabeli wartości konstruktorzy ograniczony do wkładania 1000 wierszy na raz, tak więc powyższy kod jest bardziej skomplikowany niż byłoby to w inny sposób).

+0

Bardzo imponujący Gord. Ogólnie rzecz biorąc, ludzie często zakładają, że używanie instrukcji wstawiania sql jest szybsze niż dao.recordsets - nie są one ZWYKŁE, że jedno polecenie SQL może zastąpić rekorsetyk. Jednak wykonywanie "całego" ciągu SQL dla każdego wiersza jest zwykle znacznie wolniejsze niż rekorsecja. Proponuję więc, aby plakat wypróbował prosty zestaw rekordów na połączonym stole. –

+0

Hi Gord Thompson, dzięki za kod. Otrzymuję jeden błąd podczas uruchamiania tego kodu "ODBC- Call Failed" na qdf.Execute dbFailOnError –

+0

@ravichaudhary Proszę zadać pytanie [new question] (http://stackoverflow.com/questions/ask) pokazujące rzeczywisty kod. –

0

Czy musisz zaimportować wszystkie kolumny? Może chcesz pominąć puste kolumny, jeśli takie istnieją; a także kolumny, które nie są absolutnie niezbędne do celów służbowych

+0

trzeba cały kolumny i na maksimum jest tylko 5 kolumn. Próbuję również importować małe dane, takie jak 6000 wierszy, to również zajmuje więcej niż godzinę –

+0

Pomyślałem o tym; spróbuj użyć następującego polecenia, aby uruchomić zapytanie akcji. Może to powolne, ponieważ potrzebujesz więcej deklaracji: – user2290801

+0

Czy importujesz plik do istniejącej tabeli? i jesteś użytkownikiem? Utworzenie tabeli zajmuje więcej czasu i nie chcesz nikogo innego w bazie danych, jeśli importujesz. Przeprowadź także zapytanie, aby usunąć wartości null, zanim zrobisz cokolwiek innego z kolumny, którą kopiujesz. Nulls spowalniają działanie. Tylko kilka pomysłów – user2290801

0

Niestety, zapomniałem zawierać kod:

Option Compare Database 
Option Explicit 

Public Function Run_Safe_SQL(strSQL) 
On Error GoTo Error_Handler 
Dim db As DAO.Database 

    Set db = CurrentDb() 
    db.Execute strSQL, dbFailOnError 
    DBEngine.Idle dbRefreshCache 
' DoEvents 

Exit_Here: 
    'Cleanup 
    Set db = Nothing 
    strSQL = "" 
    Exit Function 

Error_Handler: 
    MsgBox Err.Description & " " & Err.Number 

End Function 
Powiązane problemy