需要有关优化SQL select语句的帮助

时间:2015-06-29 04:21:26

标签: sql oracle

我是Oracle数据库的新手。我在'select'语句中遇到了性能问题。问题如下:

原始声明(效果极慢):

SELECT *
FROM my_pos pos
WHERE my_source NOT IN
  (SELECT my_source_id FROM my_source WHERE can_delete = 0
  )
AND EXISTS
  (SELECT 1
  FROM my_agreement agr,
    my_account acc,
    my_account fund_acc,
    my_client cli,
  WHERE (agr.agr_client_acc_id  = pos.my_acc_id
  OR agr.agr_cp_acc_id          = pos.my_acc_id
  OR agr.agr_client_coll_acc_id = pos.my_acc_id
  OR agr.agr_pool_acc_id        = pos.my_acc_id
  OR agr.client_pool_acc_id     = pos.my_acc_id )
  AND agr.agr_client_acc_id     = acc.my_acc_id
  AND acc.fund_acc_id           = fund_acc.my_acc_id(+)
  AND cli.client_id             = (
    CASE
      WHEN fund_acc.my_acc_id IS NOT NULL
      THEN fund_acc.client_id
      ELSE acc.client_id
    END )
  );

解释原始声明的计划:

Plan hash value: 4147965473

--------------------------------------------------------------------------------------------
| Id  | Operation                  | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |               |  1748 |   290K|  2532   (4)| 00:00:31 |
|*  1 |  HASH JOIN SEMI            |               |  1748 |   290K|  2532   (4)| 00:00:31 |
|*  2 |   HASH JOIN RIGHT ANTI     |               |  1748 |   268K|  1364   (2)| 00:00:17 |
|*  3 |    TABLE ACCESS FULL       | MY_SOURCE     |    44 |   264 |     2   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL       | MY_POS        |  8738 |  1288K|  1361   (2)| 00:00:17 |
|   5 |   VIEW                     | VW_SQ_1       | 16285 |   206K|  1167   (6)| 00:00:15 |
|   6 |    UNION-ALL               |               |       |       |            |          |
|   7 |     NESTED LOOPS           |               |  3257 | 78168 |   211   (7)| 00:00:03 |
|*  8 |      HASH JOIN OUTER       |               |  3257 | 68397 |   209   (6)| 00:00:03 |
|*  9 |       HASH JOIN            |               |  3257 | 45598 |   107   (6)| 00:00:02 |
|  10 |        INDEX FAST FULL SCAN| IX_AGR_CLIENT |  3257 | 13028 |     4   (0)| 00:00:01 |
|  11 |        TABLE ACCESS FULL   | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  12 |       TABLE ACCESS FULL    | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 13 |      INDEX UNIQUE SCAN     | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  14 |     NESTED LOOPS           |               |  3257 | 91196 |   238   (6)| 00:00:03 |
|* 15 |      HASH JOIN OUTER       |               |  3257 | 81425 |   236   (5)| 00:00:03 |
|* 16 |       HASH JOIN            |               |  3257 | 58626 |   135   (6)| 00:00:02 |
|  17 |        TABLE ACCESS FULL   | MY_AGREEMENT  |  3257 | 26056 |    32   (4)| 00:00:01 |
|  18 |        TABLE ACCESS FULL   | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  19 |       TABLE ACCESS FULL    | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 20 |      INDEX UNIQUE SCAN     | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  21 |     NESTED LOOPS           |               |  3257 | 84682 |   239   (6)| 00:00:03 |
|* 22 |      HASH JOIN OUTER       |               |  3257 | 74911 |   236   (5)| 00:00:03 |
|* 23 |       HASH JOIN            |               |  3257 | 52112 |   135   (6)| 00:00:02 |
|  24 |        TABLE ACCESS FULL   | MY_AGREEMENT  |  3257 | 19542 |    32   (4)| 00:00:01 |
|  25 |        TABLE ACCESS FULL   | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  26 |       TABLE ACCESS FULL    | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 27 |      INDEX UNIQUE SCAN     | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  28 |     NESTED LOOPS           |               |  3257 | 84682 |   239   (6)| 00:00:03 |
|* 29 |      HASH JOIN OUTER       |               |  3257 | 74911 |   236   (5)| 00:00:03 |
|* 30 |       HASH JOIN            |               |  3257 | 52112 |   135   (6)| 00:00:02 |
|  31 |        TABLE ACCESS FULL   | MY_AGREEMENT  |  3257 | 19542 |    32   (4)| 00:00:01 |
|  32 |        TABLE ACCESS FULL   | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  33 |       TABLE ACCESS FULL    | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 34 |      INDEX UNIQUE SCAN     | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  35 |     NESTED LOOPS           |               |  3257 | 84682 |   240   (7)| 00:00:03 |
|* 36 |      HASH JOIN OUTER       |               |  3257 | 74911 |   237   (6)| 00:00:03 |
|* 37 |       HASH JOIN            |               |  3257 | 52112 |   136   (6)| 00:00:02 |
|  38 |        TABLE ACCESS FULL   | MY_AGREEMENT  |  3257 | 19542 |    33   (7)| 00:00:01 |
|  39 |        TABLE ACCESS FULL   | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  40 |       TABLE ACCESS FULL    | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 41 |      INDEX UNIQUE SCAN     | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   1 - access("VW_COL_1"="POS"."MY_ACC_ID")
   2 - access("MY_SOURCE"="MY_SOURCE_ID")
   3 - filter("CAN_DELETE"=0)
   8 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
   9 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  13 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL)
              THEN "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  15 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  16 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  20 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL)
              THEN "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  22 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  23 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  27 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL)
              THEN "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  29 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  30 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  34 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL)
              THEN "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  36 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  37 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  41 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL)
              THEN "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )

新声明(工作速度极快):

SELECT *
FROM my_pos pos1
WHERE my_source NOT IN
  (SELECT my_source_id FROM my_source WHERE can_delete = 0
  )
AND EXISTS
  (SELECT 1
  FROM my_agreement agr,
    my_account acc,
    my_account fund_acc,
    my_client cli,
    -- add my_pos here
    my_pos pos
  WHERE (agr.agr_client_acc_id  = pos.my_acc_id
  OR agr.agr_cp_acc_id          = pos.my_acc_id
  OR agr.agr_client_coll_acc_id = pos.my_acc_id
  OR agr.agr_pool_acc_id        = pos.my_acc_id
  OR agr.client_pool_acc_id     = pos.my_acc_id )
  AND agr.agr_client_acc_id     = acc.my_acc_id
  AND acc.fund_acc_id           = fund_acc.my_acc_id(+)
  AND cli.client_id             = (
    CASE
      WHEN fund_acc.my_acc_id IS NOT NULL
      THEN fund_acc.client_id
      ELSE acc.client_id
    END )
    -- connect pos1 and pos
  AND pos1.my_pos_id = pos.my_pos_id
  );

解释新声明的计划:

Plan hash value: 2962711282

----------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |               |  1748 |   290K|  9174   (2)| 00:01:51 |
|*  1 |  HASH JOIN SEMI                    |               |  1748 |   290K|  9174   (2)| 00:01:51 |
|*  2 |   HASH JOIN RIGHT ANTI             |               |  1748 |   268K|  1364   (2)| 00:00:17 |
|*  3 |    TABLE ACCESS FULL               | MY_SOURCE     |    44 |   264 |     2   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL               | MY_POS        |  8738 |  1288K|  1361   (2)| 00:00:17 |
|   5 |   VIEW                             | VW_SQ_1       | 32799 |   416K|  7809   (2)| 00:01:34 |
|   6 |    CONCATENATION                   |               |       |       |            |          |
|*  7 |     HASH JOIN                      |               |  1277 | 54911 |  1439   (2)| 00:00:18 |
|   8 |      NESTED LOOPS                  |               |    25 |   850 |    83   (3)| 00:00:01 |
|   9 |       NESTED LOOPS OUTER           |               |    25 |   775 |    83   (3)| 00:00:01 |
|  10 |        NESTED LOOPS                |               |    25 |   600 |    58   (4)| 00:00:01 |
|* 11 |         TABLE ACCESS FULL          | MY_AGREEMENT  |    25 |   350 |    33   (7)| 00:00:01 |
|  12 |         TABLE ACCESS BY INDEX ROWID| MY_ACCOUNT    |     1 |    10 |     1   (0)| 00:00:01 |
|* 13 |          INDEX UNIQUE SCAN         | PK_MY_ACCOUNT |     1 |       |     0   (0)| 00:00:01 |
|  14 |        TABLE ACCESS BY INDEX ROWID | MY_ACCOUNT    |     1 |     7 |     1   (0)| 00:00:01 |
|* 15 |         INDEX UNIQUE SCAN          | PK_MY_ACCOUNT |     1 |       |     0   (0)| 00:00:01 |
|* 16 |       INDEX UNIQUE SCAN            | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  17 |      TABLE ACCESS FULL             | MY_POS        |  8738 | 78642 |  1356   (2)| 00:00:17 |
|* 18 |     HASH JOIN                      |               |  4956 |   208K|  1583   (2)| 00:00:19 |
|  19 |      NESTED LOOPS                  |               |    97 |  3298 |   227   (1)| 00:00:03 |
|  20 |       NESTED LOOPS OUTER           |               |    97 |  3007 |   227   (1)| 00:00:03 |
|  21 |        NESTED LOOPS                |               |    97 |  2328 |   129   (1)| 00:00:02 |
|* 22 |         TABLE ACCESS FULL          | MY_AGREEMENT  |    97 |  1358 |    32   (4)| 00:00:01 |
|  23 |         TABLE ACCESS BY INDEX ROWID| MY_ACCOUNT    |     1 |    10 |     1   (0)| 00:00:01 |
|* 24 |          INDEX UNIQUE SCAN         | PK_MY_ACCOUNT |     1 |       |     0   (0)| 00:00:01 |
|  25 |        TABLE ACCESS BY INDEX ROWID | MY_ACCOUNT    |     1 |     7 |     1   (0)| 00:00:01 |
|* 26 |         INDEX UNIQUE SCAN          | PK_MY_ACCOUNT |     1 |       |     0   (0)| 00:00:01 |
|* 27 |       INDEX UNIQUE SCAN            | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  28 |      TABLE ACCESS FULL             | MY_POS        |  8738 | 78642 |  1356   (2)| 00:00:17 |
|* 29 |     HASH JOIN                      |               |  8736 |   366K|  1594   (2)| 00:00:20 |
|  30 |      NESTED LOOPS                  |               |   776 | 26384 |   237   (6)| 00:00:03 |
|* 31 |       HASH JOIN OUTER              |               |   776 | 24056 |   236   (5)| 00:00:03 |
|* 32 |        HASH JOIN                   |               |   776 | 18624 |   135   (6)| 00:00:02 |
|* 33 |         TABLE ACCESS FULL          | MY_AGREEMENT  |   776 | 10864 |    32   (4)| 00:00:01 |
|  34 |         TABLE ACCESS FULL          | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  35 |        TABLE ACCESS FULL           | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 36 |       INDEX UNIQUE SCAN            | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  37 |      TABLE ACCESS FULL             | MY_POS        |  8738 | 78642 |  1356   (2)| 00:00:17 |
|* 38 |     HASH JOIN                      |               |  8733 |   366K|  1596   (2)| 00:00:20 |
|  39 |      NESTED LOOPS                  |               |  3075 |   102K|   239   (6)| 00:00:03 |
|* 40 |       HASH JOIN OUTER              |               |  3075 | 95325 |   237   (6)| 00:00:03 |
|* 41 |        HASH JOIN                   |               |  3075 | 73800 |   136   (6)| 00:00:02 |
|* 42 |         TABLE ACCESS FULL          | MY_AGREEMENT  |  3075 | 43050 |    33   (7)| 00:00:01 |
|  43 |         TABLE ACCESS FULL          | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  44 |        TABLE ACCESS FULL           | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 45 |       INDEX UNIQUE SCAN            | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  46 |      TABLE ACCESS FULL             | MY_POS        |  8738 | 78642 |  1356   (2)| 00:00:17 |
|* 47 |     HASH JOIN                      |               |  9097 |   382K|  1596   (2)| 00:00:20 |
|  48 |      NESTED LOOPS                  |               |  3257 |   108K|   240   (7)| 00:00:03 |
|* 49 |       HASH JOIN OUTER              |               |  3257 |    98K|   237   (6)| 00:00:03 |
|* 50 |        HASH JOIN                   |               |  3257 | 78168 |   136   (6)| 00:00:02 |
|  51 |         TABLE ACCESS FULL          | MY_AGREEMENT  |  3257 | 45598 |    33   (7)| 00:00:01 |
|  52 |         TABLE ACCESS FULL          | MY_ACCOUNT    | 23210 |   226K|   101   (4)| 00:00:02 |
|  53 |        TABLE ACCESS FULL           | MY_ACCOUNT    | 23210 |   158K|   100   (3)| 00:00:02 |
|* 54 |       INDEX UNIQUE SCAN            | PK_CLIENT     |     1 |     3 |     0   (0)| 00:00:01 |
|  55 |      TABLE ACCESS FULL             | MY_POS        |  8738 | 78642 |  1356   (2)| 00:00:17 |
----------------------------------------------------------------------------------------------------

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

   1 - access("POS1"."MY_POS_ID"="ITEM_1")
   2 - access("MY_SOURCE"="MY_SOURCE_ID")
   3 - filter("CAN_DELETE"=0)
   7 - access("AGR"."CLIENT_POOL_ACC_ID"="POS"."MY_ACC_ID")
  11 - filter("AGR"."CLIENT_POOL_ACC_ID" IS NOT NULL)
  13 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  15 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  16 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL) THEN
              "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  18 - access("AGR"."AGR_POOL_ACC_ID"="POS"."MY_ACC_ID")
       filter(LNNVL("AGR"."CLIENT_POOL_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."CLIENT_POOL_ACC_ID" IS NOT NULL))
  22 - filter("AGR"."AGR_POOL_ACC_ID" IS NOT NULL)
  24 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  26 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  27 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL) THEN
              "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  29 - access("AGR"."AGR_CLIENT_COLL_ACC_ID"="POS"."MY_ACC_ID")
       filter((LNNVL("AGR"."AGR_POOL_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."AGR_POOL_ACC_ID" IS NOT NULL)) AND
              (LNNVL("AGR"."CLIENT_POOL_ACC_ID"="POS"."MY_ACC_ID") OR LNNVL("AGR"."CLIENT_POOL_ACC_ID" IS
              NOT NULL)))
  31 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  32 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  33 - filter("AGR"."AGR_CLIENT_COLL_ACC_ID" IS NOT NULL)
  36 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL) THEN
              "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  38 - access("AGR"."AGR_CP_ACC_ID"="POS"."MY_ACC_ID")
       filter((LNNVL("AGR"."AGR_CLIENT_COLL_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."AGR_CLIENT_COLL_ACC_ID" IS NOT NULL)) AND
              (LNNVL("AGR"."AGR_POOL_ACC_ID"="POS"."MY_ACC_ID") OR LNNVL("AGR"."AGR_POOL_ACC_ID" IS NOT
              NULL)) AND (LNNVL("AGR"."CLIENT_POOL_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."CLIENT_POOL_ACC_ID" IS NOT NULL)))
  40 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  41 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  42 - filter("AGR"."AGR_CP_ACC_ID" IS NOT NULL)
  45 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL) THEN
              "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )
  47 - access("AGR"."AGR_CLIENT_ACC_ID"="POS"."MY_ACC_ID")
       filter((LNNVL("AGR"."AGR_CP_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."AGR_CP_ACC_ID" IS NOT NULL)) AND
              (LNNVL("AGR"."AGR_CLIENT_COLL_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."AGR_CLIENT_COLL_ACC_ID" IS NOT NULL)) AND
              (LNNVL("AGR"."AGR_POOL_ACC_ID"="POS"."MY_ACC_ID") OR LNNVL("AGR"."AGR_POOL_ACC_ID" IS NOT
              NULL)) AND (LNNVL("AGR"."CLIENT_POOL_ACC_ID"="POS"."MY_ACC_ID") OR
              LNNVL("AGR"."CLIENT_POOL_ACC_ID" IS NOT NULL)))
  49 - access("ACC"."FUND_ACC_ID"="FUND_ACC"."MY_ACC_ID"(+))
  50 - access("AGR"."AGR_CLIENT_ACC_ID"="ACC"."MY_ACC_ID")
  54 - access("CLI"."CLIENT_ID"=CASE  WHEN ("FUND_ACC"."MY_ACC_ID" IS NOT NULL) THEN
              "FUND_ACC"."CLIENT_ID" ELSE "ACC"."CLIENT_ID" END )

我的新选择语句比旧语句快得多(快80倍!),但我不知道为什么。

我只是将目标表添加到子语句中(新的插入句子跟我的注释),并且多次运行两个语句。他们俩都给了我相同的结果。然而,原始平均成本为80秒,而新平均成本为1秒。有没有人可以告诉我为什么会这样?大多数细节都是受欢迎的。

最好的关注。

3 个答案:

答案 0 :(得分:1)

首先,我要查看您的陈述的execution plans

1)创建执行计划:

explain plan for (select * from table_name where ...);

2)显示执行计划:

select * from table(dbms_xplan.display);

在sql * plus中,您可能还想使用AUTO TRACE选项。

这使您可以了解Oracle如何执行语句,并且是语句级别上任何性能问题的起点。

答案 1 :(得分:1)

在Oracle SQL调整过程中的第一步做好了!不幸的是,您的问题的答案并非直截了当,而且还有很多工作要做。 您的第二个查询似乎运行得很快,但是我怀疑如果我们增加数据量和/或执行频率,它是否可以有效扩展。

您应该始终使用ANSI-92 SQL标准编写查询。这是comparison。 这不仅可以帮助您更好地理解联接,而且可以极大地帮助您进行调优。

我质疑可伸缩性的另一个原因是WHERE my_source NOT IN子句。在Oracle中,您必须注意不要使IN列表达到硬限制1000, 否则您可能会收到ORA-01795: maximum number of expressions in a list is 1000错误。从调整的角度来看,IN列表应该是固定值,并且长度非常有限。 如果需要更多值,请考虑将它们存储在带有索引的表中。 代替使用NOT IN,而使用EXISTS并使用键进行连接。这允许数据库利用索引,而不是将子查询的整个结果存储在内存中。 它可以在少量数据上快速运行,但是如果数据量/执行次数增加,您最终将使用更多的宝贵数据库内存。 在极端情况下,占用大量内存的大容量查询会大大降低生产数据库的速度。

要考虑的另一件事是CASE子句中的WHERE语句。 Oracle在这里不太可能使用索引,因为每行都有一个表达式。 在每一行中使用表达式可能是为什么在“解释计划”中看到TABLE ACCESS FULL和许多NESTED LOOPS的原因。甲骨文尽力展现嵌套循环和全表扫描 将数据收集到动态视图(VW_SQ_1)中,然后使用HASH JOIN将数据全部融合在一起。所有这些额外的工作都需要付出一定的代价,包括CPU,内存(字节),磁盘IO和时间。

进行全表扫描不一定是一件坏事,只要您打算处理每行并且扫描不会嵌套在其他循环中太深。 但是,如果卷很大,则数据库必须进行繁重的工作才能扫描所有行。在这种情况下,需要对SQL进行重大重写(或重新设计表/索引)。

SQL总是在较小的逻辑子查询中表现更好。大型,复杂的子查询可能真的很麻烦。尽可能删除OR语句,以使查询更易于理解。 包含UNION的CTE是实现此目的的好方法,因为您仅在寻找一行的存在。请记住,UNIONUNION ALLDISTINCT组合而成。 您可以进一步调整为仅使用UNION ALL,但是需要对数据有更多的了解。

请小心,不要在出现LEFT JOIN结果之前对NULL子句中的WHERE进行过滤,除非您知道数据中存在NULL。我在这里的假设是id不包含NULL

最后,让您的谓词“真实”,而不是“假”。换句话说,始终尝试通过使用TRUE=ANDEXISTS来使您的逻辑搜索INNER JOINS结果。 尽量减少使用<>ORNOT EXISTS。除非您有充分的理由并且知道自己在做什么,否则比LEFT JOIN(或其他任何奇特的加入方法)更喜欢RIGHT JOIN

WITH Categories AS
(
   SELECT
   fund_acc.my_acc_id,
   acc.client_id
   FROM my_pos pos
   INNER JOIN my_agreement agr ON agr.agr_client_acc_id = pos.my_acc_id
   INNER JOIN my_account acc ON acc.my_acc_id = agr.agr_client_acc_id
   INNER JOIN my_client cli ON cli.client_id = fund_acc.client_id
   LEFT JOIN my_account fund_acc ON fund_acc.my_acc_id = acc.fund_acc_id 
   WHERE pos.my_pos_id = pos1.my_pos_id

   UNION

   SELECT
   fund_acc.my_acc_id,
   acc.client_id
   FROM my_pos pos
   INNER JOIN my_agreement agr ON agr.agr_cp_acc_id = pos.my_acc_id
   INNER JOIN my_account acc ON acc.my_acc_id = agr.agr_client_acc_id
   INNER JOIN my_client cli ON cli.client_id = fund_acc.client_id
   LEFT JOIN my_account fund_acc ON fund_acc.my_acc_id = acc.fund_acc_id 
   WHERE pos.my_pos_id = pos1.my_pos_id

   UNION

   SELECT
   fund_acc.my_acc_id,
   acc.client_id
   FROM my_pos pos
   INNER JOIN my_agreement agr ON agr.agr_client_coll_acc_id = pos.my_acc_id
   INNER JOIN my_account acc ON acc.my_acc_id = agr.agr_client_acc_id
   INNER JOIN my_client cli ON cli.client_id = fund_acc.client_id
   LEFT JOIN my_account fund_acc ON fund_acc.my_acc_id = acc.fund_acc_id 
   WHERE pos.my_pos_id = pos1.my_pos_id

   UNION

   SELECT
   fund_acc.my_acc_id,
   acc.client_id
   FROM my_pos pos
   INNER JOIN my_agreement agr ON agr.agr_pool_acc_id = pos.my_acc_id
   INNER JOIN my_account acc ON acc.my_acc_id = agr.agr_client_acc_id
   INNER JOIN my_client cli ON cli.client_id = fund_acc.client_id
   LEFT JOIN my_account fund_acc ON fund_acc.my_acc_id = acc.fund_acc_id 
   WHERE pos.my_pos_id = pos1.my_pos_id

   UNION

   SELECT
   fund_acc.my_acc_id,
   acc.client_id
   FROM my_pos pos
   INNER JOIN my_agreement agr ON agr.client_pool_acc_id = pos.my_acc_id
   INNER JOIN my_account acc ON acc.my_acc_id = agr.agr_client_acc_id
   INNER JOIN my_client cli ON cli.client_id = fund_acc.client_id
   LEFT JOIN my_account fund_acc ON fund_acc.my_acc_id = acc.fund_acc_id 
   WHERE pos.my_pos_id = pos1.my_pos_id
)
SELECT
*
FROM my_pos pos1
WHERE NOT EXISTS (
                    SELECT 1
                    FROM my_source mys
                    WHERE mys.my_source_id = pos1.my_source
                    AND mys.can_delete = 0
                 )
AND (
        EXISTS (
                    SELECT
                    c.my_acc_id
                    FROM Categories c
                    INNER JOIN my_client cli ON cli.client_id = c.my_acc_id
                    WHERE c.my_acc_id IS NOT NULL
               )        
       OR EXISTS 
               (
                    SELECT
                    c.client_id
                    FROM Categories c
                    INNER JOIN my_client cli ON cli.client_id = c.client_id
                    WHERE c.my_acc_id IS NULL
               )
    );

免责声明:我可以继续调整此语句。但是在不了解数据,要求和表结构的情况下,我可能应该在这里停止。 该查询可能存在一些错误,但是我想演示的是如何构造SQL,以便您可以在将每个片段组合成一个整体之前对其进行测试。

答案 2 :(得分:0)

我相信一旦你在查询中添加'AND pos1.my_pos_id = pos.my_pos_id'句子,oracle可以将查询视为“内连接”, - 执行第三次选择语句,并使用索引(&amp;外键)决定返回哪些记录。在第一个查询中,select语句分别为源表(my_pos)中的每个记录执行

您的查询等于:

SELECT *
 FROM my_pos pos1
  left join
   my_sourc m on m.my_source_id=pos1.my_source
     inner join
     (SELECT my_pos_id
       FROM my_agreement agr,
      my_account acc,
         my_account fund_acc,
         my_client cli,
        -- add my_pos here
         my_pos pos
        WHERE (agr.agr_client_acc_id  = pos.my_acc_id
        OR agr.agr_cp_acc_id          = pos.my_acc_id
         OR agr.agr_client_coll_acc_id = pos.my_acc_id
        OR agr.agr_pool_acc_id        = pos.my_acc_id
      OR agr.client_pool_acc_id     = pos.my_acc_id )
        AND agr.agr_client_acc_id     = acc.my_acc_id
       AND acc.fund_acc_id           = fund_acc.my_acc_id(+)
        AND cli.client_id             = (
        CASE
            WHEN fund_acc.my_acc_id IS NOT NULL
             THEN fund_acc.client_id
          ELSE acc.client_id
       END )


           )
       -- connect pos1 and pos
           on  pos1.my_pos_id = pos.my_pos_id

           where pos1.my_source is null -- this row says, my source not in           my source table   there for I accept only nulls