加入 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 行表需要太多时间的主要内容,如果未能解决你的问题,请参考以下文章

如何增强对数百万行表的 MySQL 查询?

odoo10 行表创建新数据时默认取值

将 1 行表展平为键值对表

mysql中获取未读文章的数据库设计(超过100M行表)

xml凭证模板的一般制作

在 MySQL 中高效查询 15,000,000 行表