Това, което не е наред с курсорите, е, че често се злоупотребява с тях, както в Oracle
и в MS SQL
.
Курсорът служи за поддържане на стабилен набор от резултати, който можете да извличате ред по ред. Те се създават имплицитно, когато вашата заявка се изпълнява, и се затварят, когато тя приключи.
Разбира се, поддържането на такъв набор от резултати изисква някои ресурси:locks
, latches
, memory
, дори disk space
.
Колкото по-бързо се освободят тези ресурси, толкова по-добре.
Да държите курсор отворен е като да държите вратата на хладилника отворена
Не го правите с часове без необходимост, но това не означава, че никога не трябва да отваряте хладилника си.
Това означава, че:
- Не получавате резултатите си ред по ред и не ги сумирате:извиквате
SQL
SUM
на вместо това. - Не изпълнявате цялата заявка и не получавате първите резултати от курсора:добавяте
rownum <= 10
условие за вашата заявка
и т.н.
Що се отнася до Oracle
, обработката на вашите курсори вътре в процедура изисква прословутото SQL/PLSQL context switch
което се случва всеки път, когато получите резултат от SQL
заявка извън курсора.
Това включва предаване на големи количества данни между нишки и синхронизиране на нишките.
Това е едно от най-дразнещите неща в Oracle
.
Една от по-малко очевидните последици от това поведение е, че тригерите в Oracle трябва да се избягват, ако е възможно.
Създаване на тригер и извикване на DML
функция е равна на отваряне на курсора, избиране на актуализираните редове и извикване на тригерния код за всеки ред на този курсор.
Самото съществуване на тригера (дори празния тригер) може да забави DML
операция 10 times
или повече.
Тестови скрипт на 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
секунди без тригер, 17.57
секунди с празен тригер, който не прави нищо.