2012-02-27 28 views
3

我们的应用程序管理一个表,其中包含每个用户的一组行,这是计算密集型查询的结果 。将此结果存储在表 中似乎是加速进一步计算的好方法。在具有索引结构的大型表格上改进DELETE和INSERT时间

该表的结构基本上与以下:

CREATE TABLE per_user_result_set 
      (user_login   VARCHAR2(N) 
      , result_set_item_id VARCHAR2(M) 
      , CONSTRAINT result_set_pk PRIMARY KEY(user_login, result_set_item_id) 
      ) 
      ; 

我们的应用程序将具有这个结果集计算的 每天30次,用1个单品和之间组成的一个结果集的典型的用户500,000个项目。 典型的客户将向生产数据库申报约500名用户。 所以,这张表通常由500万行组成。

,我们用它来更新此表中的典型查询:

BEGIN 
    DELETE FROM per_user_result_set WHERE user_login = :x; 
    INSERT INTO per_user_result_set(...) SELECT :x, ... FROM ...; 
END; 
/

已经遇到性能问题(DELETE部分将花费更多的时间) 我们决定全局临时表后(上提交删除行)持有行的 “增量”从表和行压制插入到它:

BEGIN 
    INSERT INTO _tmp 
    SELECT ... FROM ... 
    MINUS SELECT result_set_item_id 
      FROM per_user_result_set 
      WHERE user_login = :x; 

    DELETE FROM per_user_result_set 
      WHERE user_login = :x 
      AND result_set_item_id NOT IN (SELECT result_set_item_id 
              FROM _tmp 
             ); 
    INSERT INTO per_user_result_set 
    SELECT :x, result_set_item_id 
     FROM _tmp; 

    COMMIT; 
END; 
/

这提高了性能一点,但是这仍然不尽如人意。所以 我们正设法加速这一进程,这里是 我们遇到的问题:

  • 我们会喜欢使用表分区(由USER_LOGIN分区)。 但分区并不总是可用的(在我们的测试数据库中,我们打到了 ORA-00439)。我们的客户无法承担支付额外功能的Oracle企业版 。
  • 我们可以使per_user_result_set表全局临时使其 是孤立的,我们可以TRUNCATE它例如...但我们的应用程序 有时丢失是由于网络问题连接到Oracle,并会 自动重新连接。那时我们失去了我们的计算内容 。
  • 我们可以将该表拆分成一定数量的存储桶,制作一个视图 联合会所有这些存储桶,并触发INSTEAD OF UPDATE和DELETE 该视图,并根据ORA_HASH(user_login) % num_buckets重新分配行。 但是我们担心这可能会让SELECT操作变得更慢。 这会导致表的数量不变,在DELETE或INSERT操作中影响较小的索引 。总之,“ 穷人分区表”。
  • 我们试过ALTER TABLE per_user_result_set NOLOGGING。这不是 改善很多东西。
  • 我们试过CREATE TABLE ... ORGANIZATION INDEX COMPRESS 1。这加快了 东西的比例为1:5。
  • 我们试图为每个user_login设置一个表。这正是我们通过使用与不同的user_logins和精心挑选的散列函数相同数量的分区进行分区而得到的结果 。性能因子是 1:10。但我真的想避免这个解决方案:必须保持一个 大量的索引,表,视图,在每个用户的基础上。这将是 一个有趣的性能增益为用户,但不是我们这个系统的维护者 。
  • 由于用户同时工作,我们无法创建新的 表并将其与旧的交换。

你能提出什么建议补充这些方法?

注意。我们的客户将Oracle数据库从9i升级到11g,并将XE版本升级到 企业版。这是多种版本,我们需要与 兼容。

谢谢。

+1

我首先想到的是使表的IOT,但你已经做到了,这导致了5倍加速,是正确的? 我能想到的唯一的其他事情就是避免删除。不管怎样,每次运行新查询时都要使用一个序列使旧结果集老化 - 即表变为user_login,result_set_id和result_set_item_id。您可能需要跟踪users表中的最新result_set_id或其他内容。 您是否100%肯定插入/删除是问题,而慢速部分找不到result_set_item_id? – 2012-02-27 13:57:01

+0

@Stephen ODonnell:我相信大部分时间都在'DELETE'部分。 – Benoit 2012-02-27 14:09:36

+0

到目前为止,您已经完成了哪些工作来收集详细的跟踪数据?我们可以猜测所有我们想要的解决方案,但是您需要数据才能真正找出问题并加以解决。乔纳森刘易斯的书“基于成本的Oracle基础知识”将是一个很好的起点。 – 2012-02-27 14:33:47

回答

1

我们试着每个user_login有一个表。这正是我们通过使用等于 数量的不同user_logins和精心挑选的散列函数的多个分区进行分区可以具有的。 性能系数为1:10。但我真的想避免这种解决方案:必须在每个用户的基础上维护大量的索引,表格和视图,数量为 。这对用户而言会是一个有趣的性能增益,但对于我们系统的维护者来说却不是这样。

然后你可以让存储过程在每个用户的基础上生成这些表吗?或者,更好的是,根据所支持的Oracle的许可证,这个存储过程是否是最合适的?

If Partitioning option 
    then create or truncate user-specific list partition 
Else 
    drop user-specific result table 
    Create user-specific result table 
     as Select from template result table 
    create indexes 
    create constraints 
    perform grants 
end if 
Perform insert 
1

如果所有用户都在11g企业版,我会建议你使用Oracle's built-in result-set caching而不是试图推出自己的。但情况并非如此,所以让我们继续前进。

另一个有吸引力的选择可能是使用PL/SQL集合而不是表格。在记忆中,这些检索速度更快,并且需要更少的维护。它们也支持所有你需要的版本。然而,它们是会话变量,所以如果你有很多用户使用大的结果集,会给你的PGA分配带来压力。当网络连接断开时,他们的数据也会丢失。所以这可能不是你想要的解决方案。

你的问题的核心是这样一句话:

DELETE FROM per_user_result_set WHERE user_login = :x; 

它本身不是一个问题,但你必须在数据分布的极端变化。直截了当地说,删除单行将有一个非常不同的性能配置文件从删除五十万行。而且因为你的用户不断刷新他们的数据,所以你无法处理这个问题,除了给你的用户自己的表。

你说你不想让每个用户表,因为

“[它]将是用户的一个有趣的性能增益,但不 对我们维护的系统,”

存在系统为我们的用户的利益。只要帮助我们为他们提供更好的服务,便利对我们来说是非常好的。但他们需要一个良好的工作经验胜过我们:他们付账单。

但我质疑每个用户的单个表是否真的增加了工作量。我认为每个用户都有他们自己的帐户,因此架构。

我建议你坚持索引组织表。您只需要主键中的列,并且维护一个单独的索引是不必要的开销(用于插入和删除)。每个用户拥有一个表的最大优点是可以在刷新过程中使用TRUNCATE TABLE,这比删除快很多。

所以,你的更新过程将是这样的:

BEGIN 
    TRUNCATE TABLE per_user_result_set REUSE STORAGE; 
    INSERT INTO per_user_result_set(...) 
      SELECT ... FROM ...; 
    DBMS_STATS.GATHER_TABLE_STATS(user 
      , 'PER_USER_RESULT_SET' 
      , estimate_percent=>10); 
    COMMIT; 
END; 
/

请注意,您并不需要包括用户栏了,所以尤尔表将只拥有result_set_item_id单塔(的另一个迹象物联网的适用性

收集表统计信息并不是强制性的,但是可取的。结果集的大小有很大的可变性,并且您不想使用为500000行设计的执行计划当表只有一行时,反之亦然。

唯一的开销是需要在用户的模式中创建表。但大概你已经为新用户设置了一些设置 - 创建账户,授予权限等等 - 所以这不应该是一个很大的困难。

相关问题