在oracle中只选择新行

时间:2010-03-23 15:38:47

标签: oracle

我有“varchar2”作为主键的表 它每天有大约1 000 000笔交易。

我的应用程序每5分钟唤醒一次,通过仅查询新记录来生成文本文件 它将记住最后一点并仅处理新记录。

  1. 您是否知道如何以良好的性能进行查询? 如有必要,我可以添加新列。

  2. 您认为这个过程应该怎样做?

    • PLSQL?
    • java吗?

10 个答案:

答案 0 :(得分:3)

这里的每个人都非常亲密。但是:

如果表格在任何类型的连续DML加载下,那么Scott Bailey使用位图索引是错误的。这是使用位图索引的错误时间。

其他人对PROCESSED CHAR(1) check in ('Y','N')列的回答是正确的,但却错过了如何对其进行索引;你应该使用这样的基于函数的索引:

CREATE INDEX MY_UNPROCESSED_ROWS_IDX ON MY_TABLE
  (CASE WHEN PROCESSED_FLAG = 'N' THEN 'N' ELSE NULL END);

然后使用相同的表达式查询它:

SELECT * FROM MY_TABLE
 WHERE (CASE WHEN PROCESSED_FLAG = 'N' THEN 'N' ELSE NULL END) = 'N';

使用基于函数的索引的原因是Oracle不会为索引的完全NULL值编写索引条目,因此上面基于函数的索引将只包含PROCESSED_FLAG = 'N'的行。当您将行更新为PROCESSED_FLAG = 'Y'时,它们将“脱离”索引。

答案 1 :(得分:2)

好吧,如果您可以添加新列,则可以创建 Processed 列,该列将指示已处理的记录,并在此列上创建索引以提高性能。

然后查询应仅针对那些新添加的行,而不是已处理

这应该可以使用SQL查询轻松完成。

答案 2 :(得分:2)

啊,我真的很讨厌当其他人已经接近钉住它时再添加一个答案。但

正如Ponies指出的那样,Oracle确实有一个隐藏列(ORA_ROWSCN - 系统变更编号),可以查明每行被修改的时间。不幸的是,默认情况下,它从块获取信息而不是将其存储在每一行中,并且更改该行为将需要您重建一个非常大的表。因此,尽管这个答案对于安静SQL Server有用,但我不推荐它。

Astander就在那里,但需要一些警告。添加一个新列needs_processed CHAR(1)DEFAULT'Y'并添加一个BITMAP索引。对于低基数列('Y'/'N'),位图索引会更快。一旦你完成剩下的工作就很容易了。但是你必须要小心,不要选择新行,处理它们并将它们标记为一步处理。否则,可以在处理时插入行,这些行将被标记处理,即使它们还没有。

最简单的方法是使用pl / sql打开一个游标,选择未处理的行,处理它们,然后在处理时更新行。如果你厌恶步行游标,你可以将pk或rowid收集到嵌套表中,处理它们然后使用嵌套表进行更新。

答案 3 :(得分:0)

在我工作的MS SQL Server世界中,我们的表格上有一个'version'列,类型为'timestamp'。

所以,为了回答#1,我会添加一个新列。

要回答#2,我会在plsql中执行此操作。

标记

答案 4 :(得分:0)

“astander”几乎为你做了工作。您需要ALTER您的表格添加一列(让我们说PROCESSED )..

您还可以考虑在INDEX上创建PROCESSED a bitmap index可能会有一些优势,因为可能的值只能是'y'和'n ',但测试它),以便在查询时它将使用INDEX。

此外,如果确定,您每隔5分钟查询一次,请检查是否可以添加另一个TIMESTAMP类型的列,并使用它对表进行分区。 (不确定,再次退房)。

我还会考虑写作业或某些事情并使用UTL_FILE进行写作,并在可能的情况下显示前端。

答案 5 :(得分:0)

如果性能确实存在问题并且您想要异步创建文件,则可能需要使用Oracle Streams,它实际上会从重做日志中获取修改数据,而不会影响主数据库的性能。您甚至可能不需要单独的作业,因为您可以将Oracle Streams配置为执行更改的异步复制,通过它可以触发文件创建。

答案 6 :(得分:0)

为什么不创建一个包含两列的额外表。 ID列和已处理的标志列。在原始表上有一个插入触发器,将它的ID放在这个新表中。您的日志记录过程可以选择此新表中的记录并将其标记为已处理。最后从该表中删除已处理的记录。

答案 7 :(得分:0)

我非常同意亚当的回答。但是,与替代方案相比,我想做一些严肃的测试。

我看到的问题是,您不仅需要选择行,还需要更新这些行。虽然这应该很快,但我想避免更新。并避免任何大型交易(见下文)。

另一种方法是添加CREATE_DATE日期默认sysdate。索引。然后选择创建create_date> =(上次选择的开始日期/时间)的记录。

但是我没有足够的数据来确定将sysdate设置为默认值与设置Y值,更新基于函数的日期索引以及在日期与特定日期之间进行范围选择的相对成本选择Y的单个值。您可能希望保留统计信息或提示查询使用Y / N列上的索引,并且肯定希望在日期列上使用提示 - 日期中的统计信息专栏几乎肯定会老。

如果数据也在不断地添加到表中,包括在查询运行期间,您需要注意事务控制。毕竟,您不希望读取100,000个具有标志= Y的记录,然后在120,000上执行更新,包括在查询运行时到达的20,000个。

在标志的情况下,有两种简单的方法:在更新之后选择和提交之前设置TRANSACTION,或者从Y到Q进行更新,然后选择那些是Q,然后更新到N. Oracle的读取一致性非常好,但需要小心处理。

对于日期列版本,如果您不介意多次处理多行的风险,只需在执行选择之前立即更新具有上次处理日期/时间的表。

如果表格中的信息不多,请考虑将其编入索引组织。

答案 8 :(得分:0)

使用Materialized view logs怎么样?你有很多选择:

SQL> create table test (id_test number primary key, dummy varchar2(1000));

Table created

SQL> create materialized view log on test;

Materialized view log created

SQL> insert into test values (1, 'hello');

1 row inserted

SQL> insert into test values (2, 'bye');

1 row inserted

SQL> select * from mlog$_test;

   ID_TEST SNAPTIME$$  DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$
---------- ----------- --------- --------- ---------------------
         1 01/01/4000  I         N         FE
         2 01/01/4000  I         N         FE

SQL> delete from mlog$_test where id_test in (1,2);

2 rows deleted

SQL> insert into test values (3, 'hello');

1 row inserted

SQL> insert into test values (4, 'bye');

1 row inserted

SQL> select * from mlog$_test;

   ID_TEST SNAPTIME$$  DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$
---------- ----------- --------- --------- ---------------
         3 01/01/4000  I         N         FE
         4 01/01/4000  I         N         FE

答案 9 :(得分:0)

我认为这个解决方案应该有效.. 您需要执行以下步骤

首次运行时,您必须复制所有记录。在第一次运行中,您需要执行以下查询

插入到new_table(max_rowid)中(从yourtable中选择max(rowid));

现在,下次当您只想获取新插入的值时,可以通过执行以下命令来执行此操作

从yourtable中选择*,其中rowid> (从new_table中选择max_rowid);

完成上述查询处理后,只需截断new_table并从yourtable插入max(rowid)

我认为这应该有效并且是最快的解决方案;