【问题标题】:create table statement is slow创建表语句很慢
【发布时间】:2016-11-25 03:53:33
【问题描述】:

我正在尝试使用现有表中的数据子集创建一个新表。

这是一些示例数据。此表有 7000 条记录:

create table numbersegment (startnum varchar(35),endnum varchar(35),id_prefix number(10));
insert into numbersegment values('8175290000','8175299999','14108');
insert into numbersegment values('8175300000','8175309999','14108');
insert into numbersegment values('8175310000','8175319999','14108');
insert into numbersegment values('8175320000','8175329999','14108');
insert into numbersegment values('8175330000','8175339999','14108');

User_info 表有 3500 万条记录:

create table user_info(num varchar(35),subid number(18),custid number(18)); 


insert into user_info values('8175290031',100001234567891111,100001234567891111);
insert into user_info values('8175290032',100001234567891112,100001234567891112);
insert into user_info values('8175290033',100001234567891113,100001234567891113);
insert into user_info values('8175290034',100001234567891114,100001234567891114);
insert into user_info values('8175290035',100001234567891115,100001234567891115);

当我执行下面的 SQL 时,创建客户表大约需要 20 分钟

 create table customer as 
 select 
   mk.num,
   nm.id_prefix||substr(mk.subid,6) new_sub_id,
   nm.id_prefix||substr(mk.custid,6) new_cust_id
 from user_info mk,
   numbersegment nm 
 where mk.num >=nm.startnum 
 and mk.num    <=nm.endnum;

请建议创建此表的最快方法。

已经尝试过一些方法,比如并行执行和 Substr 来匹配第一个字符。

【问题讨论】:

  • 还提供执行计划,以便您可以专注于可以调优的地方。
  • 您正在对一个大表执行任意范围搜索;二十分钟不算快,但也不荒谬。这是一次性的练习吗?如果是这样,那就忍受吧:你已经浪费在调优上的时间比调优节省的时间还多。
  • 要明确:是语句的 SELECT 部分较慢,而不是 CREATE TABLE。如果您创建了一个空表,然后发出 INSERT INTO ... AS SELECT 语句,您的问题将标题为“插入语句很慢”

标签: sql oracle


【解决方案1】:

在我看来,parallel 没有logging option 会更快。

create table customer parallel 2 nologging as 
select /*+parallel(source 4) */ *  mk.num,
 nm.id_prefix||substr(mk.subid,6) new_sub_id,
 nm.id_prefix||substr(mk.custid,6) new_cust_id
 from user_info mk,numbersegment nm where mk.num >=nm.startnum and mk.num    <=nm.endnum;

更多详情:Miscellaneous Parallel Execution Tuning Tips

【讨论】:

  • 这个我已经尝试了 16 个并行进程,之后只需要 20 分钟。寻找一些合乎逻辑的方法来提高性能。
【解决方案2】:

选择很慢,因为 user_info 表的基数与带有子句的 numbersegment 表一起进入笛卡尔积。

         where mk.num >=nm.startnum 
         and mk.num    <=nm.endnum;

您将在两个表上进行 FULL TABLE SCAN。

一个可能的性能增强包括在 user_info.num 列上创建一个索引,如果你还没有这样做的话。

  create index USER_INFO_I1 on user_info (num);

如果你不能这样做,你可以将 user_info 表复制到另一个表中并创建索引 user_info 克隆表已经填充(否则索引重新计算将在每次插入时发生表,会破坏你的表现)。

另一个性能增强可能是将字段 user_info.numnumbersegment.startnumnumbersegment.endnum 转换为 NUMBER 数据类型(当然,如果它们是数字,就像从您的示例中看到的那样)。

还有字段

    numbersegment.id_prefix, user_info.subid, user_info.cust_id 

应该在 VARCHAR2 中进行转换,就像从您的查询中看到的那样

   nm.id_prefix||substr(mk.subid,6) new_sub_id,
   nm.id_prefix||substr(mk.custid,6) new_cust_id

但这不是性能增强

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多