IAd*_*ter 4 database oracle performance myisam transactions
MySQL具有不支持事务的特殊表类型MyISAM.Oracle有类似的东西吗?我想创建只写数据库(用于日志记录),需要非常快(将存储大量数据)并且不需要事务.
事务是SQL数据库操作的关键.它们肯定是Oracle的基础.如果不发出提交,就无法永久写入Oracle表,而且!有交易.
Oracle允许我们将表指定为NOLOGGING,它不会生成重做日志.这仅用于批量加载(使用INSERT /*+ APPEND */提示),建议切换到LOGGING并尽快退回.因为未记录的数据无法恢复.如果你不想恢复它,为什么还要先写它呢?
另一种方法是批量写入内存中的写入,然后使用批量插入来编写它们.这很快.
这是一个简单的日志表和概念证明包:
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;
/
Run Code Online (Sandbox Code Playgroud)
日志记录保存在PL/SQL集合中,该集合是具有会话范围的内存中结构.INIT()过程初始化缓冲区.FLUSH()过程将缓冲区的内容写入LOG_TABLE.WRITE()过程将一个条目插入缓冲区,如果缓冲区具有必需的条目数,则调用FLUSH().
create or replace package body fast_log is
type log_buffer is table of log_table%rowtype;
session_log log_buffer;
write_limit constant pls_integer := 1000;
write_count pls_integer;
procedure init
is
begin
session_log := log_buffer();
session_log.extend(write_limit);
write_count := 0;
end init;
procedure flush
is
begin
dbms_output.put_line('FLUSH::'||to_char(systimestamp,'HH24:MI:SS.FF6')||'::'||to_char(write_count));
forall i in 1..write_count
insert into log_table
values session_log(i);
init;
end flush;
procedure write (p_short log_table.short_text%type
, p_long log_table.long_text%type)
is
pragma autonomous_transaction;
begin
write_count := write_count+1;
session_log(write_count).ts := systimestamp;
session_log(write_count).short_text := p_short;
session_log(write_count).long_text := p_long;
if write_count = write_limit
then
flush;
end if;
commit;
end write;
begin
init;
end fast_log;
/
Run Code Online (Sandbox Code Playgroud)
写入日志表使用AUTONOMOUS_TRANSACTION编译指示,因此发生COMMIT而不影响触发刷新的周围事务.
对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>
Run Code Online (Sandbox Code Playgroud)
嗯,在0.12秒内有3456个记录,这不算太破旧.这种方法的主要问题是需要刷新缓冲区来舍入松散的记录; 这是一个痛苦,例如在会话结束时.如果某些内容导致服务器崩溃,则会丢失未刷新的记录.在内存中执行操作的另一个问题是它消耗内存(durrrr),因此我们无法使缓存太大.
为了便于比较,我在程序包中添加了一个过程,每次调用时都会将一条记录直接插入到LOG_TABLE中,再次使用自治事务:
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;
Run Code Online (Sandbox Code Playgroud)
这是它的时间:
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>
Run Code Online (Sandbox Code Playgroud)
众所周知,挂钟定时不可靠,但批量处理方法比单个记录appraoch快2-3倍.即便如此,我还是可以在不到半秒的时间内(远离顶级的)笔记本电脑执行超过三千次离散交易.所以,问题是:记录了多少瓶颈?
为了避免任何误解:
@JulesLt在我处理PoC时发布了他的答案.虽然我们的观点有相似之处,但我认为建议的解决方法的差异值得发布.
"没有自主但最终只有一次提交的write_each的时机是什么时候?我的时间表明它并不重要 - 填充插入是一个巨大的胜利"
我的时间表明略有不同.每次写入时用一个COMMIT替换COMMIT大致将经过的时间减半.仍然比批量方法慢,但不是那么多.
这里的关键是基准测试.我的概念证明运行速度比Jules的测试速度快六倍(我的表有一个索引).这可能有多种原因 - 机器规格,数据库版本(我使用的是Oracle 11gR1),表结构等等.换句话说,YMMV.
因此,教学是:首先确定为您的应用程序做正确的事情,然后根据您的环境进行基准测试.如果您的基准测试表明存在严重的性能问题,则只考虑不同的方 Knuth关于过早优化的警告适用.