Wat er mis is met cursors is dat ze vaak worden misbruikt, zowel in Oracle
en in MS SQL
.
Cursor is voor het bijhouden van een stabiele resultatenset die u rij voor rij kunt ophalen. Ze worden impliciet gemaakt wanneer uw zoekopdracht wordt uitgevoerd en gesloten wanneer deze is voltooid.
Het bijhouden van zo'n resultatenset vereist natuurlijk wat middelen:locks
, latches
, memory
, zelfs disk space
.
Hoe sneller deze middelen worden vrijgemaakt, hoe beter.
Een cursor openhouden is als een koelkastdeur openhouden
Je doet het niet urenlang zonder noodzaak, maar het betekent niet dat je nooit je koelkast moet openen.
Dat betekent dat:
- U krijgt uw resultaten niet rij voor rij en somt ze niet op:u roept de
SQL
aan 'sSUM
in plaats daarvan. - Je voert geen hele query uit en krijgt de eerste resultaten van de cursor:je voegt een
rownum <= 10
toe voorwaarde voor uw vraag
, enz.
Wat betreft Oracle
, vereist het verwerken van uw cursors in een procedure de beruchte SQL/PLSQL context switch
wat elke keer gebeurt als je een resultaat krijgt van een SQL
zoek uit de cursor.
Het gaat om het doorgeven van grote hoeveelheden gegevens tussen threads en het synchroniseren van de threads.
Dit is een van de meest irritante dingen in Oracle
.
Een van de minder voor de hand liggende gevolgen van dat gedrag is dat triggers in Oracle indien mogelijk moeten worden vermeden.
Een trigger maken en een DML
aanroepen functie is gelijk aan het openen van de cursor, het selecteren van de bijgewerkte rijen en het aanroepen van de triggercode voor elke rij van deze cursor.
Alleen al het bestaan van de trigger (zelfs de lege trigger) kan een DML
vertragen bewerking 10 times
of meer.
Een testscript op 10g
:
SQL> CREATE TABLE trigger_test (id INT NOT NULL)
2 /
Table created
Executed in 0,031 seconds
SQL> INSERT
2 INTO trigger_test
3 SELECT level
4 FROM dual
5 CONNECT BY
6 level <= 1000000
7 /
1000000 rows inserted
Executed in 1,469 seconds
SQL> COMMIT
2 /
Commit complete
Executed in 0 seconds
SQL> TRUNCATE TABLE trigger_test
2 /
Table truncated
Executed in 3 seconds
SQL> CREATE TRIGGER trg_test_ai
2 AFTER INSERT
3 ON trigger_test
4 FOR EACH ROW
5 BEGIN
6 NULL;
7 END;
8 /
Trigger created
Executed in 0,094 seconds
SQL> INSERT
2 INTO trigger_test
3 SELECT level
4 FROM dual
5 CONNECT BY
6 level <= 1000000
7 /
1000000 rows inserted
Executed in 17,578 seconds
1.47
seconden zonder trigger, 17.57
seconden met een lege trigger die niets doet.