2009-06-12 17 views
22

Który byłby lepszą opcją wstawienia zbiorczego do bazy danych Oracle? pętli for Cursor jakWstawianie zbiorcze do bazy danych Oracle: Co jest lepsze: Pętla kursora lub prosta Wybierz?

DECLARE 
    CURSOR C1 IS SELECT * FROM FOO; 
BEGIN 
    FOR C1_REC IN C1 LOOP 
    INSERT INTO BAR(A, 
       B, 
       C) 
      VALUES(C1.A, 
       C1.B, 
       C1.C); 
    END LOOP; 
END 

lub prosty select, jak:

INSERT INTO BAR(A, 
       B, 
       C) 
     (SELECT A, 
       B, 
       C 
     FROM FOO); 

żadnego konkretnego powodu, albo jeden byłby lepszy?

+2

FYI, nie powinieneś nazywać tego "wkładką zbiorczą". Podczas wstawiania dużych ilości danych dostępna jest funkcja PL/SQL o nazwie Operacje masowe (wkłady masowe, gromadzenie zbiorcze) itd. – moleboy

+0

Aby dodać odniesienie do operacji zbiorczych, należy wziąć pod uwagę, że nad pozostałymi dwoma elementami w przypadku operacji związanych z dużymi danymi lub ciągłe, regularne operacje wstawiania. W przykładach wkładek masowych można uzyskać olbrzymią poprawę wydajności w porównaniu z prostymi wstawkami w podanych przykładach. – DCookie

Odpowiedz

25

Polecam opcję Wybierz, ponieważ kursory trwają dłużej.
Korzystanie z funkcji wyboru jest dużo łatwiejsze do zrozumienia dla każdego, kto musi zmodyfikować zapytanie.

+6

+1. Druga opcja jest również bardziej zwięzła i nie wymaga kompilacji/wykonania bloku PL/SQL. –

5

Jeśli segment segmentu wycofania/cofania może pomieścić rozmiar transakcji, opcja 2 jest lepsza. Opcja 1 jest przydatna, jeśli nie masz możliwości wycofywania zmian i musisz przełamać dużą wstawkę w mniejsze zatwierdzenia, aby nie uzyskać zbyt małego błędu w przypadku wycofania/cofnięcia segmentu.

5

Prosta wkładka/wybierz jak druga opcja jest zdecydowanie lepsza. Dla każdej wstawki w pierwszej opcji wymagany jest przełącznik kontekstowy z pl/sql do sql. Uruchom każdy z trace/tkprof i sprawdź wyniki.

Jeśli, jak wspomina Michael, twoje wycofanie nie może obsłużyć stwierdzenia, to twoja dba da ci więcej. Dysk jest tani, a częściowe wyniki, które pochodzą z wstawiania danych w wielu przejściach, są potencjalnie dość drogie. (Prawie nie ma nic wspólnego z wstawką.)

21

Ogólna zasada jest taka, że ​​jeśli możesz to zrobić za pomocą pojedynczego polecenia SQL zamiast PL/SQL, powinieneś. Zwykle będzie bardziej wydajny.

Jednakże, jeśli potrzebujesz dodać więcej logiki proceduralnej (z jakiegoś powodu), może być konieczne użycie PL/SQL, ale powinieneś użyć operacji zbiorczych zamiast przetwarzania wiersz po rzędzie. (Uwaga: w Oracle 10g i późniejszych, twoja pętla FOR automatycznie użyje BULK COLLECT, aby pobrać 100 wierszy na raz, ale instrukcja wstawiania będzie nadal wykonywana rząd po rzędzie).

np.

DECLARE 
    TYPE tA IS TABLE OF FOO.A%TYPE INDEX BY PLS_INTEGER; 
    TYPE tB IS TABLE OF FOO.B%TYPE INDEX BY PLS_INTEGER; 
    TYPE tC IS TABLE OF FOO.C%TYPE INDEX BY PLS_INTEGER; 
    rA tA; 
    rB tB; 
    rC tC; 
BEGIN 
    SELECT * BULK COLLECT INTO rA, rB, rC FROM FOO; 
    -- (do some procedural logic on the data?) 
    FORALL i IN rA.FIRST..rA.LAST 
     INSERT INTO BAR(A, 
         B, 
         C) 
     VALUES(rA(i), 
      rB(i), 
      rC(i)); 
END; 

Powyższe rozwiązanie pozwala zminimalizować przełączanie kontekstu między SQL a PL/SQL. Oracle 11g ma również lepsze wsparcie dla tabel rekordów, dzięki czemu nie musisz mieć oddzielnej tabeli PL/SQL dla każdej kolumny.

Ponadto, jeśli objętość danych jest bardzo duża, istnieje możliwość zmiany kodu w celu przetwarzania danych w partiach.

3

Myślę, że w tym pytaniu brakuje jednej ważnej informacji.

Ile wpisów wstawisz?

  1. Jeśli od 1 do ok. 10.000 to powinieneś użyć instrukcji SQL (Tak jak powiedzieli, jest to łatwe do zrozumienia i łatwe do napisania).
  2. Jeśli z cca. 10.000 do cca. 100.000 to powinieneś użyć kursora, ale powinieneś dodać logikę, aby zatwierdzić co 10.000 rekordów.
  3. Jeśli z cca. Od 100 000 do milionów, powinieneś używać zbiorczego gromadzenia dla lepszej wydajności.
2

Jak widać, czytając inne odpowiedzi, dostępnych jest wiele opcji. Jeśli właśnie robisz < 10k wierszy, powinieneś iść z drugą opcją.

Krótko mówiąc, w przybliżeniu> 10k, aby powiedzieć < 100k. To jest rodzaj szarej strefy. Wielu starych geerów będzie szczekać w dużych segmentach wycofywania. Ale szczerze mówiąc, sprzęt i oprogramowanie poczyniły niesamowite postępy, aby móc uciec z opcją 2 dla wielu rekordów, jeśli uruchamiasz tylko kod kilka razy. W przeciwnym razie prawdopodobnie powinieneś zatwierdzić każde 1k-10k wierszy. Oto fragment, którego używam. Podoba mi się, ponieważ jest krótki i nie muszę deklarować kursora. Plus ma zalety zbiorczej zbiórki i bez opłat.

begin 
    for r in (select rownum rn, t.* from foo t) loop 
     insert into bar (A,B,C) values (r.A,r.B,r.C); 
     if mod(rn,1000)=0 then 
      commit; 
     end if; 
    end; 
    commit; 
end; 

Znalazłem link ze strony Oracle, który ilustruje opcje w sposób bardziej szczegółowy.

+0

dzięki za wgląd! – Sathya

0

Można użyć:

luzem zbierać wraz z za wszystko, co nazywa się Bulk binding.

Ponieważ operator PL/SQL forall przyśpiesza 30 razy szybciej w przypadku prostych wstawień tabel.

BULK_COLLECT i Oracle FORALL razem te dwie funkcje są znane jako Bulk Binding. Wiązania zbiorcze to technika PL/SQL, w której zamiast wielu pojedynczych instrukcji wykonanych w celu pobrania z lub zapisania danych w tabeli wszystkie operacje są wykonywane jednocześnie, zbiorczo. Zapobiega to przełączaniu kontekstu, gdy silnik PL/SQL musi przejść do silnika SQL, a następnie z powrotem do silnika PL/SQL i tak dalej, gdy indywidualnie uzyskujesz dostęp do wierszy pojedynczo. Aby wykonać zbiorcze powiązania z instrukcjami INSERT, UPDATE i DELETE, należy dołączyć instrukcję SQL do instrukcji PL/SQL FORALL. Aby wykonać zbiorcze powiązania z instrukcjami SELECT, należy dodać klauzulę BULK COLLECT do oświadczenia SELECT zamiast używać INTO.

Poprawia wydajność.