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

问题描述 投票:2回答:3

我是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 )

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

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

最良好的问候。

sql oracle
3个回答
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
投票

在您的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。嵌套循环和全表扫描显示为Oracle尽力将数据收集到动态视图(VW_SQ_1)中,然后使用HASH JOINs将其全部混合在一起。所有这些额外工作都需要付出代价,包括CPU,内存(字节),磁盘IO和时间。

执行全表扫描不一定是坏事,假设您的目的是处理每一行,并且扫描不会嵌套在其他循环中。但是如果卷是巨大的,那么数据库必须做很多繁重的工作才能扫描所有行。在这种情况下,需要重写SQL(或重新设计表/索引)。

对于较小的逻辑子查询,SQL总是表现得更好。大而复杂的子查询可能是一个非常麻烦的调整。尽可能删除OR语句,因此查询更容易理解。包含UNION的CTE是实现这一目标的好方法,因为您只需要查找一行的存在。请记住,UNIONUNION ALLDISTINCT相结合。你可以进一步调整它以仅使用UNION ALL,但需要更多的数据知识。

除非你知道数据中存在NULLs,否则在LEFT JOIN的结果出现之前,不要试图在WHERE子句中过滤NULLs。我的假设是ids不包含NULLs。

最后,保持你的谓词“真实”,而不是“虚假”。或者换句话说,总是试图通过在可能的情况下使用TRUE=ANDEXISTS来进行逻辑搜索INNER JOINS结果。继续使用<>OR以及NOT 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,以便在将每个片段组合成一个整体之前对其进行测试。


0
投票

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

您的查询等于:

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 
© www.soinside.com 2019 - 2024. All rights reserved.