Performance 在IN子句-Oracle中使用嵌套表的性能

Performance 在IN子句-Oracle中使用嵌套表的性能,performance,oracle,plsql,Performance,Oracle,Plsql,我试图在PL-SQL块的IN子句中使用嵌套表 首先,我定义了一个类型: CREATE OR REPLACE TYPE VARCHAR_ARRAY AS TABLE OF VARCHAR2(32767); 下面是使用“批量收集到”的PL-SQL块: DECLARE COL1 VARCHAR2(50) := '123456789'; N_TBL VARCHAR_ARRAY := VARCHAR_ARRAY(); C NUMBER; BEGIN -

我试图在PL-SQL块的
IN
子句中使用嵌套表

首先,我定义了一个类型:

CREATE OR REPLACE TYPE VARCHAR_ARRAY AS TABLE OF VARCHAR2(32767);
下面是使用“批量收集到”的PL-SQL块:

DECLARE
  COL1 VARCHAR2(50) := '123456789';
  N_TBL                VARCHAR_ARRAY := VARCHAR_ARRAY();
  C NUMBER;
BEGIN

    -- Print timestamp
    DBMS_OUTPUT.PUT_LINE('START: ' || TO_CHAR(SYSTIMESTAMP  ,'dd-mm-yyyy hh24:mi:ss.FF'));

    SELECT    COLUMN1
      BULK COLLECT INTO N_TBL
    FROM MY_TABLE
    WHERE     COLUMN1 = COL1;


    SELECT    COUNT(COLUMN1)
      INTO C
    FROM      MY_OTHER_TABLE
    WHERE     COLUMN1 IN (SELECT column_value FROM TABLE(N_TBL));

    -- Print timestamp
    DBMS_OUTPUT.PUT_LINE('ENDED: ' || TO_CHAR(SYSTIMESTAMP  ,'dd-mm-yyyy hh24:mi:ss.FF'));

END;
输出为:

START: 01-08-2014 12:36:14.997
ENDED: 01-08-2014 12:36:17.554
START: 01-08-2014 12:36:08.889
ENDED: 01-08-2014 12:36:08.903
所需时间超过2.5秒(精确为2.557秒)

现在,如果用子查询替换嵌套表,如下所示:

DECLARE
  COL1 VARCHAR2(50) := '123456789';
  N_TBL                VARCHAR_ARRAY := VARCHAR_ARRAY();
  C NUMBER;
BEGIN

    -- Print timestamp
    DBMS_OUTPUT.PUT_LINE('START: ' || TO_CHAR(SYSTIMESTAMP  ,'dd-mm-yyyy hh24:mi:ss.FF'));

    SELECT    COUNT(COLUMN1)
      INTO C
    FROM      MY_OTHER_TABLE
    WHERE     COLUMN1 IN (
                          -- Nested table replaced by a subquery
                          SELECT    COLUMN1
                          FROM MY_TABLE
                          WHERE     COLUMN1 = COL1
    );

    -- Print timestamp
    DBMS_OUTPUT.PUT_LINE('ENDED: ' || TO_CHAR(SYSTIMESTAMP  ,'dd-mm-yyyy hh24:mi:ss.FF'));

END;
输出为:

START: 01-08-2014 12:36:14.997
ENDED: 01-08-2014 12:36:17.554
START: 01-08-2014 12:36:08.889
ENDED: 01-08-2014 12:36:08.903
只需14毫秒

我可以做些什么来增强这个PL-SQL块?
是否需要任何数据库配置?

这两种查询计划是否不同

假设它们是,差异可能在于优化器对子查询将返回的行数有合理的估计,因此能够选择最有效的计划。当您的数据位于嵌套表中时(我不喜欢在这里的类型声明中使用单词
array
,因为这意味着您使用的是
varray
,而不是),Oracle没有关于集合中将包含多少元素的信息。默认情况下,它会猜测集合的元素数量与数据块的字节数量相同。因此,如果您有8k个块,Oracle将猜测您的集合有8192个元素

假设您的实际查询没有返回接近8192行的任何位置,并且它实际上返回更多或更少的行,您可以使用来让优化器做出更准确的猜测。例如,如果您的查询通常返回几十行,那么您可能需要

SELECT    COUNT(COLUMN1)
  INTO C
FROM      MY_OTHER_TABLE
WHERE     COLUMN1 IN (SELECT /*+ cardinality(t 50) */ column_value 
                        FROM TABLE(N_TBL) t);
您在
基数
提示中输入的文字不需要特别精确,只需要接近一般现实。如果行数完全未知,则提示会有所帮助


如果您使用的是Oracle 11g,那么还可以帮助优化器更好地估计集合中的元素数量,从而从中获益。

您可以将此缩短为
,其中N_TBL的COLUMN1成员
Thank@Wernfried使代码更具可读性。无论如何,结果是一样的:(