Database 如何在没有事务的情况下使用Oracle?
MySQL具有不支持事务的特殊表类型MyISAM。甲骨文有这样的东西吗?我想创建一个只写数据库(用于日志记录),它需要非常快(将存储大量数据)并且不需要事务。对于类似的情况,我会做的是将日志写入一个文件(附加到文件可能是存储日志的最快方式)然后让一个批处理程序定期将这些日志插入数据库。当然,除非直接插入数据库足够快。。。但是您必须测试…最接近的方法可能是创建一个NOLOGGING表空间,并使用NOLOGGING选项在其中创建表-尽管这可能只适用于批量操作(即需要INSERT/*+APPEND*/hint) 这将删除重做,如果数据库宕机,将以丢失完整性和数据为代价Database 如何在没有事务的情况下使用Oracle?,database,performance,oracle,transactions,myisam,Database,Performance,Oracle,Transactions,Myisam,MySQL具有不支持事务的特殊表类型MyISAM。甲骨文有这样的东西吗?我想创建一个只写数据库(用于日志记录),它需要非常快(将存储大量数据)并且不需要事务。对于类似的情况,我会做的是将日志写入一个文件(附加到文件可能是存储日志的最快方式)然后让一个批处理程序定期将这些日志插入数据库。当然,除非直接插入数据库足够快。。。但是您必须测试…最接近的方法可能是创建一个NOLOGGING表空间,并使用NOLOGGING选项在其中创建表-尽管这可能只适用于批量操作(即需要INSERT/*+APPEND*/
我不知道它实际上是“更快”的,你也应该考虑并发(如果你有很多进程试图写入同一个表,那么你可以更好的使用写挂起的更新到重做日志中的事务,而不是尝试全部更新‘真实表’。” 不过,我还没有真正研究过NOLOGGING——我很少遇到应用程序瓶颈是插入速度的问题——当我研究过时,问题出在更新索引的成本上,而不是表
我刚刚做了一个快速测试,在我动力不足的开发数据库上(启用了重做)。为每一行使用一个自治事务—因此每一行开始一个新事务并以提交结束,我可以在1秒内将1000多行写入/提交到一个索引日志表中,而在不提交的情况下执行1000次插入大约需要.875秒 使用批量操作在一次点击中插入1000行只需几秒钟,因此,如果您可以将日志批量化,就可以这样做 其他一些想法:外部表是否可以完成这项工作?例如,写入日志文件,然后在需要读取时将其作为Oracle中的外部表装载?这似乎是一种解决问题的方法 你有没有对业绩进行基准测试?甲骨文的速度够快吗?事务管理内置于Oracle的工作方式中,试图绕过它似乎是在为自己创造工作
您似乎已经将事务管理视为一个问题,而不知道是否存在问题。当桌上有多个书写器时,以后会发生什么?还是读卡器阻止写卡器?事务是SQL数据库操作的关键。它们无疑是甲骨文的基础。如果不发出commit,就无法永久写入Oracle表,而且lo!这就是交易 Oracle允许我们指定要取消记录的表,这不会生成重做日志。这仅适用于批量加载(使用
INSERT/*+APPEND*/
提示),建议切换到日志记录并尽快返回。因为未记录的数据是不可恢复的。如果你不想恢复它,为什么一开始就要写呢
另一种方法是对内存中的写入进行批处理,然后使用大容量插入进行写入。这相当快
以下是一个简单的日志表和一个概念验证包:
create table log_table
(ts timestamp(6)
, short_text varchar(128)
, long_text varchar2(4000)
)
/
create or replace package fast_log is
procedure init;
procedure flush;
procedure write (p_short log_table.short_text%type
, p_long log_table.long_text%type);
end fast_log;
/
日志记录保存在PL/SQL集合中,该集合是具有会话作用域的内存中结构。INIT()过程初始化缓冲区。FLUSH()过程将缓冲区的内容写入LOG_表。WRITE()过程在缓冲区中插入一个条目,如果缓冲区具有所需数量的条目,则调用FLUSH()
写入日志表使用自治的_事务pragma,因此提交不会影响触发刷新的周围事务
对DBMS_OUTPUT.PUT_LINE()的调用是为了便于监控进度。那么,让我们看看它有多快
SQL> begin
2 fast_log.flush;
3 for r in 1..3456 loop
4 fast_log.write('SOME TEXT', 'blah blah blah '||to_char(r));
5 end loop;
6 fast_log.flush;
7 end;
8 /
FLUSH::12:32:22.640000::0
FLUSH::12:32:22.671000::1000
FLUSH::12:32:22.718000::1000
FLUSH::12:32:22.749000::1000
FLUSH::12:32:22.781000::456
PL/SQL procedure successfully completed.
SQL>
嗯,0.12秒内录制3456张唱片,还不算太差。这种方法的主要问题是需要刷新缓冲区以收集松散的记录;这是一种疼痛,例如,在一个疗程结束时。如果某个原因导致服务器崩溃,未刷新的记录将丢失。在内存中执行任务的另一个问题是它会消耗内存(durrr),因此我们不能使缓存太大
为了便于比较,我向包中添加了一个过程,该过程在每次调用LOG_表时直接将一条记录插入其中,再次使用自治事务:
procedure write_each (p_short log_table.short_text%type
, p_long log_table.long_text%type)
is
pragma autonomous_transaction;
begin
insert into log_table values ( systimestamp, p_short, p_long );
commit;
end write_each;
以下是它的时间安排:
SQL> begin
2 fast_log.flush;
3 for r in 1..3456 loop
4 fast_log.write_each('SOME TEXT', 'blah blah blah '||to_char(r));
5 end loop;
6 fast_log.flush;
7 end;
8 /
FLUSH::12:32:44.157000::0
FLUSH::12:32:44.610000::0
PL/SQL procedure successfully completed.
SQL>
众所周知,挂钟计时不可靠,但批处理方法比单记录方法快2-3倍。即便如此,我也可以在不到半秒钟的时间内,在一台笔记本电脑上执行三千多个离散事务。所以,问题是:日志记录有多大的瓶颈
为避免任何误解: @JulesLt在我进行PoC时发布了他的答案。虽然我们的观点有相似之处,但我认为建议的解决方法的差异值得发表这篇文章
“每次写作的时间是什么 没有自主,只有一个 在最后承诺?我的时间安排表明 这并不重要——那就是膨胀 插入是一大胜利” 我的时间安排暗示了一些稍微不同的事情。将每次写入的提交替换为最后的一次提交,所用时间大约为所用时间的一半。仍然比庞大的方法慢,但没有那么多 这里的关键是基准测试。我的概念验证运行速度大约是Jules测试的六倍(我的表有一个索引)。这可能有各种各样的原因——机器规格、数据库版本(我使用的是Oracle11GR1)、表结构等等,换句话说,YMMV 所以教学是:首先决定什么
SQL> begin
2 fast_log.flush;
3 for r in 1..3456 loop
4 fast_log.write_each('SOME TEXT', 'blah blah blah '||to_char(r));
5 end loop;
6 fast_log.flush;
7 end;
8 /
FLUSH::12:32:44.157000::0
FLUSH::12:32:44.610000::0
PL/SQL procedure successfully completed.
SQL>
CREATE OR REPLACE FUNCTION FNC_LOG(p_log_text varchar2(4000))
RETURN NUMBER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- Your brief code goes here (don't abuse the evil feature that is autonomous transactions).
END;