最有效的PLSQL存储过程版本

时间:2013-09-20 15:57:06

标签: stored-procedures plsql sql-execution-plan

我正在编写一个PL / SQL存储过程,它将在.NET应用程序中调用。

我的存储过程必须返回

  • 基于输入部件号
  • 的部件修订表中的值计数
  • 此表中当前为输入部件号
  • 捕获的最低修订级别的名称
  • 与此部件号关联的数据库中特定单元的修订级别名称和输入单元ID。

    单位的修订级别名称在单独的表格中捕获,与零件修订表没有直接关系。

相关数据结构:

Table Part has columns:
    Part_ID int PK
    Part_Number varchar2(30)

Table Part_Revisions:
    Revision_ID int PK
    Revision_Name varchar2(100)
    Revision_Level int
    Part_ID int FK

Table Unit:
    Unit_ID int PK
    Part_ID int FK

Table Unit_Revision:
    Unit_ID int PK
    Revision_Name varchar2(100)

话虽如此,我最有效的方法是将这三个数据元素查询到输出的引用游标中?我正在考虑以下选项1:

OPEN cursor o_Return_Cursor FOR
SELECT (SELECT COUNT (*)
          FROM Part_Revisions pr
          inner join PART pa on pa.part_id = pr.part_id
         WHERE PA.PART_NO = :1 )
          AS "Cnt_PN_Revisions",
       (select pr1.Revision_Name from Part_Revisions pr1 
            inner join PART pa1 on pa1.part_id = pr1.part_id
            WHERE PA.PART_NO = :1 and pr1.Revision_Level = 0)
          AS "Input_Revison_Level",
       (select ur.Revision_Name from Unit_Revision ur
            WHERE ur.Unit_ID = :2) as "Unit_Revision"
        FROM DUAL;

然而,Toad的解释计划返回成本:2基数:1,我怀疑是由于我在主查询中使用DUAL。将其与选项2进行比较:

select pr.Revision_Name, (select count(*) 
                           from Part_Revisions pr1
                           where pr1.part_id = pr.part_id) as "Count",
                         (select ur.Revision_Name 
                           from Unit_Revision ur
                           where ur.Unit_ID = :2) as "Unit_Revision"
from Part_Revisions pr 
            inner join PART pa on pa.part_id = pr.part_id
            WHERE PA.PART_NO = :1 and pr.Revision_Level = 0

基本上我真的不知道如何比较我的执行计划的结果,以选择最佳设计。我还考虑了选项1的一个版本,其中不是将两次连接到Part表,而是将Part_ID选择为局部变量,并简单地根据该值查询Part_Revisions表。但是,我不能使用解释计划进行分析。

2 个答案:

答案 0 :(得分:1)

您的描述和选择语句看起来不同......我基于SQL语句的程序。

PROCEDURE the_proc
(
    part_no_in         IN  NUMBER
,   revision_level_in  IN  NUMBER
,   unit_id_in         IN  NUMBER
,   part_rev_count_out OUT NUMBER
,   part_rev_name_out  OUT VARCHAR2
,   unit_rev_name_out  OUT VARCHAR2
)
AS
BEGIN
    SELECT  COUNT(*)
    INTO    part_rev_count_out
    FROM    part  pa
    WHERE   pa.part_no = part_no_in
    AND     EXISTS
            (
                SELECT  1
                FROM    part_revisions  pr
                WHERE   pa.part_id = pr.part_id
            );

    SELECT  pr1.revision_name 
    INTO    part_rev_name_out
    FROM    part_revisions  pr1
    WHERE   pr1.revision_level = revision_level_in
    AND     EXISTS
            (
                SELECT  1
                FROM    part  pa1
                WHERE   pa1.part_id = pr1.part_id
                AND     pa.part_no = part_no_in
            );

    SELECT  ur.revision_name
    INTO    unit_rev_name_out
    FROM    unit_revision ur
    WHERE   ur.unit_id = unit_id_in;
END the_proc;

答案 1 :(得分:0)

看起来你正在获得标量值。而不是返回游标,只需使用干净的sql语句返回值。我已经从.net做了很多次,它运行正常。

Procedure get_part_info(p_partnum in part.part_number%type
    , ret_count          out integer 
    , ret_revision_level out part_revisions.revision_level%type
    , ret_revision_name  out part_revisions.revision_name%type) as
begin 
   select count(*) into ret_count from ....;
   select min(revision_level) into ret_revision_level from ...;
   select revision_name in ret_revision_name...;
   return;
end;