Oracle PL/SQL BULK COLLECT: FORALL Eksempel

⚡ Smart oppsummering

MASSEHENTING i Oracle PL/SQL henter mange rader samtidig inn i en samling, mens FORALL sender masse-DML tilbake til databasen. Begge kutter kontekstbytter mellom SQL- og PL/SQL-motorene, noe som øker ytelsen.

  • 📦 MASSEINNSAMLING: Henter flere rader i én omgang inn i en samlingsvariabel, og erstatter langsom henting rad for rad.
  • 🔁 FOR ALLE: Kjører én INSERT-, UPDATE- eller DELETE-funksjon på tvers av en hel samling med én kontekstbryter.
  • 📏 LIMIT-klausul: Setter en grense for hvor mange rader hver BULK COLLECT henter laster, og beskytter øktminnet på store tabeller.
  • 📊 Attributter for MASSEINNSAMLING: Attributtet %BULK_ROWCOUNT(n) rapporterer hvor mange rader den n-te FORALL DML-setningen påvirket.
  • ⚙️ Nødvendige samlinger: INTO-klausulen må være målrettet mot en samlingstype, for eksempel en nestet tabell eller en assosiativ matrise.
  • 🤖 AI-hjelp: AI-assistenter som GitHub Copilot utarbeider BULK COLLECT- og FORALL-blokker og flagger en manglende LIMIT-klausul.

Oracle Oversikt over PL/SQL BULK COLLECT og FORALL med LIMIT-klausul

Hva er BULK COLLECT?

MASSEINNSAMLING reduserer kontekstbytter mellom SQL og PL/SQL-motoren, og lar SQL-motoren hente postene samtidig.

Oracle PL / SQL gir funksjonaliteten til å hente postene i bulk i stedet for å hente dem én etter én. Denne BULK COLLECT-funksjonen kan brukes i en SELECT-setning for å fylle ut postene i bulk, eller for å hente en markør i bulk. Siden BULK COLLECT henter postene i bulk, bør INTO-klausulen alltid inneholde en variabel av samlingstypen. Hovedfordelen med å bruke BULK COLLECT er at den øker ytelsen ved å redusere interaksjonen mellom databasen og PL/SQL-motoren.

Syntaks:

SELECT <column1> BULK COLLECT INTO bulk_variable FROM <table name>;
FETCH <cursor_name> BULK COLLECT INTO <bulk_variable>;

I syntaksen ovenfor brukes BULK COLLECT til å samle inn dataene fra SELECT- og FETCH-setningene.

FORALL klausul

FORALL-setningen utfører DML-operasjoner på data i bulk. Det ligner en FOR-løkkesetning, bortsett fra at i en FOR-løkke skjer handlinger på postnivå, mens det i FORALL ikke finnes noe LOOP-konsept. I stedet behandles alle dataene som finnes i det gitte området samtidig.

Syntaks:

FORALL <loop_variable> in <lower range> .. <higher range>

<DML operations>;

I syntaksen ovenfor vil den gitte DML-operasjonen bli utført for alle dataene som finnes mellom det nedre og øvre området.

LIMIT-klausul

Konseptet med masseinnsamling laster alle dataene inn i målinnsamlingsvariabelen som en bulk, dvs. at alle dataene vil bli fylt inn i innsamlingsvariabelen på én gang. Men dette er ikke tilrådelig når det totale antallet poster som må lastes inn er veldig stort, fordi når PL/SQL prøver å laste inn alle dataene, bruker det mer sesjonsminne. Derfor er det alltid lurt å begrense størrelsen på denne masseinnsamlingsoperasjonen.

Denne størrelsesgrensen kan enkelt oppnås ved å introdusere ROWNUM-betingelsen i SELECT-setningen, mens dette ikke er mulig for en markør.

For å overvinne dette, Oracle har gitt LIMIT-klausulen som definerer antall poster som må inkluderes i bulk.

Syntaks:

FETCH <cursor_name> BULK COLLECT INTO <bulk_variable> LIMIT <size>;

I syntaksen ovenfor bruker markørhentingssetningen BULK COLLECT-setningen sammen med LIMIT-klausulen.

BULK COLLECT-attributter

I likhet med markørattributter har BULK COLLECT %BULK_ROWCOUNT(n) som returnerer antall rader som er påvirket i den n-te DML-setningen i FORALL-setningen, dvs. den gir antallet poster som er påvirket i FORALL-setningen for hver enkelt verdi fra samlingsvariabelen. Begrepet 'n' indikerer sekvensen av verdien i samlingen som radantallet er nødvendig for.

Eksempel 1: I dette eksemplet vil vi projisere alle ansattnavnene fra emp-tabellen ved hjelp av BULK COLLECT, og vi skal også øke lønnen til alle ansatte med 5000 ved hjelp av FORALL.

Skjermbildet nedenfor viser dette BULK COLLECT- og FORALL-eksemplet sammen med utdataene i Oracle.

BULK COLLECT med LIMIT og FORALL eksempel på oppdatering av ansattlønn i Oracle PL / SQL

DECLARE
CURSOR guru99_det IS SELECT emp_name FROM emp;
TYPE lv_emp_name_tbl IS TABLE OF VARCHAR2(50);
lv_emp_name lv_emp_name_tbl;
BEGIN
OPEN guru99_det;
FETCH guru99_det BULK COLLECT INTO lv_emp_name LIMIT 5000;
FOR c_emp_name IN lv_emp_name.FIRST .. lv_emp_name.LAST
LOOP
Dbms_output.put_line('Employee Fetched:'||c_emp_name);
END LOOP;
FORALL i IN lv_emp_name.FIRST .. lv_emp_name.LAST
UPDATE emp SET salary=salary+5000 WHERE emp_name=lv_emp_name(i);
COMMIT;
Dbms_output.put_line('Salary Updated');
CLOSE guru99_det;
END;
/

Produksjon

Employee Fetched:BBB
Employee Fetched:XXX
Employee Fetched:YYY
Salary Updated

Code Forklaring:

  • Code linje 2: Deklarerer markøren guru99_det for setningen 'SELECT emp_name FROM emp'.
  • Code linje 3: Deklarerer lv_emp_name_tbl som en tabelltype for VARCHAR2(50).
  • Code linje 4: Deklarerer lv_emp_name som lv_emp_name_tbl-typen.
  • Code linje 6: Åpne markøren.
  • Code linje 7: Henter markøren ved hjelp av BULK COLLECT med LIMIT-størrelsen 5000 inn i variabelen lv_emp_name.
  • Code linje 8–11: Setter opp en FOR-løkke for å skrive ut alle postene i samlingen lv_emp_name.
  • Code linje 12: Bruk FORALL til å oppdatere lønnen til alle ansatte med 5000.
  • Code linje 14: Å begå Transaksjonen.

Spørsmål og svar

Nei. En BULK COLLECT SELECT genererer aldri NO_DATA_FOUND; i stedet returnerer den en tom samling. Test alltid samlingen med .COUNT-metoden før du ser på den.ping, ellers kan du behandle null rader stille.

SAVE EXCEPTIONS lar FORALL fortsette å kjøre når individuelle rader feiler. Feilende rader lagres i SQL%BULK_EXCEPTIONS, deretter Oracle hever ORA-24381, som du fanger i en unntak behandler for å inspisere hver feil.

Bruk BULK COLLECT når en løkke leser mange rader. markør FOR-løkken henter én rad per bryter, så massehenting pluss FORALL kan kjøre mange ganger raskere på store resultatsett.

BULK COLLECT returnerer mange rader samtidig, så den trenger en container med flere rader. INTO-målet må være et samling som for eksempel en nestet tabell, VARRAY eller assosiativ matrise, ikke en enkelt skalar variabel.

Nei. En FORALL-header kjører nøyaktig én INSERT-, UPDATE-, DELETE- eller MERGE-klausul. Bare verdiene i VALUES- og WHERE-klausulene kan endres per iterasjon. For flere setninger, bruk separate FORALL-setninger.

Massebehandling kan være flere ganger til over hundre ganger raskere enn rad-for-rad-kode, fordi BULK COLLECT og FORALL kollapser tusenvis av motorkontekstbrytere til noen få, noe som reduserer overhead på store datavolumer kraftig.

Ja. GitHub Copilot lager utkast til BULK COLLECT-hentinger, FORALL DML-løkker og LIMIT-klausuler fra en kommentar, og foreslår deklarasjoner av samlingstyper, men du bør gjennomgå batchstørrelser og feilhåndtering selv.

AI-assistenter skanner løkker som henter eller endrer én rad om gangen og anbefaler å skrive dem om med BULK COLLECT, LIMIT og FORALL. Denne maskinlæringsgjennomgangen fanger opp manglende LIMIT-grenser og ytelsesflaskehalser før produksjon.

Oppsummer dette innlegget med: