Oracle - 函数与过程性能比较

11 浏览
0 Comments

Oracle - 函数与过程性能比较

我正在组合一个用于执行一些操作并返回日期范围的关联数组的包。我一直在使用函数,但我开始怀疑是否从性能上来说这是最好的选择,所以我编写了一个测试包来进行检查:

CREATE OR REPLACE PACKAGE pk_perf_test IS
  TYPE pt_rDateSpan IS RECORD
  (
    start_date DATE,
    end_date DATE
  );
  TYPE pt_aaDateTable IS TABLE OF pt_rDateSpan INDEX BY PLS_INTEGER;
  FUNCTION pf_getDateTable (p_nInputParam INTEGER) RETURN pt_aaDateTable;
  PROCEDURE pp_getDateTable (p_nInputParam INTEGER, op_aaDateTable OUT pt_aaDateTable);
  PROCEDURE pp_getDateTable_NoCopy (p_nInputParam INTEGER, op_aaDateTable OUT NOCOPY pt_aaDateTable);
END pk_perf_test;

每个函数/过程只是运行相同的查询,使用输入参数作为绑定变量将结果使用BULK COLLECT存储到集合中。像这样:

CREATE OR REPLACE PACKAGE BODY pk_perf_test IS
  FUNCTION pf_getDateTable 
  (p_nInputParam INTEGER)
  RETURN pt_aaDateTable
  IS
    l_aaToRet pt_aaDateTable;
  BEGIN
    SELECT mt.start_date, mt.end_date
    BULK COLLECT INTO l_aaToRet
    FROM my_table mt
    INNER JOIN my_other_table mot ON mt.pk_col = mot.fk_col
    WHERE mt.pk_col = p_nInputParam;
    RETURN l_aaToRet;
  END pf_getDateTable;
  PROCEDURE pp_getDateTable
  (p_nInputParam INTEGER, op_aaDateTable OUT pt_aaDateTable)
  IS
  BEGIN
    SELECT mt.start_date, mt.end_date
    BULK COLLECT INTO op_aaDateTable
    FROM my_table mt
    INNER JOIN my_other_table mot ON mt.pk_col = mot.fk_col
    WHERE mt.pk_col = p_nInputParam;
  END pp_getDateTable;
  PROCEDURE pp_getDateTable_NoCopy
  (p_nInputParam INTEGER, op_aaDateTable OUT NOCOPY pt_aaDateTable)
  IS
  BEGIN
    SELECT mt.start_date, mt.end_date
    BULK COLLECT INTO op_aaDateTable
    FROM my_table mt
    INNER JOIN my_other_table mot ON mt.pk_col = mot.fk_col
    WHERE mt.pk_col = p_nInputParam;
  END pp_getDateTable_NoCopy;
END pk_perf_test;

然后,我编写了一个简短的脚本来测试它们的性能:

DECLARE
  l_tsStartTS TIMESTAMP WITH LOCAL TIME ZONE;
  l_iFunctionTotal INTERVAL DAY TO SECOND := INTERVAL '0' SECOND;
  l_iProcedureTotal INTERVAL DAY TO SECOND := INTERVAL '0' SECOND;
  l_iNoCopyTotal INTERVAL DAY TO SECOND := INTERVAL '0' SECOND;
  l_aaDummy pk_perf_test.pt_aaDateTable;
  l_nDummy INTEGER := 123;
  l_nCaseCount INTEGER := 0;
  CURSOR c_ids IS
    SELECT mt.pk_col
    FROM my_table SAMPLE (10) mt;
BEGIN
  --Priming Query Run to make sure plan is cached
  SELECT mt.start_date, mt.end_date
  BULK COLLECT INTO l_aaDummy
  FROM my_table mt
  INNER JOIN my_other_table mot ON mt.pk_col = mot.fk_col
  WHERE mt.pk_col = l_nDummy;
  FOR r IN c_ids LOOP
    l_nCaseCount := l_nCaseCount + 1;
    l_aaDummy.DELETE;
    l_tsStartTS := SYSTIMESTAMP;
    l_aaDummy := pk_perf_test.pf_getDateTable(r.pk_col);
    l_iFunctionTotal := l_iFunctionTotal + (SYSTIMESTAMP-l_tsStartTS);
    l_aaDummy.DELETE;
    l_tsStartTS := SYSTIMESTAMP;
    pk_perf_test.pp_getDateTable(r.pk_col, l_aaDummy);
    l_iProcedureTotal := l_iProcedureTotal + (SYSTIMESTAMP-l_tsStartTS);
    l_aaDummy.DELETE;
    l_tsStartTS := SYSTIMESTAMP;
    pk_perf_test.pp_getDateTable_NoCopy(r.pk_col, l_aaDummy);
    l_iNoCopyTotal := l_iNoCopyTotal + (SYSTIMESTAMP-l_tsStartTS);
  END LOOP;
  dbms_output.put_line('Total Cases: '||l_nCaseCount);
  dbms_output.put_line('Function Total: '||l_iFunctionTotal);
  dbms_output.put_line('Procedure Total: '||l_iProcedureTotal);
  dbms_output.put_line('No Copy Total: '||l_iNoCopyTotal);
END;
/

我得到了以下结果:

Total Cases: 10787
Function Total: +00 00:00:22.857400
Procedure Total: +00 00:00:04.346413
No Copy Total: +00 00:00:01.942333

现在是我的问题。我明白为什么NOCOPY比普通过程快。但我不明白为什么普通过程比函数快得多?我认为这可能是一个偶然现象,所以我在多个环境中运行了多次,并得到了类似的结果(我发布的结果实际上是所有运行的平均值)。有人能解释为什么性能会如此不同吗?或者指出我测试中的缺陷?

0
0 Comments

问题的原因:

该问题的原因是关于Oracle中函数(Function)和过程(Procedure)的性能差异的疑问。询问者想知道函数和过程在性能方面是否有差异。

解决方法:

根据该问题的回答者,函数和过程在性能方面没有差异。它们之间唯一的区别是它们的工作方式。因此,根据具体情况选择使用函数或过程即可。

总结:

在Oracle中,函数和过程的性能没有差异。它们的区别在于它们的工作方式。因此,根据具体情况选择使用函数或过程即可,不会对性能产生影响。

参考链接:https://stackoverflow.com/questions/1942753

0