oraclesql如何在不相关子查询中进行优化
我有以下查询执行得很差:oraclesql如何在不相关子查询中进行优化,sql,oracle,query-optimization,Sql,Oracle,Query Optimization,我有以下查询执行得很差: select distinct u.uuid u.user_name, u.key from request req join int_user u on u.uuid = req.user_uuid join int_right r on r.uuid = req.right_uuid where r.uuid in ( select r2.uuid
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
where r.uuid in (
select r2.uuid from int_right r2
where
(
lower(r2.right_name) like '%keyword%'
or lower(r2.right_key) like '%keyword%'
)
)
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
子查询是不相关的,它通常只返回几行,有时只返回一行。
现在我不明白为什么如果我接受子查询并单独执行它,然后接受结果列表并使用IN运算符将其静态添加到外部查询,那么它将执行得非常好,从3-6秒执行时间下降到0.05秒
r.uuid in ('value1', 'value2', 'value3')
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
如何让oracle先执行子查询,然后将结果集应用于外部查询
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
几点注意:
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
请求表非常庞大,大约有7百万行
Int_右表-约10K行
Int_用户表-大约10万行
从执行计划来看,oracle似乎对所有表进行了全面扫描。成本和基数是非常大的要求表。
同样有趣的是,即使我的子查询将针对某个搜索条件返回一行,查询仍然很慢,但是如果我将IN运算符替换为equals=则查询变得非常快,成本也很低。在这种情况下,oracle似乎只会在int_right表中执行完全扫描,而对于其他表,它会执行唯一或范围扫描
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
我还尝试了此查询的其他变体,如直接将条件添加到外部查询、使用exists或关联子查询,但无论如何都很慢。为什么需要子查询
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
相同条件可通过两种不同方式应用:
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
联合
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
在哪里
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
两者都会导致更快的查询,尽管我不能100%确定哪一个1会更快。据我所知,连接中的连接将更快…通常不能通过查看文本来调整SQL语句,除非代码中存在根本缺陷,例如缺少连接条件等。对于Oracle,最有效的方法之一是:
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
1使用以下附加提示执行有问题的语句
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
select /*+ gather_plan_statistics */ ... <rest of query>
这样,您将:
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
a查看所使用的真实执行计划
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
b获取计划中每个步骤的估计/实际行源计数。如果估计值与实际值之间的差异很大,那么这通常是您关注的重点,因为优化器很可能没有足够或准确的信息来处理这一问题
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
比如说
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')
SQL> select /*+ gather_plan_statistics */ count(dname)
2 from scott.emp e, scott.dept d
3 where e.sal <= 1500
4 and d.deptno = e.deptno;
COUNT(DNAME)
------------
7
1 row selected.
SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------
SQL_ID c1cb4s8b141h8, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(dname) from scott.emp e,
scott.dept d where e.sal <= 1500 and d.deptno = e.deptno
Plan hash value: 3037575695
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 9 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 9 |
| 2 | MERGE JOIN | | 1 | 3 | 7 |00:00:00.01 | 9 |
| 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 4 | 4 |00:00:00.01 | 2 |
| 4 | INDEX FULL SCAN | DEPT_PK | 1 | 4 | 4 |00:00:00.01 | 1 |
|* 5 | SORT JOIN | | 4 | 3 | 7 |00:00:00.01 | 7 |
|* 6 | TABLE ACCESS FULL | EMP | 1 | 3 | 7 |00:00:00.01 | 7 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("D"."DEPTNO"="E"."DEPTNO")
filter("D"."DEPTNO"="E"."DEPTNO")
6 - filter("E"."SAL"<=1500)
在第6行,您可以看到优化器估计了3行,但实际上得到了7行。较大的差异表明需要调查的区域。很抱歉输入错误。更正,谢谢。为什么需要子查询?我认为,子查询中的where子句可以作为外部查询中的where子句。是的,但在大多数情况下,如果在外部查询中使用where子句,我会获得相同的性能。如果搜索条件为长20-30个字符,则子查询的性能更好。您需要提供短搜索条件和长搜索条件的执行计划,以及有无子查询的执行计划,以便我们了解速度缓慢是否有原因。感谢您的答复,但已尝试过此操作,但不会提高性能。当搜索条件较小时,我可以获得相同的性能,但是当搜索条件较大(如20-30个字符)时,子查询的性能会更好,无法解释为什么..@DimaSendrea连接条件上有索引吗?如果有帮助的话,也可以在存在的地方尝试。[.
select
distinct
u.uuid
u.user_name,
u.key
from request req
join int_user u on u.uuid = req.user_uuid
join int_right r on r.uuid = req.right_uuid
Where (lower(r.right_name) like '%keyword%' or lower(r.right_key) like '%keyword%')