Oracle Sql Query 需要一天的时间才能使用 dblink 返回结果

Posted

技术标签:

【中文标题】Oracle Sql Query 需要一天的时间才能使用 dblink 返回结果【英文标题】:Oracle Sql Query taking a day long to return results using dblink 【发布时间】:2011-01-06 10:50:37 【问题描述】:

伙计们,我有以下 oracle sql 查询,它为我提供了日期之间的月度报告。基本上对于 11 月,我想要日期 01nov 到 11 月 30 日之间的值总和。 正在查询的表位于另一个数据库中并使用 dblink 进行访问。 DT 列是 NUMBER 类型(例如 20101201)。

SELECT /*+ PARALLEL (A 8) */ /*+ DRIVING_STATE(A) */
 TO_CHAR(TRUNC(TRUNC(SYSDATE,'MM')- 1,'MM'),'MONYYYY') "MONTH", 
   TYPE AS "TYPE", COLUMN, COUNT (DISTINCT A) AS "A_COUNT",
    COUNT (COLUMN) AS NO_OF_COLS, SUM (DURATION) AS "SUM_DURATION",
     SUM (COST) AS "COST"  FROM **A@LN_PROD A**  
      WHERE DT >=  TO_NUMBER(TO_CHAR(add_months(SYSDATE,-1),'YYYYMM"01"'))
      AND  DT < TO_NUMBER(TO_CHAR(SYSDATE,'YYYYMM"01"'))
       GROUP BY TYPE, COLUMN

查询的执行需要一天的时间,但尚未完成。请建议我,如果他们可以在 dblink 上向我的 DBA 建议任何优化,或者可以对查询进行的任何调整,或者重写相同的内容。

表格更新

该表按日期列和近 10 亿条记录进行分区。

下面我给出了TOADEXPLAIN PLAN

**Plan**
SELECT STATEMENT REMOTE  ALL_ROWSCost: 1,208,299  Bytes: 34,760  Cardinality: 790                                               
    12 PX COORDINATOR                                           
        11 PX SEND QC (RANDOM) SYS.:TQ10002 Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                                        
            10 SORT GROUP BY  Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                                      
                9 PX RECEIVE  Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                                  
                    8 PX SEND HASH SYS.:TQ10001 Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                            
                        7 SORT GROUP BY  Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                       
                            6 PX RECEIVE  Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                      
                                5 PX SEND HASH SYS.:TQ10000 Cost: 1,208,299  Bytes: 34,760  Cardinality: 790                
                                    4 SORT GROUP BY  Cost: 1,208,299  Bytes: 34,760  Cardinality: 790           
                                        3 FILTER        
                                            2 PX BLOCK ITERATOR  Cost: 1,203,067  Bytes: 15,066,833,144  Cardinality: 342,428,026  Partition #: 11  Partitions accessed #1 - #5 
                                                1 TABLE ACCESS FULL TABLE CDRR.FRD_CDF_DATA_INTL_IN_P Cost: 1,203,067  Bytes: 15,066,833,144  Cardinality: 342,428,026  Partition #: 11  

我今天要做的事情如下,任何额外的提示都会有所帮助。

    我将收集该表的表格统计信息,这可能会提供最佳的 执行计划。 检查是否为分区创建了本地索引。 使用 BETWEEN 代替 >= 和 <.>

【问题讨论】:

只是好奇,直接在远程数据库上运行需要多长时间?如果查询本身只是花费很长时间,则 DB 链接可能是一条红鲱鱼。 十亿行!难怪需要很长时间! 【参考方案1】:

像往常一样,对于这类问题,解释计划会很有用。它将帮助我们弄清楚数据库中实际发生了什么。

理想情况下,您希望确保查询在远程数据库上运行并发送回结果集,而不是通过链接发送数据并在本地运行查询。这可确保通过链路发送的数据更少。 DRIVING_SITE 提示可以帮助解决这个问题,尽管 Oracle 通常对此非常聪明,因此它可能根本没有帮助。

Oracle 似乎在运行远程查询方面做得更好,但仍然可能存在问题。

此外,简化一些日期转换可能会有所帮助。

例如,替换这个:

TO_CHAR(TRUNC(TRUNC(SYSDATE,'MM')- 1,'MM'),'MONYYYY')

用这个:

TO_CHAR(add_months(TRUNC(SYSDATE,'MM'), -1),'MONYYYY')

它可能更高效一些,但也更容易阅读。

同样替换这个:

WHERE DT >=TO_NUMBER(TO_CHAR(TRUNC(TRUNC(SYSDATE,'MM')-1,'MM'),'YYYYMMDD')) 
  AND  DT < TO_NUMBER(TO_CHAR(TRUNC(TRUNC(SYSDATE,'MM'),'MM'),'YYYYMMDD')) 

WHERE DT >=TO_NUMBER(TO_CHAR(add_months(TRUNC(SYSDATE,'MM'), -1),'YYYYMMDD')) 
  AND  DT < TO_NUMBER(TO_CHAR(TRUNC(SYSDATE,'MM'),'YYYYMMDD')) 

甚至

WHERE DT >=TO_NUMBER(TO_CHAR(add_months(SYSDATE,-1),'YYYYMM"01"')) 
  AND  DT < TO_NUMBER(TO_CHAR(SYSDATE,'YYYYMM"01"')) 

【讨论】:

我已经在这里发布了解释计划供您参考。请注意 int。 @Suresh:我从来没有那么擅长阅读并行查询或分区的执行计划,所以 prob 帮不上什么忙。不过看起来确实是一张非常大的桌子!我发现表/分区压缩可以帮助处理大型表,尽管这仅适用于 10g 中的静态数据的批量加载(在 11 中更好),但我认为您可以根据需要压缩历史分区。【参考方案2】:

可能是因为几个问题: 1.网络速度,因为数据库可能驻留在不同的硬件上。 但是你可以参考这个链接 http://www.experts-exchange.com/Database/Oracle/Q_21799513.html。 有类似的问题。

【讨论】:

刚刚突出显示了其中一个参数 你不能在另一个数据库中运行查询来创建丢失的表。如果它工作正常,那么你可能需要调整 SQL 查询【参考方案3】:

在不知道表结构、约束、索引、数据量、结果集大小、网络速度、并发级别、执行计划等的情况下无法回答。

我会调查的一些事情:

如果表是分区的,查询命中的分区是否存在统计信息?一个常见的问题是在插入数据之前在空分区上收集统计信息。然后当您查询它时(在刷新统计信息之前)Oracle 会选择索引扫描,而实际上它应该在该分区上使用 FTS。

也与统计有关:确保

WHERE DT >=TO_NUMBER(TO_CHAR(TRUNC(TRUNC(SYSDATE,'MM')-1,'MM'),'YYYYMMDD')) 
  AND DT < TO_NUMBER(TO_CHAR(TRUNC(TRUNC(SYSDATE,'MM'),'MM'),'YYYYMMDD')) 

生成与以下相同的执行计划:

WHERE DT >= 20101201
  AND DT <  20110101

更新 您使用的是哪个版本的 Oracle?我要问的原因是在 Oracle 10g 及更高版本上,在这种情况下应该选择另一个 group by 实现(散列而不是排序)。看起来您基本上是在对从日期过滤器(14 GB)返回的 3.42 亿行进行排序。你有内存来备份吗?否则,您将进行多遍排序,溢出到磁盘。这很可能是正在发生的事情。

根据计划,将返回大约 790 行。这是在正确的球场吗? 如果是这样,您可以排除网络问题:)

另外,我并不完全熟悉该计划的格式。表子分区了吗?否则我没有得到分区 #11 的引用。

【讨论】:

以上是关于Oracle Sql Query 需要一天的时间才能使用 dblink 返回结果的主要内容,如果未能解决你的问题,请参考以下文章

sql Oracle SQL:返回当前月份第一天的字符串(如果其他月份为ar,则替换SYSDATE的任何日期字段/值

oracle上个月某一天的数据

使用 Power Query 过滤每月第一天和最后一天的日期

以 30 分钟的时间间隔计算一天的用户数 oracle

用SQL获取某个某年某个月份的最后一天的日期

sql 获取所有最后一天的时间段