Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何加快对包含有效日期数据的大型数据仓库表的查询?_Sql_Oracle_Data Warehouse_Peoplesoft - Fatal编程技术网

Sql 如何加快对包含有效日期数据的大型数据仓库表的查询?

Sql 如何加快对包含有效日期数据的大型数据仓库表的查询?,sql,oracle,data-warehouse,peoplesoft,Sql,Oracle,Data Warehouse,Peoplesoft,所以我查询了一些非常大的表。它们之所以如此庞大,是因为PeopleSoft每次对某些数据进行更改时都会插入新记录,而不是更新现有记录。实际上,它的事务表也是一个数据仓库 这需要在查询中嵌套SELECT以获取最近/当前行。它们都是生效日期,并且在每个日期(铸造到一天)内,它们可以有一个有效的序列。因此,为了获得user_id=123的当前记录,我必须执行以下操作: select * from sometable st where st.user_id = 123 and st.effective_

所以我查询了一些非常大的表。它们之所以如此庞大,是因为PeopleSoft每次对某些数据进行更改时都会插入新记录,而不是更新现有记录。实际上,它的事务表也是一个数据仓库

这需要在查询中嵌套SELECT以获取最近/当前行。它们都是生效日期,并且在每个日期(铸造到一天)内,它们可以有一个有效的序列。因此,为了获得
user_id=123
的当前记录,我必须执行以下操作:

select * from sometable st
where st.user_id = 123
and st.effective_date = (select max(sti.effective_date) 
  from sometable sti where sti.user_id = st.user_id)
and st.effective_sequence = (select max(sti.effective_sequence) 
  from sometable sti where sti.user_id = st.user_id
  and sti.effective_date = st.effective_date)
这些表上的索引数量惊人,我找不到任何其他可以加快查询速度的方法

我的问题是,我经常想从这些表中获取关于个人的数据,可能需要50个用户ID,但当我将只有几条记录的表与一些PeopleSoft表连接起来时,事情就变得一团糟了

PeopleSoft表位于我通过数据库链接访问的远程数据库上。我的查询通常如下所示:

select st.* from local_table lt, sometable@remotedb st
where lt.user_id in ('123', '456', '789')
and lt.user_id = st.user_id
and st.effective_date = (select max(sti.effective_date) 
  from sometable@remotedb sti where sti.user_id = st.user_id)
and st.effective_sequence = (select max(sti.effective_sequence) 
  from sometable@remotedb sti where sti.user_id = st.user_id
  and sti.effective_date = st.effective_date)
当我不得不将几个PeopleSoft表与本地表连接在一起时,情况会变得更糟。表现令人无法接受

我可以做些什么来提高绩效?我尝试了查询提示,以确保我的本地表首先连接到PeopleSoft中的合作伙伴,因此在将其缩小到正确的用户id之前,它不会尝试将所有表连接在一起。我尝试了
前导的
提示,并尝试了尝试将处理推送到远程数据库的提示,但解释计划模糊不清,只说了几次行动“远程”,我不知道发生了什么

假设我没有能力改变PeopleSoft和我桌子的位置,提示是我最好的选择吗?如果我将一个本地表与四个远程表连接起来,而本地表与其中两个表连接起来,那么我将如何设置提示的格式,以使我的本地表(非常小——事实上,我可以通过内联视图使我的本地表只成为我感兴趣的用户ID)首先与每个远程表连接起来


编辑:应用程序需要实时数据,因此很遗憾,物化视图或其他缓存数据的方法是不够的。

您可以尝试使用此方法,而不是使用子查询。我不知道Oracle是否会在这方面表现得更好,因为我很少使用Oracle

SELECT
    ST1.col1,
    ST1.col2,
    ...
FROM
    Some_Table ST1
LEFT OUTER JOIN Some_Table ST2 ON
    ST2.user_id = ST1.user_id AND
    (
        ST2.effective_date > ST1.effective_date OR
        (
            ST2.effective_date = ST1.effective_date AND
            ST2.effective_sequence > ST1.effective_sequence
        )
    )
WHERE
    ST2.user_id IS NULL
另一个可能的解决办法是:

SELECT
    ST1.col1,
    ST1.col2,
    ...
FROM
    Some_Table ST1
WHERE
    NOT EXISTS
    (
        SELECT
        FROM
            Some_Table ST2
        WHERE
            ST2.user_id = ST1.user_id AND
            (
                ST2.effective_date > ST1.effective_date OR
                (
                    ST2.effective_date = ST1.effective_date AND
                    ST2.effective_sequence > ST1.effective_sequence
                )
            )
    )

是否可以选择创建一个数据库,用于非仓库类型的东西,可以每晚更新?如果是这样的话,您可以创建一个夜间进程,该进程将只移动最新的记录。这将消除每天查询的最大工作量,并显著减少数量或记录

此外,这取决于最新数据和可用数据之间是否有1天的间隔


我对Oracle不太熟悉,因此可能有一种方法可以通过对查询进行更改来获得改进…

您没有提到对数据新鲜度的要求,但一种方法是创建物化视图(由于无法在源系统中创建快照日志,您将被限制为刷新完成)只有事务表的当前版本行的数据。这些物化视图表将驻留在本地系统中,可以向它们添加额外的索引以提高查询性能。

性能问题将是对链接的访问。通过对本地表的部分查询,所有查询都在本地执行,因此无法访问远程索引,并且它将所有远程数据拉回到本地进行测试

如果可以在本地数据库中使用物化视图,定期(每夜)从peoplesoft数据库刷新历史数据,则仅访问远程peoplesoft数据库以获取今天的更改(将生效日期=今天添加到where子句中)并合并两个查询

另一种选择可能是使用INSERT INTO X SELECT FROM将远程数据拉入临时本地表或物化视图,然后使用第二个查询将其与本地数据连接起来。。。类似于josephj1989的建议


或者(尽管可能存在许可问题)尝试将本地数据库与远程peoplesoft数据库进行RAC群集。

像这样重构查询是否有帮助

SELECT *
  FROM (SELECT st.*, MAX(st.effective_date) OVER (PARTITION BY st.user_id) max_dt,
                     MAX(st.effective_sequence) OVER (PARTITION BY st.user_id, st.effective_date) max_seq
          FROM local_table lt JOIN sometable@remotedb st ON (lt.user_id = st.user_id)
         WHERE lt.user_id in ('123', '456', '789'))
 WHERE effective_date = max_dt
   AND effective_seq = max_seq;

我同意@Mark Baker的观点,通过DB链接连接的性能确实会很差,而且这种方法的效果可能会受到限制。

一个选项是首先使用公共表表达式具体化查询的远程部分,这样您就可以确保只从远程DB获取相关数据。另一个改进是将针对远程数据库的2个子查询合并为一个基于分析函数的子查询。这样的查询也可以用于当前查询。只有在玩了db之后,我才能提出其他建议

见下文

with remote_query as
(
    select /*+ materialize */  st.* from sometable@remotedb st
    where st.user_id in ('123', '456', '789')
    and st.rowid in( select first_value(rowid) over (order by effective_date desc, 
                         effective_sequence desc ) from sometable@remotedb st1 
                      where st.user_id=st1.user_id)
)

select lt.*,st.* 
FROM local_table st,remote_query rt
where st.user_id=rt.user_id

您能否将具有所需用户id的行ETL到您自己的表中,只创建所需的索引来支持您的查询并对其执行查询

PeopleSoft表是交付的还是定制的?您确定这是一个物理表,而不是PS端写得很差的视图吗?若您要针对的是已交付的记录(示例看起来很像PS_作业或引用它的视图),可能您可以指出这一点。PS_作业是一个有着大量索引的庞然大物,而且大多数站点添加的索引甚至更多

如果知道表上的索引,可以使用Oracle提示指定要使用的首选索引;这有时会有帮助

你有没有做过解释计划,看看你是否能确定问题出在哪里?也许有笛卡尔连接,全表扫描,e
create table remote (user_id number, eff_date date, eff_seq number, value varchar2(10));

create type typ_remote as object (user_id number, eff_date date, eff_seq number, value varchar2(10));
.
/

create type typ_tab_remote as table of typ_remote;
.
/

insert into remote values (1, date '2010-01-02', 1, 'a');
insert into remote values (1, date '2010-01-02', 2, 'b');
insert into remote values (1, date '2010-01-02', 3, 'c');
insert into remote values (1, date '2010-01-03', 1, 'd');
insert into remote values (1, date '2010-01-03', 2, 'e');
insert into remote values (1, date '2010-01-03', 3, 'f');

insert into remote values (2, date '2010-01-02', 1, 'a');
insert into remote values (2, date '2010-01-02', 2, 'b');
insert into remote values (2, date '2010-01-03', 1, 'd');

create function show_remote (i_user_id_1 in number, i_user_id_2 in number) return typ_tab_remote pipelined is
    CURSOR c_1 is
    SELECT user_id, eff_date, eff_seq, value
    FROM
        (select user_id, eff_date, eff_seq, value, 
                        rank() over (partition by user_id order by eff_date desc, eff_seq desc) rnk
        from remote
        where user_id in (i_user_id_1,i_user_id_2))
    WHERE rnk = 1;
begin
    for c_rec in c_1 loop
        pipe row (typ_remote(c_rec.user_id, c_rec.eff_date, c_rec.eff_seq, c_rec.value));
    end loop;
    return;
end;
/

select * from table(show_remote(1,null));

select * from table(show_remote(1,2));
UserKey  UserBusinessKey State    ValidFrom    ValidTo   Version  Status
7234     John_Smith_17   Indiana  2005-03-20  2010-06-23    1     expired
9116     John_Smith_17   Ohio     2010-06-24  3000-01-01    2     current
WHERE Status = 'current'
WHERE ValidTo = '3000-01-01'
WHERE ValidTo > CURRENT_DATE