我是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秒。有没有人可以告诉我为什么会这样?大多数细节都是受欢迎的。
最好的关注。
答案 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是实现此目的的好方法,因为您仅在寻找一行的存在。请记住,UNION
是UNION ALL
与DISTINCT
组合而成。
您可以进一步调整为仅使用UNION ALL
,但是需要对数据有更多的了解。
请小心,不要在出现LEFT JOIN结果之前对NULL
子句中的WHERE
进行过滤,除非您知道数据中存在NULL
。我在这里的假设是id
不包含NULL
。
最后,让您的谓词“真实”,而不是“假”。换句话说,始终尝试通过使用TRUE
,=
,AND
和EXISTS
来使您的逻辑搜索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,以便您可以在将每个片段组合成一个整体之前对其进行测试。
答案 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