我有两个表SessionOrder
的表。此列是整数数据类型,并具有以下索引:CREATE INDEX OSIDX_<internal name> ON <Entity>
。
我正在执行以下查询:
SELECT i_0.rn, i_1.rn
FROM (
SELECT "RawEvent"."SessionOrder" as rn
FROM "RawEvent" i_0
WHERE something = 12
)
INNER JOIN (
SELECT "RawEvent"."SessionOrder" as rn
FROM "RawEvent" i_1
WHERE something = 14
) ON i_0.rn > i_1.rn
此查询的问题是ON i_0.rn > i_1.rn
变得太慢而且超时。
我将其替换为ON i_0.rn = i_1.rn
并且它非常快,但显然不会产生预期的结果。
是否有人知道如何提高此查询的性能以避免超时?
此问题的其他目标是了解为什么ON i_0.rn > i_1.rn
会导致性能下降。
PS:无法增加超时时间
答案 0 :(得分:3)
如果您真的使用Oracle数据库,请先检查。 SQL的语法建议使用其他RDBMS或某些预处理器。
要获得您对此类查询的期望,您可以使用如下虚拟示例。
生成样本数据
create table myTab as
with mySeq as
(select rownum SessionOrder from dual connect by level <= 10000)
select 12 something, SessionOrder from mySeq union all
select 14 something, SessionOrder from mySeq
;
这产生两个子源,每个子源具有从1到10.000开始的10.000个序列。
测试查询
create table myRes as
select a.SessionOrder rn0, b.SessionOrder rn1
from myTab a join myTab b on a.SessionOrder > b.SessionOrder and
a.something = 12 and b.something = 14;
在不到30秒的时间内产生49.995.000行。
如果您希望在更短的时间内获得如此大的结果,那么您需要进行高级优化。在不知道您的数据和要求的情况下,不可能提供一般的建议。
答案 1 :(得分:1)
根据建议,我尝试用其他策略来解决问题,从而获得更高的性能。
尽管有这个简单的解决方案,但我不明白为什么原始查询太慢了。我认为Oracle引擎没有使用索引。
SELECT i_0."SessionOrder", i_1."SessionOrder"
FROM "RawEvent" i_0
INNER JOIN "RawEvent" i_1 ON i_0."SessionOrder" < i_1."SessionOrder"
WHERE i_0."something" = 12 AND i_1."something" = 14
答案 2 :(得分:0)
您的查询执行三项任务:
1)获取两个子集(12和14)的数据
2)加入数据和
3)将结果传递给客户
请注意,索引访问(您怀疑会导致问题)仅与步骤1相关。 因此,为了获得更好的印象,首先要实现三个步骤之间经过的时间分布。 这可以使用SQL * Plus完成(我使用与之前答案相同的生成数据)
数据访问
由于我的表没有索引,执行count(*)会执行FULL TABLE SCAN。因此,在最坏的情况下,使用两倍的时间来获取数据。
SQL> set timi on
SQL> set autotrace on
SQL> select count(*) from mytab;
COUNT(*)
----------
20000
Elapsed: 00:00:01.13
Execution Plan
----------------------------------------------------------
Plan hash value: 3284627250
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5472 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| MYTAB | 20000 | 5472 (1)| 00:00:01 |
--------------------------------------------------------------------
FTS已准备好大约一秒钟,所以要让两个组都成为aprox。两秒钟过去了。
<强> JOIN 强>
可以使用连接查询的CTAS模拟连接所用的时间。
SQL> create table myRes as
2 select a.SessionOrder rn0, b.SessionOrder rn1
3 from myTab a join myTab b on a.SessionOrder > b.SessionOrder and
4 a.something = 12 and b.something = 14;
Table created.
Elapsed: 00:00:23.65
Join返回近50M行(由于大于条件)并花费大约21秒(我为数据访问减去2秒)。
将数据传递给客户
我们使用选项set autotrace traceonly
来抑制客户端屏幕上的查询输出,但数据已传输,因此我们可以
衡量时间。 (如果在屏幕上渲染结果,时间会更高)
SQL> SET ARRAYSIZE 5000
SQL> set autotrace traceonly
SQL> select a.SessionOrder rn0, b.SessionOrder rn1
2 from myTab a join myTab b on a.SessionOrder > b.SessionOrder and
3 a.something = 12 and b.something = 14;
49995000 rows selected.
Elapsed: 00:03:03.89
Execution Plan
----------------------------------------------------------
Plan hash value: 2857240533
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 49M| 667M| 11077 (2)| 00:00:01 |
| 1 | MERGE JOIN | | 49M| 667M| 11077 (2)| 00:00:01 |
| 2 | SORT JOIN | | 10000 | 70000 | 5473 (1)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| MYTAB | 10000 | 70000 | 5472 (1)| 00:00:01 |
|* 4 | SORT JOIN | | 10000 | 70000 | 5473 (1)| 00:00:01 |
|* 5 | TABLE ACCESS FULL| MYTAB | 10000 | 70000 | 5472 (1)| 00:00:01 |
-----------------------------------------------------------------------------
这是花费大约2:40分钟的时间
<强>摘要强>
因此,在总共3分钟的场景中,仅花费大约2秒钟来进行数据访问(或大约1%)。 即使您将数据访问权限削减到十分之一 - 您几乎看不到任何差异。 问题在于连接,甚至更多的是将数据传输到客户端。
索引可以帮助
当然这取决于......
在一个非常特殊的情况下,你有一个非常大的表,只有很少的数据something in (12,14)
您可以从 AND SessionOrder上定义的索引中获利。这允许使用仅索引访问数据,完全绕过表访问。