游标的问题在于它们经常被滥用,无论是在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 秒有一个空触发器什么都不做。