Arrays 在Oracle存储过程sql中使用数组参数

Arrays 在Oracle存储过程sql中使用数组参数,arrays,oracle,parameters,dynamic-sql,Arrays,Oracle,Parameters,Dynamic Sql,我们有一个PL/SQL过程,其中包含一个从典型事实表返回结果的基本查询。查询中WHERE子句所基于的维度值作为参数传入。我的问题是:使用这些参数构造查询的最佳方法是什么 下面是一些测试代码: SET SERVEROUTPUT ON 100000; -- build table DROP TABLE T_FACT; CREATE TABLE T_FACT (CUBE_ID NUMBER ,THE_DATE DATE ,DIM1 NUMBER ,DIM2 NUMBER ,DIM3 NUMBER

我们有一个PL/SQL过程,其中包含一个从典型事实表返回结果的基本查询。查询中WHERE子句所基于的维度值作为参数传入。我的问题是:使用这些参数构造查询的最佳方法是什么

下面是一些测试代码:

SET SERVEROUTPUT ON 100000;

-- build table
DROP TABLE T_FACT;
CREATE TABLE T_FACT 
(CUBE_ID NUMBER
,THE_DATE DATE
,DIM1 NUMBER
,DIM2 NUMBER
,DIM3 NUMBER
,DIM4 NUMBER
,DIM5 NUMBER
,VALUE NUMBER)
PARTITION BY LIST (CUBE_ID)
(  
  PARTITION P1 VALUES ('1')
 ,PARTITION P2 VALUES ('2')
 ,PARTITION P3 VALUES ('3')
 ,PARTITION P4 VALUES ('4')
 ,PARTITION P5 VALUES ('5')
 ,PARTITION PDEFAULT VALUES (DEFAULT)
);

CREATE UNIQUE INDEX T_FACT_UK1 ON T_FACT
(CUBE_ID, THE_DATE, DIM1, DIM2, DIM3, DIM4, DIM5)
LOCAL (  
  PARTITION P1
 ,PARTITION P2
 ,PARTITION P3
 ,PARTITION P4
 ,PARTITION P5
 ,PARTITION PDEFAULT
);

ALTER TABLE T_FACT ADD (
  CONSTRAINT T_FACT_UK1
  UNIQUE (CUBE_ID, THE_DATE, DIM1, DIM2, DIM3, DIM4, DIM5)
  USING INDEX LOCAL);

-- add test data
TRUNCATE TABLE T_FACT;
INSERT INTO T_FACT
SELECT MOD(ROWNUM-1,5)+1 AS CUBE_ID
      ,ADD_MONTHS( TO_DATE('20010101','YYYYMMDD') , MOD(ROWNUM,48) - 1 ) AS THE_DATE
      ,MOD(TRUNC((DECODE(ROWNUM-1,0,1,ROWNUM-1)) / (5*POWER(30,4))),30)+1 AS DIM1
      ,MOD(TRUNC((DECODE(ROWNUM-1,0,1,ROWNUM-1)) / (5*POWER(30,3))),30)+1 AS DIM2
      ,MOD(TRUNC((DECODE(ROWNUM-1,0,1,ROWNUM-1)) / (5*POWER(30,2))),30)+1 AS DIM3
      ,MOD(TRUNC((DECODE(ROWNUM-1,0,1,ROWNUM-1)) / (5*30)),30)+1 AS DIM4
      ,MOD(TRUNC((DECODE(ROWNUM-1,0,1,ROWNUM-1)) / 5),30)+1 AS DIM5
      ,TRUNC(dbms_random.value(1, 10000)) AS VALUE
FROM DUAL
CONNECT BY ROWNUM <= 1000000;

COMMIT;

CREATE OR REPLACE TYPE DIM_TYPE AS TABLE OF NUMBER;
/

-- slow procedure
CREATE OR REPLACE PROCEDURE P_SLOW
(
    CubeId_in                   IN  NUMBER,
    DateStart_in                IN  DATE,
    DateEnd_in                  IN  DATE,
    Dim1_in                     IN  DIM_TYPE,
    Dim2_in                     IN  DIM_TYPE,
    Dim3_in                     IN  DIM_TYPE,
    Dim4_in                     IN  DIM_TYPE,
    Dim5_in                     IN  DIM_TYPE,
    Data_out                    OUT DIM_TYPE
)

IS
    Count1     NUMBER := Dim1_in.COUNT;
    Count2     NUMBER := Dim2_in.COUNT;
    Count3     NUMBER := Dim3_in.COUNT;
    Count4     NUMBER := Dim4_in.COUNT;
    Count5     NUMBER := Dim5_in.COUNT;

BEGIN

    SELECT  VALUE
    BULK COLLECT INTO Data_out
    FROM    T_FACT
    WHERE   CUBE_ID = CubeId_in
    AND     (THE_DATE BETWEEN DateStart_in AND DateEnd_in)
    AND     (DIM1 IN (SELECT COLUMN_VALUE FROM TABLE( Dim1_in )) OR Count1 = 0)
    AND     (DIM2 IN (SELECT COLUMN_VALUE FROM TABLE( Dim2_in )) OR Count2 = 0)
    AND     (DIM3 IN (SELECT COLUMN_VALUE FROM TABLE( Dim3_in )) OR Count3 = 0)
    AND     (DIM4 IN (SELECT COLUMN_VALUE FROM TABLE( Dim4_in )) OR Count4 = 0)
    AND     (DIM5 IN (SELECT COLUMN_VALUE FROM TABLE( Dim5_in )) OR Count5 = 0);

END P_SLOW;
/

-- fast procedure
CREATE OR REPLACE PROCEDURE P_FAST
(
    CubeId_in                   IN  NUMBER,
    DateStart_in                IN  DATE,
    DateEnd_in                  IN  DATE,
    Dim1_in                     IN  DIM_TYPE,
    Dim2_in                     IN  DIM_TYPE,
    Dim3_in                     IN  DIM_TYPE,
    Dim4_in                     IN  DIM_TYPE,
    Dim5_in                     IN  DIM_TYPE,
    Data_out                    OUT DIM_TYPE
)

IS
    Count1     NUMBER := Dim1_in.COUNT;
    Count2     NUMBER := Dim2_in.COUNT;
    Count3     NUMBER := Dim3_in.COUNT;
    Count4     NUMBER := Dim4_in.COUNT;
    Count5     NUMBER := Dim5_in.COUNT;

BEGIN

    SELECT  VALUE
    BULK COLLECT INTO Data_out
    FROM    T_FACT
    WHERE   CUBE_ID = CubeId_in
    AND     (THE_DATE BETWEEN DateStart_in AND DateEnd_in)
    AND     (DIM1 IN (SELECT COLUMN_VALUE FROM TABLE( Dim1_in )))
    AND     (DIM2 IN (SELECT COLUMN_VALUE FROM TABLE( Dim2_in )))
    AND     (DIM3 IN (SELECT COLUMN_VALUE FROM TABLE( Dim3_in )))
    AND     (DIM4 IN (SELECT COLUMN_VALUE FROM TABLE( Dim4_in )))
    AND     (DIM5 IN (SELECT COLUMN_VALUE FROM TABLE( Dim5_in )));

END P_FAST;
/

DECLARE 
    CubeId_in                     NUMBER := 2;
    DateStart_in                  DATE := TO_DATE('20010101','YYYYMMDD');
    DateEnd_in                    DATE := TO_DATE('20030101','YYYYMMDD');
    Dim1_in                       DIM_TYPE := DIM_TYPE(1,2,3,6,15,21,25);
    Dim2_in                       DIM_TYPE := DIM_TYPE(1,3,4,6,7,8,9,10);
    Dim3_in                       DIM_TYPE := DIM_TYPE(2,3,4,5,6,7,8,13,14,15);
    Dim4_in                       DIM_TYPE := DIM_TYPE(1,4,21,22,23,24,29);
    Dim5_in                       DIM_TYPE := DIM_TYPE(2,15,21);
    Data_out                      DIM_TYPE;

    timestart NUMBER;

BEGIN

    timestart:=DBMS_UTILITY.GET_TIME();

    P_FAST(CubeId_in, DateStart_in, DateEnd_in, Dim1_in, Dim2_in, Dim3_in,
     Dim4_in, Dim5_in, Data_out);
    DBMS_OUTPUT.PUT_LINE('Number of data values:'||Data_out.COUNT);

    DBMS_OUTPUT.PUT_LINE('Fast proc:' || TO_CHAR(DBMS_UTILITY.GET_TIME()-timestart));

    timestart:=DBMS_UTILITY.GET_TIME();

    P_SLOW(CubeId_in, DateStart_in, DateEnd_in, Dim1_in, Dim2_in, Dim3_in,
     Dim4_in, Dim5_in, Data_out);
    DBMS_OUTPUT.PUT_LINE('Number of data values:'||Data_out.COUNT);

    DBMS_OUTPUT.PUT_LINE('Slow proc:' || TO_CHAR(DBMS_UTILITY.GET_TIME()-timestart));

END;
/

anonymous block completed
Elapsed: 00:00:00.567
Number of data values:642
Fast proc:22
Number of data values:642
Slow proc:32
当我知道Dim3_in、Dim4_in、Dim5_in为空时


如果您能提出任何其他建议,我们将不胜感激。

问题是您不应该这样做。事实表和不同维度/维度属性之间的关系提供不同的报告

1) 您不希望有一个主SELECT语句来管理事实表

2) 收集一天的数据很容易,一个月就可以了。一年或者整个历史呢

最好是每个需求有一个SQL语句。有许多SQL语句是可以的,即使它们看起来很相似。将结果写入适当的聚合表并从中开始工作


i、 e:可以用一个包含聚合数据的表,然后再根据它进行其他聚合。

到目前为止,我找到的最佳答案或至少是讨论是:

> EXPLAIN PLAN FOR
    SELECT  VALUE
    FROM    T_FACT
    WHERE   CUBE_ID = 3
    AND     (THE_DATE BETWEEN TO_DATE('20010101','YYYYMMDD') AND TO_DATE('20030101','YYYYMMDD'))
    AND     (DIM1 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )) OR :COUNT1 = 0)
    AND     (DIM2 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )) OR :COUNT2 = 0)
    AND     (DIM3 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )) OR :COUNT3 = 0)
    AND     (DIM4 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )) OR :COUNT4 = 0)
    AND     (DIM5 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1) )) OR :COUNT5 = 0)
plan FOR succeeded.
> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)
PLAN_TABLE_OUTPUT              
--------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1947951911    

---------------------------------------------------------------------------------------------------------------------    
| Id  | Operation                              | Name       | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    
---------------------------------------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT                       |            |     1 |   100 |   291   (0)| 00:00:04 |       |       |    
|*  1 |  FILTER                                |            |       |       |            |          |       |       |    
|   2 |   PARTITION LIST SINGLE                |            |  5934 |   579K|   291   (0)| 00:00:04 |   KEY |   KEY |    
|   3 |    TABLE ACCESS BY LOCAL INDEX ROWID   | T_FACT     |  5934 |   579K|   291   (0)| 00:00:04 |     3 |     3 |    
|*  4 |     INDEX RANGE SCAN                   | T_FACT_UK1 |  5934 |       |   290   (0)| 00:00:04 |     3 |     3 |    
|*  5 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|            |       |       |            |          |       |       |    
|*  6 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|            |       |       |            |          |       |       |    
|*  7 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|            |       |       |            |          |       |       |    
|*  8 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|            |       |       |            |          |       |       |    
|*  9 |   COLLECTION ITERATOR CONSTRUCTOR FETCH|            |       |       |            |          |       |       |    
---------------------------------------------------------------------------------------------------------------------    

Predicate Information (identified by operation id):   
---------------------------------------------------   

   1 - filter((TO_NUMBER(:COUNT1)=0 OR  EXISTS (SELECT 0 FROM TABLE() "KOKBF$" WHERE VALUE(KOKBF$)=:B1)) AND             
              (TO_NUMBER(:COUNT2)=0 OR  EXISTS (SELECT 0 FROM TABLE() "KOKBF$" WHERE VALUE(KOKBF$)=:B2)) AND             
              (TO_NUMBER(:COUNT3)=0 OR  EXISTS (SELECT 0 FROM TABLE() "KOKBF$" WHERE VALUE(KOKBF$)=:B3)) AND             
              (TO_NUMBER(:COUNT4)=0 OR  EXISTS (SELECT 0 FROM TABLE() "KOKBF$" WHERE VALUE(KOKBF$)=:B4)) AND             
              (TO_NUMBER(:COUNT5)=0 OR  EXISTS (SELECT 0 FROM TABLE() "KOKBF$" WHERE VALUE(KOKBF$)=:B5)))                
   4 - access("CUBE_ID"=3 AND "THE_DATE">=TO_DATE(' 2001-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND                  
              "THE_DATE"<=TO_DATE(' 2003-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))      
   5 - filter(VALUE(KOKBF$)=:B1)      
   6 - filter(VALUE(KOKBF$)=:B1)      
   7 - filter(VALUE(KOKBF$)=:B1)      
   8 - filter(VALUE(KOKBF$)=:B1)      
   9 - filter(VALUE(KOKBF$)=:B1)      

Note     
-----    
   - dynamic sampling used for this statement

 36 rows selected 

> EXPLAIN PLAN FOR
    SELECT  VALUE
    FROM    T_FACT
    WHERE   CUBE_ID = 3
    AND     (THE_DATE BETWEEN TO_DATE('20010101','YYYYMMDD') AND TO_DATE('20030101','YYYYMMDD'))
    AND     (DIM1 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )))
    AND     (DIM2 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )))
    AND     (DIM3 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )))
    AND     (DIM4 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1,2,3) )))
    AND     (DIM5 IN (SELECT COLUMN_VALUE FROM TABLE( DIM_TYPE(1) )))
plan FOR succeeded.
> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)
PLAN_TABLE_OUTPUT              
--------------------------------------------------------------------------------------------------------------------------

Plan hash value: 3872369897    

-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name       | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |            |     1 |   110 |   440   (1)| 00:00:06 |       |       |
|*  1 |  HASH JOIN SEMI                            |            |     1 |   110 |   440   (1)| 00:00:06 |       |       |
|*  2 |   HASH JOIN SEMI                           |            |     1 |   108 |   410   (1)| 00:00:05 |       |       |
|*  3 |    HASH JOIN SEMI                          |            |     1 |   106 |   381   (1)| 00:00:05 |       |       |
|*  4 |     HASH JOIN SEMI                         |            |     1 |   104 |   351   (1)| 00:00:05 |       |       |
|*  5 |      HASH JOIN RIGHT SEMI                  |            |    59 |  6018 |   321   (1)| 00:00:04 |       |       |
|   6 |       COLLECTION ITERATOR CONSTRUCTOR FETCH|            |       |       |            |          |       |       |
|   7 |       PARTITION LIST SINGLE                |            |  5934 |   579K|   291   (0)| 00:00:04 |   KEY |   KEY |
|   8 |        TABLE ACCESS BY LOCAL INDEX ROWID   | T_FACT     |  5934 |   579K|   291   (0)| 00:00:04 |     3 |     3 |
|*  9 |         INDEX RANGE SCAN                   | T_FACT_UK1 |  5934 |       |   290   (0)| 00:00:04 |     3 |     3 |
|  10 |      COLLECTION ITERATOR CONSTRUCTOR FETCH |            |       |       |            |          |       |       |
|  11 |     COLLECTION ITERATOR CONSTRUCTOR FETCH  |            |       |       |            |          |       |       |
|  12 |    COLLECTION ITERATOR CONSTRUCTOR FETCH   |            |       |       |            |          |       |       |
|  13 |   COLLECTION ITERATOR CONSTRUCTOR FETCH    |            |       |       |            |          |       |       |
-------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):   
---------------------------------------------------   

   1 - access("DIM1"=VALUE(KOKBF$))   
   2 - access("DIM2"=VALUE(KOKBF$))   
   3 - access("DIM3"=VALUE(KOKBF$))   
   4 - access("DIM4"=VALUE(KOKBF$))   
   5 - access("DIM5"=VALUE(KOKBF$))   
   9 - access("CUBE_ID"=3 AND "THE_DATE">=TO_DATE(' 2001-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND                  
              "THE_DATE"<=TO_DATE(' 2003-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))      

Note     
-----    
   - dynamic sampling used for this statement

 35 rows selected 
SELECT VALUE
FROM    T_FACT
WHERE   CUBE_ID = 3
AND     (THE_DATE BETWEEN TO_DATE('20010101','YYYYMMDD') AND TO_DATE('20030101','YYYYMMDD'))
AND     (DIM1 IN (SELECT COLUMN_VALUE FROM TABLE( Dim1_in )))
AND     (DIM2 IN (SELECT COLUMN_VALUE FROM TABLE( Dim2_in )))
AND     (1=1 OR DIM3 IN (SELECT COLUMN_VALUE FROM TABLE( Dim3_in )))
AND     (1=1 OR DIM4 IN (SELECT COLUMN_VALUE FROM TABLE( Dim4_in )))
AND     (1=1 OR DIM5 IN (SELECT COLUMN_VALUE FROM TABLE( Dim5_in )))

OPEN mycursor  
FOR mysql  
USING Dim1_in, Dim2_in, Dim3_in, Dim4_in, Dim5_in;