Performance 在IN子句-Oracle中使用嵌套表的性能
我试图在PL-SQL块的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 -
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使代码更具可读性。无论如何,结果是一样的:(