使用“按级别连接”时查询速度非常慢

jv2fixgn  于 2021-07-26  发布在  Java
关注(0)|答案(2)|浏览(347)

需要
我想在oracle sql中创建如下表:

COUNTRY  NAME  WMWHSE_ID   DATE
   US     CRD2     1      040620
   GR     WAZ      2      040620
   CN     KOL      3      040620
   FR     DEL      4      040620
                  ...      ...
   US     CRD2     1      030620
   GR     WAZ      2      030620
   CN     KOL      3      030620
   FR     DEL      4      030620
                  ...      ...

wmwhse\ U id中的每个仓库都将打印一个日期列,表示今天的日期,并且对于日期=昨天、前天、前天…等重复此操作,直到1周前。我一共有124个仓库,所以124*7=868行。

查询块
下面是我的问题。它使用级别连接<=来实现7个日期(理论上)

select 
SUBSTR(db_alias, 1, 2) AS COUNTRY, 
db_alias as NAME, 
To_Number(Regexp_Replace(Db_Logid, '[^0-9]', '')) As Wmwhse_Id, 
to_char(sysdate, 'yyyyMMdd')+1-level as ACTDATE 
from wmsadmin.pl_db, dual where db_alias not like '%BPV' and  db_alias not like 'PRDO%' and db_alias not like 'ENTERPRISE'
connect by level <=7
order by ACTDATE desc, WMWHSE_ID asc

(需要group by,因为没有它,表看起来像:)

COUNTRY  NAME  WMWHSE_ID   DATE
   US     CRD2     1      040620
   GR     WAZ      2      040620
   CN     KOL      3      040620
   FR     DEL      4      040620
                  ...      ...
   US     CRD2     1      030620
   US     CRD2     1      030620
   US     CRD2     1      030620
   US     CRD2     1      030620
                  ...      ...

===
问题
在connectby level中,查询时间似乎随着n的增加呈指数增长<=n。我做了一些测试,结果如下:

CONNECT BY LEVEL <= n      ROWS         SECONDS
         1                 124           2-6
         2                 248           10+?
         3                 372           110

任何n=4或更高的值似乎都会完全挂起sqldeveloper。当n=7时,我让计算机运行了30多分钟,查询仍在运行。
是什么导致了这种缓慢?有没有更好的方法来实现我的表?谢谢你的时间。

von4xj4u

von4xj4u1#

为什么查询这么慢?因为每次迭代都会将每一行与124个新行连接起来。第二层是124*124行,第四层是236421376行,第七层是450766669594624行。这就是为什么你会得到复制品。也加入双没有影响。
解决办法是纠正错误 connect by 零件,添加条件 wmwhse_id = prior wmwhse_id :

select country, name, wmwhse_id, trunc(sysdate) - level + 1 dt
  from pl_db 
  connect by level <= 7 and prior wmwhse_id = wmwhse_id and prior sys_guid() is not null 
  order by dt desc, wmwhse_id

递归cte在大多数数据库中都是标准的,它更容易实现:

with r(country, name, wmwhse_id, dt, lvl) as (
  select country, name, wmwhse_id, trunc(sysdate), 1 from pl_db union all
  select country, name, wmwhse_id, trunc(sysdate) - lvl, lvl + 1 from r where lvl < 7)
select country, name, wmwhse_id, dt from r;

但最简单的方法是用7个数字进行交叉连接,不管如何生成它们:

select country, name, wmwhse_id, trunc(sysdate) - trim(column_value) + 1 dt
  from pl_db cross join xmltable('1 to 7')

包含所有三个查询的dbfiddle。

bpsygsoo

bpsygsoo2#

除了速度慢之外,您的查询还返回了许多重复项。即使选择不同的值,也不会更快。
但是,像这样的事情可能会发生。我没有你的数据,所以我用cte制作了一个小样本集。

SQL> set timing on
SQL> with pl_db (country, db_alias, db_logid) as
  2    (select 'US', 'CRD2'      , 'AB1' from dual union all
  3     select 'GR', 'WAZ'       , 'CD2' from dual union all
  4     select 'CN', 'KOL'       , 'EF3' from dual union all
  5     select 'FR', 'DEL'       , 'GH4' from dual union all
  6     select 'HR', 'XBPV'      , 'IJ5' from dual union all
  7     select 'AT', 'PRDO'      , 'KL6' from dual union all
  8     select 'DE', 'ENTERPRISE', 'MN7' from dual
  9    )
 10  select
 11    substr(country, 1, 2) as country,
 12    db_alias              as name,
 13    to_number(regexp_replace(db_logid, '[^0-9]', '')) as wmwhse_id,
 14    to_char(sysdate + 1 - column_value, 'yyyymmdd') as actdate
 15  from pl_db cross join
 16    table(cast(multiset(select level from dual
 17                        connect by level <= 7
 18                       ) as sys.odcinumberlist))
 19  where db_alias not like '%BPV'
 20    and db_alias not like 'PRDO%'
 21    and db_alias not like 'ENTERPRISE'
 22  order by actdate desc, wmwhse_id asc;

COUNTRY  NAME        WMWHSE_ID ACTDATE
-------- ---------- ---------- --------
US       CRD2                1 20200604
GR       WAZ                 2 20200604
CN       KOL                 3 20200604
FR       DEL                 4 20200604
US       CRD2                1 20200603
GR       WAZ                 2 20200603
CN       KOL                 3 20200603
FR       DEL                 4 20200603
US       CRD2                1 20200602
GR       WAZ                 2 20200602
CN       KOL                 3 20200602
FR       DEL                 4 20200602
US       CRD2                1 20200601
GR       WAZ                 2 20200601
CN       KOL                 3 20200601
FR       DEL                 4 20200601
US       CRD2                1 20200531
GR       WAZ                 2 20200531
CN       KOL                 3 20200531
FR       DEL                 4 20200531
US       CRD2                1 20200530
GR       WAZ                 2 20200530
CN       KOL                 3 20200530
FR       DEL                 4 20200530
US       CRD2                1 20200529
GR       WAZ                 2 20200529
CN       KOL                 3 20200529
FR       DEL                 4 20200529

28 rows selected.

Elapsed: 00:00:00.09
SQL>

在我看来相当快;试试看,希望对你有帮助。

相关问题