楼主: newkid

[每日一题] PL/SQL CHALLENGE 每日一题

[复制链接]
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
281#
 楼主| 发表于 2012-1-24 01:56 | 只看该作者
2012-1-19 答案AC. 注意dbms_sql.to_refcursor是11G才有的功能。

B:会出现编译错误,无法运行:
PLS-00363: expression 'DBMS_SQL.OPEN_CURSOR' cannot be used as an assignment
dbms_sql.to_refcursor的参数被定义为IN OUT, 你不能把另一个函数作为参数传进去。
D:这里试图调用dbms_sql.to_refcursor来把一个数字游标转换为游标变量。可是在此之前并没有调用DBMS_SQL.OPEN_CURSOR来获得这个数字游标。因此DBMS_SQL无法再继续使用了,你必须重新创建一个会话才可以使用DBMS_SQL。这个特性是处于安全因素的考虑。

===================================
2012-1-20
作者:Steven Feuerstein
难度:中

下列哪些选项在执行后会显示:
1
2
3
Done

(A)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
   LOOP
      l_index := l_index + 1;
      EXIT next_step WHEN l_index > 3;
      DBMS_OUTPUT.put_line (l_index);
   END LOOP;

  <<next_step>>
   DBMS_OUTPUT.put_line ('Done');
END;
/

(B)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
   <<first_step>>
   LOOP
      l_index := l_index + 1;
      EXIT first_step WHEN l_index > 3;
      DBMS_OUTPUT.put_line (l_index);
   END LOOP;

  <<next_step>>
   DBMS_OUTPUT.put_line ('Done');
END;
/

(C)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
   LOOP
      l_index := l_index + 1;
      DBMS_OUTPUT.put_line (l_index);
      EXIT WHEN l_index > 3;
   END LOOP;

   DBMS_OUTPUT.put_line ('Done');
END;
/

(D)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
   LOOP
      l_index := l_index + 1;
      EXIT TO next_step WHEN l_index > 3;
      DBMS_OUTPUT.put_line (l_index);
   END LOOP;

  <<next_step>>
   DBMS_OUTPUT.put_line ('Done');
END;
/

(E)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
   LOOP
      l_index := l_index + 1;

      IF l_index > 3
      THEN
         GOTO next_step;
      END IF;

      DBMS_OUTPUT.put_line (l_index);
   END LOOP;

  <<next_step>>
   DBMS_OUTPUT.put_line ('Done');
END;
/


(F)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
  <<next_step>>
   LOOP
      l_index := l_index + 1;

      IF l_index > 3
      THEN
         GOTO next_step;
      END IF;

      DBMS_OUTPUT.put_line (l_index);
   END LOOP;

   DBMS_OUTPUT.put_line ('Done');
END;
/

(G)
DECLARE
   l_index   PLS_INTEGER := 0;
BEGIN
  <<first_step>>
   WHILE (l_index <= 3)
   LOOP
      l_index := l_index + 1;
      EXIT first_step WHEN l_index > 3;
      DBMS_OUTPUT.put_line (l_index);
   END LOOP;

  <<next_step>>
   DBMS_OUTPUT.put_line ('Done');
END;
/   

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
282#
 楼主| 发表于 2012-1-25 04:49 | 只看该作者
2012-1-20 答案BEG.
A: 标记放错了,应该在LOOP前面。
C: 输出语句放在EXIT之前是错误,导致最后一轮的4也被输出。
D: 语法错误,EXIT不能带TO
F: GOTO导致循环重新开始,永远不会结束。

===================================
2012-1-23 重复异常定义
作者:Steven Feuerstein
难度:中

我建立了如下的包:
CREATE OR REPLACE PACKAGE plch_pkg
AS
   my_exception   EXCEPTION;
   PRAGMA EXCEPTION_INIT (my_exception, -1);
END plch_pkg;
/

然后我开始写这个过程:
CREATE OR REPLACE PROCEDURE plch_dupexc
IS
   my_exception   EXCEPTION;
   PRAGMA EXCEPTION_INIT (my_exception, -1);
BEGIN
   RAISE my_exception;

下列哪些选项会完成这个过程,使得下列代码块执行之后会显示"My exception handled!"

(A)
EXCEPTION
   WHEN my_exception
   THEN
      DBMS_OUTPUT.put_line ('My exception handled!');
   WHEN plch_pkg.my_exception
   THEN
      DBMS_OUTPUT.put_line ('My exception handled!');
   WHEN DUP_VAL_ON_INDEX
   THEN
      DBMS_OUTPUT.put_line ('My exception handled!');
END;

(B)
EXCEPTION
   WHEN my_exception OR
        plch_pkg.my_exception OR  
        DUP_VAL_ON_INDEX
   THEN
      DBMS_OUTPUT.put_line ('My exception handled!');
END;

(C)
EXCEPTION
   WHEN plch_pkg.my_exception
   THEN
      DBMS_OUTPUT.put_line ('My exception handled!');
END;

(D)
EXCEPTION
   WHEN DUP_VAL_ON_INDEX
   THEN
      DBMS_OUTPUT.put_line ('My exception handled!');
END;

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
283#
 楼主| 发表于 2012-1-26 01:07 | 只看该作者
2012-1-23 答案BCD.
A: 会报如下错误:
PLS-00484: redundant exceptions 'MY_EXCEPTION' and 'MY_EXCEPTION' must appear in same exception handler
因为本地声明的my_exception和包里头定义的my_exception异常共享同一个错误代码(-1).
B: 用OR分隔多个异常的捕获,是有效的语法。当然此处有些不必要因为它们全部共享同一个错误代码(-1).
C,D: 虽然捕获异常名称和抛出异常名称不同,但由于它们共享同一个错误代码,仍然能够捕获。
===================================
2012-1-24 动态SQL中引用标识符
作者:Steven Feuerstein
难度:中

我定义了这个函数来动态获取一个标识符的日期值:

FUNCTION plch_date_value (identifier_in IN VARCHAR2) RETURN DATE
IS
   l_value   DATE;
BEGIN
   EXECUTE IMMEDIATE
      'BEGIN :actual_value := ' || identifier_in || '; END;'
      USING OUT l_value;
   RETURN l_value;
END;

下列哪些选项执行之后会显示"New Year"?

(A)
DECLARE
   dt   DATE := TO_DATE ('2009-01-01', 'YYYY-MM-DD');
BEGIN
   IF TO_CHAR (plch_date_value ('dt'), 'MM-DD') = '01-01'
   THEN
      DBMS_OUTPUT.put_line ('New Year');
   END IF;
END;
/

(B)
CREATE OR REPLACE PACKAGE plch_pkg
IS
   dt   DATE := TO_DATE ('2009-01-01', 'YYYY-MM-DD');
END;
/

BEGIN
   IF TO_CHAR (plch_date_value ('plch_pkg.dt'), 'MM-DD') =
         '01-01'
   THEN
      DBMS_OUTPUT.put_line ('New Year');
   END IF;
END;
/

(C)
DECLARE
   dt   DATE := TO_DATE ('2009-01-01', 'YYYY-MM-DD');
BEGIN
   IF TO_CHAR (plch_date_value (dt), 'MM-DD') = '01-01'
   THEN
      DBMS_OUTPUT.put_line ('New Year');
   END IF;
END;
/

(D)
CREATE OR REPLACE PACKAGE plch_pkg
IS
   FUNCTION dt
      RETURN DATE;
END;
/

CREATE OR REPLACE PACKAGE BODY plch_pkg
IS
   FUNCTION dt
      RETURN DATE
   IS
   BEGIN
      RETURN TO_DATE ('2009-01-01', 'YYYY-MM-DD');
   END;
END;
/

BEGIN
   IF TO_CHAR (plch_date_value ('plch_pkg.dt'), 'MM-DD') = '01-01'
   THEN
      DBMS_OUTPUT.put_line ('New Year');
   END IF;
END;
/

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
284#
 楼主| 发表于 2012-1-27 05:32 | 只看该作者
2012-1-24 答案 BD.
A: 这个选项会出现错误:
PLS-00201: identifier 'DT' must be declared
虽然函数plch_date_value是在DT定义的范围之内执行,但是对于动态PLSQL块来说,变量DT不在其范围之内。
B: 动态PLSQL块可以引用SCHEMA级别的元素。既然DT现在是在一个包的声明中被定义,动态PLSQL块可以引用它并显示其值。
C: 这个选项试图传入变量值而不是变量名。ORACLE会隐式把DATE转换为字符串,然后替换到动态PLSQL中并试图执行它,变成这样:(日期格式取决于nls_date_format设定)

BEGIN :actual_value := 01-JAN-09; END;

这个语法是错误的。
D: 这个选项把日期值作为函数返回,动态PLSQL可以正确访问这个包里定义的函数。
==========================================================

2012-1-25: 不完整的创建过程语句

作者:Jeff Kemp
难度:中

下列的哪些选项可用来代替 "/* REPLACE CODE HERE*/",从而使得下面的SELECT语句的结果会返回"PROCEDURE"?

DROP PROCEDURE plch_test;

/* REPLACE CODE HERE */
/

SELECT object_type FROM user_objects WHERE object_name = 'PLCH_TEST';

(A)
CREATE PROCEDURE plch_test;

(B)
CREATE PROCEDURE plch_test AS;

(C)
CREATE PROCEDURE plch_test NULL;

(D)
CREATE PROCEDURE plch_test IS BEGIN NULL; END;

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
285#
 楼主| 发表于 2012-1-28 02:35 | 只看该作者
2012-1-25 答案 BCD.
只要在过程名称之后还带着任何东西,过程就会被创建,进入数据字典,哪怕有编译错误。
选项A只有过程名称,所以不被创建。

==========================================================

2012-1-26: 触发器中的UPDATING函数和带引号列名

作者:Steven Feuerstein
难度:高

我创建了下列的表并填入数据,同时在表上创建了一个触发器:
CREATE TABLE plch_tab
(
   abc     VARCHAR2 (100)
, "abc"   VARCHAR2 (100)
)
/

BEGIN
   INSERT INTO plch_tab
        VALUES ('ABC', 'abc');

   COMMIT;
END;
/

CREATE OR REPLACE TRIGGER plch_tab_trg
   AFTER UPDATE
   ON plch_tab
   FOR EACH ROW
DECLARE
   PROCEDURE check_updating (column_in IN VARCHAR2, title_in IN VARCHAR2)
   IS
   BEGIN
      IF UPDATING (column_in)
      THEN
         DBMS_OUTPUT.put_line (title_in || '     updating');
      ELSE
         DBMS_OUTPUT.put_line (title_in || ' not updating');
      END IF;
   END check_updating;
BEGIN
   check_updating ('abc',   'Lower case         :');

   check_updating ('"abc"', 'Lower double quotes:');

   check_updating ('ABC',   'Upper case         :');
END;
/

下列代码块执行之后会显示什么?
BEGIN
   DBMS_OUTPUT.put_line ('Update "abc"');

   UPDATE plch_tab
      SET "abc" = '1';

   DBMS_OUTPUT.put_line ('Update ABC');

   UPDATE plch_tab
      SET abc = '1';
END;
/


(A)
Update "abc"
Lower case         : not updating
Lower double quotes:     updating
Upper case         : not updating
Update ABC
Lower case         :     updating
Lower double quotes: not updating
Upper case         :     updating


(B)
Update "abc"
Lower case         :     updating
Lower double quotes: not updating
Upper case         :     updating
Update ABC
Lower case         :     updating
Lower double quotes: not updating
Upper case         :     updating

(C)
Update "abc"
Lower case         :     updating
Lower double quotes:     updating
Upper case         :     updating
Update ABC
Lower case         :     updating
Lower double quotes:     updating
Upper case         :     updating

(D)
Update "abc"
Lower case         : not updating
Lower double quotes: not updating
Upper case         : not updating
Update ABC
Lower case         : not updating
Lower double quotes: not updating
Upper case         : not updating

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
286#
 楼主| 发表于 2012-1-31 00:56 | 只看该作者
2012-1-26 答案B.
非常遗憾,UPDATING这个函数不支持大小写敏感的列名,也不支持双引号。要不然答案就是A了。UPDATING总是自动把列名转换为大写然后到数据库字典里去找匹配。
============================================
2012-1-27 带行数限制的BULK FETCH操作
作者:Steven Feuerstein
难度:中

我创建了这张表并填入数据:
CREATE TABLE plch_employees
(
   employee_id   INTEGER,
   last_name     VARCHAR2 (100),
   salary        NUMBER
)
/

BEGIN
   INSERT INTO plch_employees
        VALUES (100, 'Ellison', 1000000);

   INSERT INTO plch_employees
        VALUES (200, 'Gates', 1000000);

   INSERT INTO plch_employees
        VALUES (300, 'Zuckerberg', 1000000);

   COMMIT;
END;
/

然后我创建了这个包:
CREATE OR REPLACE PACKAGE plch_pkg
IS
   CURSOR employees_cur
   IS
      SELECT * FROM plch_employees;

   TYPE employees_t IS TABLE OF plch_employees%ROWTYPE;

   PROCEDURE show_employees (employees_in IN employees_t);
END;
/

CREATE OR REPLACE PACKAGE BODY plch_pkg
IS
   PROCEDURE show_employees (employees_in IN employees_t)
   IS
   BEGIN
      DBMS_OUTPUT.put_line (employees_in.COUNT);
   END;
END;
/

下列哪些选项在执行之后会显示这两行文本:
2
1

(A)
DECLARE
   c_limit   CONSTANT PLS_INTEGER := 2;

   l_employees        plch_pkg.employees_t;
BEGIN
   OPEN plch_pkg.employees_cur;

   LOOP
      FETCH plch_pkg.employees_cur
      BULK COLLECT INTO l_employees
      LIMIT c_limit;

      EXIT WHEN l_employees.COUNT = 0;
      plch_pkg.show_employees (l_employees);
   END LOOP;

   CLOSE plch_pkg.employees_cur;
END;
/

(B)
DECLARE
   l_employees   plch_pkg.employees_t;
BEGIN
   OPEN plch_pkg.employees_cur;

   LOOP
      FETCH plch_pkg.employees_cur
      BULK COLLECT INTO l_employees;
      EXIT WHEN l_employees.COUNT = 0;
      plch_pkg.show_employees (l_employees);
   END LOOP;

   CLOSE plch_pkg.employees_cur;
END;
/

(C)
DECLARE
   c_limit   CONSTANT PLS_INTEGER := 2;
   l_employees   plch_pkg.employees_t;
BEGIN
   OPEN plch_pkg.employees_cur;

   LOOP
      FETCH plch_pkg.employees_cur
      BULK COLLECT INTO l_employees LIMIT c_limit;
      EXIT WHEN l_employees.COUNT = 3;
      plch_pkg.show_employees (l_employees);
   END LOOP;

   CLOSE plch_pkg.employees_cur;
END;
/

(D)
DECLARE
   c_limit   CONSTANT PLS_INTEGER := 2;
   l_employees        plch_pkg.employees_t;
BEGIN
   OPEN plch_pkg.employees_cur;

   LOOP
      FETCH plch_pkg.employees_cur
      BULK COLLECT c_limit INTO l_employees;
      EXIT WHEN l_employees.COUNT = 0;
      plch_pkg.show_employees (l_employees);
   END LOOP;

   CLOSE plch_pkg.employees_cur;
END;
/

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
287#
 楼主| 发表于 2012-2-1 03:57 | 只看该作者
2012-1-27 答案A.
B: 没有包含LIMIT, 因此三行会被一下子取出来,显示3
C: 这是个死循环,因为LIMIT是2, 永远不会出现l_employees.COUNT = 3的情况。
D: 语法错。
===========================================================
2012-1-30 BULK COLLECT 获取多行数据
作者:Steven Feuerstein
难度:中

我创建了这张表并填入数据:
CREATE TABLE plch_parts
(
   partnum    INTEGER PRIMARY KEY,
   partname   VARCHAR2 (100) UNIQUE
)
/

BEGIN
   INSERT INTO plch_parts
        VALUES (1, 'Mouse');

   INSERT INTO plch_parts
        VALUES (100, 'Keyboard');

   INSERT INTO plch_parts
        VALUES (500, 'Monitor');

   COMMIT;
END;
/


我创建了一个存储过程来显示所有符合过滤条件的部件名称:
CREATE OR REPLACE PROCEDURE plch_by_name (filter_in IN VARCHAR2)
IS
   TYPE parts_t IS TABLE OF plch_parts%ROWTYPE;
   l_parts   parts_t;
   l_count   PLS_INTEGER;
BEGIN
   l_parts := parts_t ();

   SELECT COUNT (*)
     INTO l_count
     FROM plch_parts
    WHERE partname LIKE filter_in;

   l_parts.EXTEND (l_count);

   SELECT *
     BULK COLLECT INTO l_parts
     FROM plch_parts
    WHERE partname LIKE filter_in;

   FOR indx IN l_parts.FIRST .. l_parts.LAST
   LOOP
      DBMS_OUTPUT.put_line (l_parts (indx).partname);
   END LOOP;
END;
/

我执行了这个代码块:
BEGIN
   plch_by_name ('M%');
   plch_by_name ('%X%');
END;
/

下列关于这个存储过程以及匿名代码块的执行情况的判断哪些是正确的?

(A)
匿名块会出错,有一个未处理异常。


(B)
这几行代码可以从存储过程中去除而不会对输出有任何影响:
l_parts := parts_t ();

SELECT COUNT (*)
  INTO l_count
  FROM plch_parts
WHERE partname LIKE filter_in;

l_parts.EXTEND (l_count);

(C)
FOR循环必须用WHILE循环代替,用FIRST和NEXT方法从头到尾遍历集合,这样才能避免FOR循环中可能出现的NO_DATA_FOUND异常。

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
288#
 楼主| 发表于 2012-2-2 04:00 | 只看该作者
本帖最后由 newkid 于 2012-2-2 04:21 编辑

2012-1-30 答案 AB
A: 既然没有一个名字中包含"X", 在BULK COLLECT查询之后l_parts集合为空。所以FIRST 和 LAST都返回NULL。如果在一个FOR循环中,下限和上限有一个为NULL, ORACLE会抛出VALUE_ERROR异常。
B: BULK COLLECT之前没有必要对集合进行初始化。ORACLE会自动初始化。
C: BULK COLLECT获取的集合都是密集的,所以从FIRST走到LAST的FOR循环不会报NO_DATA_FOUND异常。
==================================
2012-1-31 11GR2下的RESULT_CACHE函数
作者:Valentin Nikotin
难度:高
数据库版本:11GR2

我创建了两张表并填入数据:

create table plch_a(col varchar2(2));
create table plch_b(col varchar2(2));

insert into plch_a values ('a1');
insert into plch_b values ('b1');
commit;

然后我创建了如下函数:
create or replace function plch_result_cache
  return varchar2 result_cache
is
  res varchar2(2);
begin
  dbms_output.put_line('Hello!');
  select col into res from plch_a;
  if res = 'a2' then
    select col into res from plch_b;
  end if;  
  return res;
end;

我执行下列代码块之后,屏幕上会显示什么?
begin
  -- a1, b1
  dbms_output.put_line(plch_result_cache);
  update plch_b set col = 'b2';
  commit;
  -- a1, b2
  dbms_output.put_line(plch_result_cache);
  update plch_a set col = 'a2';
  commit;
  -- a2, b2
  dbms_output.put_line(plch_result_cache);
  update plch_b set col = 'b3';
  commit;
  -- a2, b3
  dbms_output.put_line(plch_result_cache);
end;
/

(A)
Hello!
a1
Hello!
a1
Hello!
b2
Hello!
b3

(B)
Hello!
a1
a1
a1
a1

(C)
Hello!
a1
a1
Hello!
b2
Hello!
b3

(D)
Hello!
a1
a1
Hello!
b2
b2

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
289#
 楼主| 发表于 2012-2-3 00:16 | 只看该作者
2012-1-31 我也以为是A, 正确答案是C.

Oracle PL/SQL 允许你创建基于不同类型的程序单元的应用,这些程序单元包括:基本块(匿名块和嵌套块),函数,过程,包,触发器和对象类型。

PL/SQL 函数结果缓存机制提供了一种方法来将PL/SQL 函数的结果缓存在SGA里面,这些结果对运行你运用的任何会话都是可见的。缓存机制高效而且易于使用,并且使你从设计、开发自己的缓存、缓存管理机制中解脱出来。

注意:函数缓存功能只在ORACLE数据库企业版中提供。在标准版中这项功能被屏蔽了。

为了打开函数结果缓存,你所需要做的一切只是把RESULT_CACHE子句加到你的函数头(如果是在包中,则包头和包体都要加)。

当一个结果缓存函数被调用,系统就会检查缓存。如果缓存里有上次调用结果而且参数值一样,则系统直接吧缓存结果返回给调用者,而不会执行函数体。如果缓存里没有该结果,则系统执行函数体并把结果加入到缓存(针对这一组参数值),然后把控制权返回给调用者。

函数结果缓存通常存放着在函数体中查询的来自一张或多张表的数据。ORACLE需要确保这份数据拷贝没有变脏。

ORACLE通过两种机制来确保数据的干净:

1. 一旦对一张表的修改被一个会话提交,所有依赖于这张表的结果将被清除。随后对依赖于该表的函数的调用会导致数据重新进入缓存。
2. 一旦你在自己的会话中修改了表数据,则依赖于这些表的缓存将被忽略。也就是说,依赖于这些表的缓存函数体永远会被执行,直到你提交或回滚事务为止。

在一个结果缓存函数运行的时候, ORACLE 数据库11g R2会自动侦测所有的数据源(表和视图)。如果任何对这些数据源的修改被提交,缓存结果就无效了,必须重新计算。

结果缓存机制会在函数的每一次调用跟踪这种依赖关系。取决于函数中的逻辑,不同的表可能会在不同的参数下被查询。在本题中,仅当plch_a表的一行被修改为"a2"时,缓存才会对plch_b产生依赖。(跟踪到这种细致程度,令人惊讶!)

你可以查询V$RESULT_CACHE_DEPENDENCY来查看缓存的依赖关系,如下所示:


drop table plch_a purge;
drop table plch_b purge;

create table plch_a(col varchar2(2));
create table plch_b(col varchar2(2));

insert into plch_a values ('a1');
insert into plch_b values ('b1');
commit;

drop function plch_result_cache;

create or replace function plch_result_cache return varchar2 result_cache is
  res varchar2(2);
begin
  dbms_output.put_line('Hello!');
  select col into res from plch_a;
  if res = 'a2' then
    select col into res from plch_b;
  end if;  
  return res;
end;
/

-- grant select on sys.v_$result_cache_objects to test_user;
-- grant select on sys.v_$result_cache_dependency to test_user;

create or replace view plch_result_cache_dependencies as
select d.result_id, dep.name
from v$result_cache_dependency d
   , v$result_cache_objects res
   , v$result_cache_objects dep
where res.id = d.result_id
  and dep.id = d.depend_id
  and res.name like '"%"."PLCH_RESULT_CACHE"%';

测试脚本:
select plch_result_cache from dual;
select * from plch_result_cache_dependencies;
update plch_b set col = 'b2';
commit;
select plch_result_cache from dual;
update plch_a set col = 'a2';
commit;
select plch_result_cache from dual;
select * from plch_result_cache_dependencies;
update plch_b set col = 'b3';
commit;
select plch_result_cache from dual;
update plch_a set col = 'a3';
commit;
select plch_result_cache from dual;
select * from plch_result_cache_dependencies;

在11.2的SQL*Plus下结果:
SQL> select plch_result_cache a from dual;

A
--
a1

Hello!
SQL> select * from plch_result_cache_dependencies;

RESULT_ID NAME
---------- ----------------------------
        77 TEST_USER.PLCH_A
        77 TEST_USER.PLCH_RESULT_CACHE

SQL> update plch_b set col = 'b2';

1 row updated.

SQL> commit;

Commit complete.

SQL> select plch_result_cache a from dual;

A
--
a1

SQL> update plch_a set col = 'a2';

1 row updated.

SQL> commit;

Commit complete.

SQL> select plch_result_cache a from dual;

A
--
b2

Hello!
SQL> select * from plch_result_cache_dependencies;

RESULT_ID NAME
---------- -----------------------------
        77 TEST_USER.PLCH_B
        77 TEST_USER.PLCH_A
        77 TEST_USER.PLCH_RESULT_CACHE

SQL> update plch_b set col = 'b3';

1 row updated.

SQL> commit;

Commit complete.

SQL> select plch_result_cache a from dual;

A
--
b3

Hello!
SQL> update plch_a set col = 'a3';

1 row updated.

SQL> commit;

Commit complete.

SQL> select plch_result_cache a from dual;

A
--
a3

Hello!

SQL> select * from plch_result_cache_dependencies;

RESULT_ID NAME
---------- -----------------------------
        77 TEST_USER.PLCH_A
        77 TEST_USER.PLCH_RESULT_CACHE

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
290#
 楼主| 发表于 2012-2-3 00:22 | 只看该作者
2012-2-1 编译器优化
作者:Steven Feuerstein
难度:中
数据库版本:10GR2


我在一个Oracle9i实例上创建了如下的类型和过程:
CREATE OR REPLACE TYPE plch_numbers_t IS TABLE OF NUMBER
/

CREATE OR REPLACE PROCEDURE plch_loop (parts_in IN plch_numbers_t)
IS
   l_result   NUMBER := 0;
BEGIN
   FOR indx IN 1 .. 10000000
   LOOP
      l_result := l_result + (parts_in (1) + parts_in (2)) / parts_in (3);
   END LOOP;

   DBMS_OUTPUT.put_line (l_result);
END;
/

现在我们升级到ORACLE 数据库10gR2。下列哪些选项描述了我能够采取的步骤来改善plch_loop过程的性能?

(A)
把过程改为:
CREATE OR REPLACE PROCEDURE plch_loop (parts_in IN plch_numbers_t)
IS
   l_computation   NUMBER
                      := (parts_in (1) + parts_in (2)) / parts_in (3);
   l_result        NUMBER := 0;
BEGIN
   FOR indx IN 1 .. 10000000
   LOOP
      l_result := l_result + l_computation;
   END LOOP;

   DBMS_OUTPUT.put_line (l_result);
END;
/

(B)
把过程改为:
CREATE OR REPLACE PROCEDURE plch_loop3 (parts_in IN plch_numbers_t)
IS
   l_computation   NUMBER;
   l_result        NUMBER := 0;
BEGIN
   FOR indx IN 1 .. 10000000
   LOOP
      l_computation := (parts_in (1) + parts_in (2)) / parts_in (3);
      l_result := l_result + l_computation;
   END LOOP;

   DBMS_OUTPUT.put_line (l_result);
END;
/

(C)
在拥有plch_loop的SCHEMA执行下列语句:
ALTER PROCEDURE plch_loop COMPILE plsql_optimize_level = 1
/

(D)
在拥有plch_loop的SCHEMA执行下列语句:
ALTER PROCEDURE plch_loop COMPILE plsql_optimize_level = 0
/

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表