【问题标题】:Pivoting on table with huge number of records在具有大量记录的表上进行透视
【发布时间】:2020-01-07 08:59:18
【问题描述】:

我有以下表格

Create Table A
(rpt_id number,
Acct_id number,
type vatchar2(10));


Create Table 2
(rpt_id number,
Acct_id number,
tp varchar2(10),
information varchar2(100));


Insert into A1 (RPT_ID,ACCT_ID,TYPE) values (1,11,'type1');
Insert into A1 (RPT_ID,ACCT_ID,TYPE) values (2,22,'type2');


Insert into A2 (RPT_ID,ACCT_ID,TP,INFORMATION) values (1,11,'billnum','2341');
Insert into A2 (RPT_ID,ACCT_ID,TP,INFORMATION) values (1,11,'billname','abcd');

我需要获取以下信息

RPT_ID ACCT_ID billnum billname
1   11      2341        abcd

虽然这张表会有很大的数据,但A1中大约有200000条记录,A2中记录了相关的记录,每个RPT_ID至少有4到5行

直接从这两个连接创建枢轴会产生性能问题吗? 到目前为止,我使用了以下方法

Insert into t3
as select a2.*
     from a1
     join a2 on a1.rpt_id = a2.rpt_id and a1.ACCT_ID = a2.ACCT_ID
    where a1.type = 'type1';

然后在 t3 上旋转以制作下面的结构并插入到 t4 中以进一步使用它

RPT_ID ACCT_ID billnum billname
------ ------- ------- --------
1      11      2341    abcd

这是对 A2 表的全扫描,我们有什么办法可以避免全扫描。如果数据量很大,pivot 会出现性能问题。

【问题讨论】:

  • @jarlh 感谢您格式化问题。请帮我如何格式化,以便我下次可以用格式化的方式写。
  • 在您选择的编辑工具中正确设置文本格式。选择/复制。/将您的代码粘贴到您的 Q 中。现在使用在 S.O. 中选择的代码。编辑屏幕,单击编辑屏幕顶部编辑菜单中的{} 工具。祝你好运。

标签: sql oracle oracle11g pivot


【解决方案1】:

这是对 A2 表的全扫描,有什么可以解决的吗 这避免了全扫描

您是否在相关表上创建了任何索引?如果没有,那么全表扫描是唯一的选择!

请记住:全表扫描可能是获取行的最快方法。要查看是否是这种情况,您需要获取 execution plan 以进行查询。

也就是说,当前将连接加载到第三个表中,然后将结果旋转到第四个表的过程很复杂。并且可能比仅仅运行查询慢很多。

如果您想预先计算枢轴,最好使用materialized view。这将存储您的查询结果。并且 - 如果您可以将其设为 fast refresh on commit - 数据库将在您运行 DML 后对其进行更新。

例如:

Create Table A1 (
  rpt_id number,
  Acct_id number,
  type varchar2(10)
);  

Create Table A2 (rpt_id number,
  Acct_id number,
  tp varchar2(10),
  information varchar2(100)
);

Insert into A1 (RPT_ID,ACCT_ID,TYPE) values (1,11,'type1');
Insert into A1 (RPT_ID,ACCT_ID,TYPE) values (2,22,'type2');

Insert into A2 (RPT_ID,ACCT_ID,TP,INFORMATION) values (1,11,'billnum','2341');
Insert into A2 (RPT_ID,ACCT_ID,TP,INFORMATION) values (1,11,'billname','abcd');

commit;

create materialized view log on a1 
  with rowid, sequence ( rpt_id,acct_id,type )
  including new values;
create materialized view log on a2
  with rowid, sequence ( rpt_id,acct_id,tp,information )
  including new values;

create materialized view mv 
refresh fast on commit
as
with rws as (
  select a1.type, a2.*
  from   a1
  join   a2 on a1.rpt_id = a2.rpt_id 
  and    a1.ACCT_ID = a2.ACCT_ID
)
  select type, rpt_id, acct_id, 
         max ( case when tp = 'billnum' then information end ) billnum, 
         max ( case when tp = 'billname' then information end ) billname,
         count(*)
  from   rws
  group  by type, rpt_id, acct_id;

Insert into A2 (RPT_ID,ACCT_ID,TP,INFORMATION) values (2,22,'billname','abcd');

commit;

select * from mv;

TYPE     RPT_ID    ACCT_ID    BILLNUM    BILLNAME    COUNT(*)   
type1            1         11 2341       abcd                  2 
type2            2         22 <null>     abcd                  1 

如有必要,您可以在物化视图本身上创建索引,进一步提高性能。

NB - Oracle 数据库确实有一个pivot 子句,但这不适用于fast refresh on commit。你需要老式的版本。

【讨论】:

  • 感谢@Chris 一如既往的详细解释。 RPT_ID,ACCT_ID 上有索引,我可以看到这已在执行计划中使用。我不太确定是否要在类型上创建索引,因为基数太低,并且类型为“类型”的每条记录几乎是每条 2 到 3 条。在这种情况下是否值得创建索引?从来没有想过为pivot创作MV。我会试试这个以获得一些性能改进。
  • 我不确定您在说什么 - 每种类型有 2-3 行,还是整个表中只有 2-3 种类型?
  • 我只寻找一个特定的类型值,即 Type1。此外,基数相对于 Type 值太低。从 a1 中选择计数(); 668559 select count() from a1 where type='type1' ; 36855
  • 也许吧?你需要尝试一下!如果您仍然卡住/不确定,请使用execution plan 发布问题以获取声明
  • 看起来我的表 a1 和 a2 太大了,有一半将近 200000 行,在这个表上创建 MV 日志不会造成空间问题吗?因为我每天都在这个表中截断并插入这么多行。
猜你喜欢
  • 2019-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多