加入 1 行表需要太多时间
Posted
技术标签:
【中文标题】加入 1 行表需要太多时间【英文标题】:Join to 1 row table takes too much time 【发布时间】:2017-07-20 07:26:04 【问题描述】:我正在尝试从一个表中读取所有产品代码(mal_no 列)和数量数据(adet 列)(这是“hso”表并由 mal_no 索引,下面的所有表都有 mal_no 索引)但即使它只有 1 行数据它一直在运行并且永无止境。
没有此连接的查询(通过仅添加下面注释掉的部分)是立即的。
您对此有什么建议吗?
谢谢,
select mt.mal_no,hso.adet siparis,
mot.birim_no,round((mbs.eldeki_stok_miktar*0.8),0) duzelts,
mot.oncelik,
SUM(round((mbs.eldeki_stok_miktar*0.8),0)) OVER(ORDER BY
mot.oncelik desc ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) kumule_stok
from mal_birim_ambar_detay@live mbs
,mal_tanim@live mt
,mss_temin_yeri_oncelik@live mot
,web_hso hso
where 1=1
and hso.mal_no=mbs.mal_no
and mbs.mal_no=mt.mal_no
and mbs.birim_no=mot.birim_no
and mt.mal_grup_no=mot.mal_grup_no
and mt.mal_altgrup_no=mot.mal_altgrup_no
--and mt.mal_no in ('1035541001')
and mbs.eldeki_stok_miktar>0
and mot.oncelik>0
and mbs.ambar_no='01'
order by mot.oncelik desc
【问题讨论】:
连接似乎没问题,您能否向我们提供这些表的 DDL/结构。 【参考方案1】:您正在将远程数据库中的三个表连接到本地数据库中的一个。像这样的分布式查询非常慢,因为数据必须通过两个数据库之间的网络发送。
本地数据库将向远程数据库发送子查询;但是加入和过滤是在本地进行的,因此有可能从远程数据库传输大量冗余数据。因此,您需要为优化器提供足够的信息,以便它可以制作巧妙的子查询。
例如,在内联视图中隔离远程表:
select rmt.mal_no,
hso.adet siparis,
rmt.birim_no,
rmt.duzelts,
rmt.oncelik,
rmt.kumule_stok
from web_hso hso
join
( select mt.mal_no,
mot.birim_no,
round((mbs.eldeki_stok_miktar*0.8),0) duzelts,
mot.oncelik,
SUM(round((mbs.eldeki_stok_miktar*0.8),0))
OVER(ORDER BY mot.oncelik desc ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) kumule_stok
from mal_birim_ambar_detay@live mbs
join mal_tanim@live mt
on mbs.mal_no=mt.mal_no
join mss_temin_yeri_oncelik@live mot
on mbs.birim_no=mot.birim_no
and mt.mal_grup_no=mot.mal_grup_no
and mt.mal_altgrup_no=mot.mal_altgrup_no
where mbs.eldeki_stok_miktar>0
and mot.oncelik>0
and mbs.ambar_no='01' ) rmt
on hso.mal_no=rmt.mal_no
order by rmt.oncelik desc
显然这只是一个猜测,因为我不了解您的数据模型或您的数据。您需要在这里应用您的领域知识来制作一个好的查询。单独的内联视图可能无法提供您需要的所有速度。例如,如果大部分工作涉及三个远程表上的连接,并且很可能确实如此,那么正如@BriteSponge 建议的那样,您可能会发现使用the driving_site
hint 可以显着提高性能。因此,使用上面的内联视图,代码将开始
select /*+DRIVING_SITE(rmt)*/
rmt.mal_no,
hso.adet siparis,
rmt.birim_no,
rmt.duzelts,
rmt.oncelik,
rmt.kumule_stok
from web_hso hso
join ( ... ) rmt
on hso.mal_no=rmt.mal_no
Oracle 文档有进一步的指导。 Find out more.
【讨论】:
我不太喜欢提示,但看起来使用 DRIVING_SITE 提示在这里也可能有所帮助。 @BriteSponge - DRIVING_SITE 提示通常被认为是更安全的提示之一。这是一个很好的建议,我已将其纳入我的回答中,【参考方案2】:从这么多信息中很难判断。
但我建议您按照以下步骤操作:
-
如果您有任何数据库管理员或有合适的工具,请检查执行计划。 (例如 TOAD 显示 Oracle 数据库的执行计划。)
如果您在嵌套循环内的执行计划中看到“完全扫描”,则表示数据库正在一遍又一遍地扫描表。
对于整体方法,您可以使用以下方法:
-
在 where 条件项中找到最先减少集合的项。
(Oracle) 使用索引提示和 use_nl 提示明确定义数据库,它应该如何进入表。
最后,原则上尽量避免大连接。划分并征服您的数据。尝试编写嵌套循环并在检索数据时尽可能多地使用索引。
【讨论】:
以上是关于加入 1 行表需要太多时间的主要内容,如果未能解决你的问题,请参考以下文章