【问题标题】:oracle insert into very sloworacle插入很慢
【发布时间】:2017-01-04 21:41:57
【问题描述】:

我有以下 Oracle 查询,执行速度很快(几秒钟内):

select contract_id_fk as ct,
       max(trip_id) as tid,
       max(consumed_mileage) as cum
from trip
where to_date > to_date('20-12-2016','DD-MM-YYYY')
and contract_id_fk is not null
and vehicle_id_fk is not null
and trip_stop_status is null
group by contract_id_fk

“trip”表有大量行(超过 2000 万) 现在,我想将此查询的结果插入表中,使用:

INSERT INTO lst
select contract_id_fk as ct, 
       max(trip_id) as tid, 
       max(consumed_mileage) as cum 
from trip
where to_date > to_date('20-12-2016','DD-MM-YYYY') 
and contract_id_fk is not null 
and vehicle_id_fk is not null 
and trip_stop_status is null 
group by contract_id_fk

这非常慢。太慢以至于事务超时(在我的情况下超过 30 秒)。知道为什么这么慢,以及如何对其进行优化吗?

【问题讨论】:

  • 您如何运行SELECT 查询(SQLPlus、一些工具,...)?请尝试select count(*) from (yourSelect) 看看会发生什么。
  • 尝试添加附加提示 - /*+ append */ 可能有很多很多原因(硬件、操作系统配置、表配置)。选择返回多少行?表上有多少个索引?
  • 如果原始表中有 20M 行,那么您可能有数百万条结果行要写入表 lst。输出本质上比输入慢,而且您必须检查约束、更新索引等。您描述的相对时间似乎并没有超出范围。
  • 在你的情况下,你可以在插入之前先做一个CTAS 吗?
  • 不同之处可能在于 I/O。读意味着只读。写入意味着读取原始数据并写入数百万个结果行。您还可以在插入数据时检查日志文件的自动增长并检查可用的系统资源。问题也可能与索引有关 - 禁用或删除目标表的索引并在插入后重新创建它们。

标签: sql oracle sql-insert


【解决方案1】:

很难说是什么原因,因为可能有多种原因,例如:

  • 内存不足,或重做日志大小
  • 次优表设置(PCTFREE 等)
  • 硬件性能问题

我推荐两件事:

  • 检查等待事件是什么
  • 尝试使用 APPEND 提示插入
INSERT /*+ APPEND */ INTO lst
select contract_id_fk as ct,
max(trip_id) as tid, max(consumed_mileage) as cum
from trip where to_date > to_date('20-12-2016','DD-MM-YYYY')
and contract_id_fk is not null and vehicle_id_fk is not null and
trip_stop_status is null group by contract_id_fk

【讨论】:

  • 谢谢,我试试APPEND关键字。关于如何检查等待事件的任何提示?
  • 看看 V$SESSION_EVENT。
【解决方案2】:

尝试用光标选择,然后插入到循环中。就这样;

DECLARE
       CURSOR SCURSOR IS
        select contract_id_fk as ct, 
           max(trip_id) as tid, 
           max(consumed_mileage) as cum 
        from trip
        where to_date > to_date('20-12-2016','DD-MM-YYYY') 
        and contract_id_fk is not null 
        and vehicle_id_fk is not null 
        and trip_stop_status is null 
        group by contract_id_fk ;
    BEGIN
       FOR RECS IN SCURSOR
       LOOP
            INSERT INTO lst 
            SELECT RECS.ct , RECS.tid , RECS.cum FROM DUAL;
            COMMIT;
       END LOOP;
    END;

【讨论】:

    【解决方案3】:

    检查缓冲区现金,我认为问题可能出在缓冲区现金上 或尝试收集表统计信息

    【讨论】:

    • 欢迎来到 StackOverflow! “现金”是指cache
    【解决方案4】:

    因为他们仍在为这个将近 4 年的问题做出答案...... IO(AWS上的RDS实例......)饱和缓慢的根本原因加上太多的分组/排序。更多的是数据库建模问题。 感谢所有试图提供帮助的人!

    【讨论】:

      猜你喜欢
      • 2017-01-07
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 2020-09-05
      • 2015-01-05
      • 2021-05-28
      • 1970-01-01
      相关资源
      最近更新 更多