Sql 使用“连接方式”的重复行已运行很长时间

Sql 使用“连接方式”的重复行已运行很长时间,sql,oracle,Sql,Oracle,我想根据父表中的开始日期和结束日期插入若干行。我尝试了以下查询,但它运行了一个小时 INSERT INTO CHILD_TABLE with num as ( select level as rnk from dual connect by level<=300 ), Select Data, start_date, end_date,rnk From Paratent_table Join num O

我想根据父表中的开始日期和结束日期插入若干行。我尝试了以下查询,但它运行了一个小时

INSERT INTO CHILD_TABLE
  with num as (
    select level as rnk 
     from dual 
  connect by level<=300
  ), 
  Select Data, start_date,
         end_date,rnk
    From Paratent_table
    Join num 
      ON (num.rnk <= end_date-start_date)
父表有超过一百万行。

通过基数提示、直接路径插入、并行性和删除公共表表达式,问题的一般版本可以从6分钟改进到22秒。可能还有其他一些因素可以解释为什么你的版本在60分钟内运行,而我的版本在6分钟内运行。如果在进行这些更改后仍然存在问题,请使用SQL监视找出问题出在哪个操作和等待事件上

示例模式

原始版本-在我的旧桌面上运行6-10分钟

新版本-在22秒内运行

变更说明

基数提示通知优化器内联视图返回300行,而原始估计值为1行。改进的基数估计将计划从嵌套循环更改为合并联接

直接路径插入可避免大多数重做生成。尽管使用简单的示例表,语句的INSERT部分仍然很昂贵。如果有许多索引或外键需要验证,那么您的实际示例可能会在INSERT中花费大量时间。请注意,如果不重做,表更改不会自动备份

并行性利用了多种资源,可以真正改变游戏规则。并行性确实给系统带来了更大的压力,并且可能对其他进程非常不公平。而且它需要企业版、健全的配置等

通用表表达式CTE用于重复查询块。CTE有时会导致性能问题,但在这种情况下不会。这更多的是风格问题;内联视图比CTE更容易调试,但这里很难解释这一点


最后,如果上述任何一项都不起作用,则需要增加分析的粒度。大多数调优方法只关注哪些SQL语句慢,然后猜测该SQL语句中的哪个操作慢。无需猜测,实时SQL监控将准确地告诉您每个操作需要多长时间以及等待什么。找到SQL_ID并运行如下语句:从dual中选择dbms_sqltune.report_SQL_monitorsql_ID=>13gdzd4w5fx4y',type=>text

您是否自行运行了select?您希望插入多少行?删除CTE并从父表中选择end_date-start_date>300的行不是更简单吗?或者我在您的逻辑中遗漏了什么?其实我是,;您将对每个父行进行300次评估,并且每次都可能将每个父行插入子表。我想你经常吵架,但我不知道这是否是你想要的。首先,我要运行带有计数的select来查看实际检索的内容。with是邪恶的,如果select查询本身运行了很长时间,只需使用简单的INSERT或select INTO。我预计结果将是5000万张唱片。我想在开始日和结束日之间插入一条每天的记录,因此我必须重复父表中的记录,这是REASON for using WITH子句。
--drop table child_table;
--drop table parent_table;

create table parent_table(data varchar2(100), start_date date, end_date date);
create table child_table (data varchar2(100), start_date date, end_date date, rank number);

--Insert 1 million rows, gather statistics.
begin
    for i in 1 .. 10 loop
        insert into parent_table
        select level, sysdate,sysdate+50
        from dual
          connect by level <= 100000;
    end loop;
end;
/
begin
    dbms_stats.gather_table_stats(user, 'parent_table');
end;
/
insert into child_table
with num as
(
    select level as rnk 
    from dual 
    connect by level<=300
)
select data, start_date, end_date, rnk
from parent_table
join num 
    on num.rnk <= end_date-start_date;

commit;
truncate table child_table;
insert /*+ append parallel */ into child_table
select data, start_date, end_date, rnk
from parent_table
join
(
    select /*+ cardinality(300) */ level as rnk 
    from dual 
    connect by level<=300
) num
    on num.rnk <= end_date-start_date;