您好,登錄后才能下訂單哦!
今天小編給大家分享一下Oracle數據庫的事務日志怎么理解的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
redo
重做日志文件(redo log file)對Oracle數據庫來說至關重要,它們是數據庫的事務日志。Oracle維護著兩類重做日志文件:
在線(online)重做日志文件和歸檔(archived)重做日志文件。這兩類重做日志文件都用于恢復;其主要目的是,
萬一實例失敗或介質失敗,它們就能派上用場。
如果數據庫所在主機掉電,導致實例失敗,Oracle會使用在線重做日志將系統恰好恢復到掉電之前的那個時間點。
如果磁盤驅動器出現故障(這是一個介質失敗),Oracle會使用歸檔重做日志以及在線重做日志將該驅動器上的
數據備份恢復到適當的時間點。
歸檔重做日志文件實際上就是已填滿的"舊"在線重做日志文件的副本。系統將日志文件填滿時,
ARCH進程會在另一個位置建立在線重做日志文件的一個副本,也可以在本地和遠程位置上建立多個另外的副本.
如果由于磁盤驅動器損壞或者其他物理故障而導致失敗,就會用這些歸檔重做日志文件來執行介質恢復.
Oracle拿到這些歸檔重做日志文件,并把它們應用于數據文件的備份,使這些數據文件能與數據庫的其余部分保持一至.
歸檔重做日志文件是數據庫的事務歷史。
測量redo
redo管理是數據庫中的一個串行點.任何Oracle實例都有一個LGWR,最終所有事務都會歸于LGWR,要求這個進程管理它們的redo,
并COMMIT其事務,LGWR工作越忙,系統就會越慢.通過查看一個操作會生成多少redo,并對一個問題的多種解決方法進行測試,
可以從中找出最佳的方法。
與redo有關的視圖
V$MYSTAT,其中有會話的提交信息
V$STATNAME,這個視圖能告訴我們V$MYSTAT中的每一行表示什么(查看的統計名)。
查詢redo大小的語句
SELECT a.NAME,
b.VALUE cur_size_byte,
round(b.VALUE / 1024, 3) || 'KB' cur_size_kb
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.NAME) LIKE '%' || lower('redo size') || '%'
數據庫歸檔模式
數據庫歸檔用來保存redo的日志文件副本,一般安裝時默認未開啟數據庫的歸檔模式。
在NOARCHIVELOG模式的數據庫中,除了數據字典的修改外,CREATE TABLE不會記錄日志.
如果你想在NOARCHIVELOG模式的數據庫上看到差別,可以把對表T的DROP TABLE和CREATE TABLE換成DROP INDEX和CREATE INDEX。
默認情況下,不論數據庫以何種模式運行,這些操作都會生成日志。
因為不同的模式可能導致不同的行為。你的生產系統可能采用ARCHIVELOG模式運行.
倘若你執行的大量操作在ARCHIVELOG模式下會生成redo,而在NOARCHIVELOG模式下不會生成redo,
你肯定想在測試時就發現這一點,而不要等到系統交付給用戶時才暴露出來!
查看是否歸檔
查看數據庫是否開啟歸檔
select name,log_mode from v$database;
啟用歸檔
startup mount
alter database archivelog;
alter database open;
禁止歸檔
shutdown immediate
startup mount
alter database noarchivelog
alter database open
force logging(強制日志)模式:
如果數據庫強制日志模式開啟后,則Oracle無論什么操作都進行redo的寫入。
查看強制日志模式
通過
select force_logging from v$database
可以看到當前數據庫是否開啟了強制日志模式狀態
開啟強制日志模式
如果未開啟數據庫強制日志模式(默認未開啟),則可以通過
alter database force logging開啟,之后Oracle無論什么操作都進行redo的寫入,不依賴于數據庫的歸檔模式等其他因素.
關閉強制日志模式
如果已經開啟了數據庫強制日志模式,則可以通過
alter database no force logging關閉強制日志模式。
使數據庫恢復先前的設置,數據庫是否寫入redo由數據庫的歸檔模式等其他因素決定
disable_logging
那么在Oracle內部還存在一個內部參數:_disable_logging 默認是false
通過更改為true可以讓Oracle在修改表中的記錄的時候完全不記錄redo,這個參數要甚用,平時,我們只作為性能測試用。
查看:show parameter disa /disable/_disable_logging
開啟:alter system set "_disable_logging"=true scope=both;
禁用:alter system set "_disable_logging"=false
表的歸檔模式
查看表的logging模式
查看表是否是logging狀態用如下SQL:
select table_name,logging from dba_tables where table_name='tablename';
修改表的logging模式
修改表的logging狀態sql:
alter table table_name nologging/logging
減少redo寫入
本節所講的都是當數據庫未開啟強制日志模式時的操作。
對象的操作在執行時會產生重做日志,采用某種方式,生成的redo會比平常(即不使用NOLOGGING子句時)少得多.
注意,這里說"redo"少得多,而不是"完全沒有redo".所有操作都會生成一些redo,不論數據庫的日志模式是什么,
所有數據字典操作都會計入日志。
如何減少redo
create table時減少redo的方法
創建表時crate table as加入nolongging選項減少redo,格式如下
create table [table_name] nologging as [select表達式]。
insert into減少redo的方法
insert 大批量數據時加入/*+append */選項減少redo寫入,格式如下
insert /*+append */ into [table_name] [select表達式]
數據庫歸檔模式下生成redo規則
create table時nologging效果
歸檔模式下創建的表,默認為logging模式。
創建表時crate table as加入nolongging選項減少redo寫入明顯
驗證
下面比較以下兩種create table as時產生的redo size量。
SELECT a.NAME,
b.VALUE cur_size_byte,
round(b.VALUE / 1024, 3) || 'KB' cur_size_kb
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.NAME) LIKE '%' || lower('redo size') || '%'
查詢當前的重做日志大小記錄下來
create table test_1 as select * from test;
SELECT a.NAME,
b.VALUE cur_size_byte,
round(b.VALUE / 1024, 3) || 'KB' cur_size_kb
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.NAME) LIKE '%' || lower('redo size') || '%'
查詢當前的重做日志大小減去前面記錄下來的值計算剛才這個操作產生的redo大小標記為redo_1
SELECT a.NAME,
b.VALUE cur_size_byte,
round(b.VALUE / 1024, 3) || 'KB' cur_size_kb
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.NAME) LIKE '%' || lower('redo size') || '%'
查詢當前的重做日志大小記錄下來
create table test_2 nologging as select * from test;
SELECT a.NAME,
b.VALUE cur_size_byte,
round(b.VALUE / 1024, 3) || 'KB' cur_size_kb
FROM v$statname a, v$mystat b
WHERE a.statistic# = b.statistic#
AND lower(a.NAME) LIKE '%' || lower('redo size') || '%'
查詢當前的重做日志大小減去前面記錄下來的值計算剛才這個操作產生的redo大小標記為redo_2
比較redo_1和redo_2的大小就知道crate table as加入nolongging或不加nologging選項的區別了
insert into時加入append效果
表模式logging
當表模式為logging狀態時,無論是append模式還是no append模式,redo都會生成,即加入append選項無法生效。
驗證
下面比較以下兩種insert時產生的redo size量,可以看出redo量是差不多的。
計算重做大小的方法與上面的一樣就不說了
1、insert /*+append */ into test_1 select * from test;
commit;
2、insert into test_1 select * from test;
commit;
表模式nologging
當表模式為nologging狀態時,只有加入append模式會明顯減少生成redo。
驗證
1、insert /*+append */ into test_1 select * from test;
commit;
2、insert into test_1 select * from test;
commit;
數據庫非歸檔模式生成redo規則
create table 使用nologging對產生redo的影響
非歸檔模式下創建的表,默認為nologging模式。
在NOARCHIVELOG模式的數據庫中,除了數據字典的修改外,CREATE TABLE不會記錄日志。
因此創建表時(crate table as)加入nologging選項減少redo寫入不明顯,即nologging選項加不加都差不多
驗證
下面比較以下兩種create table as時產生的redo size量。
create table test_1 as select * from test;
create table test_2 nologging as select * from test;
insert into時append效果
表模式logging
當表模式為logging狀態時,加入append模式明顯減少生成redo,而no append模式下不會減少生成。
驗證
insert /*+append */ into test_1 select * from test;
commit;
insert into test_1 select * from test;
commit;
表模式nologging
當表模式為nologging狀態時,append的模式會減少生成redo,而no append模式不會減少生成。
驗證
insert /*+append */ into test_1 select * from test;
commit;
insert into test_1 select * from test;
commit;
其實就是直截加載與傳統加載的區別
直接加載優勢
直接加載比傳統加載效率要高
不掃描原來的空數據塊
不需要sql解析,減少系統的負載
不經過SGA
不走DBWR進程,走自己的專屬進程,所以速度快
直接加載限制
不能加載簇表
鎖定整個表,在表上有活動事務的時候不能加載
直接加載特點
直接加載是在所有數據塊后面加載新數據塊,修改高水位線,不掃描原來的空數據塊。
直接加載只產生一點點的管理redo,因為要修改數據字典(也可以講不產生redo)。
回滾,如果加載失敗把新分配數據塊抹掉就行了。
無需SGA,無需SQL解析,無需DBWR進程
實驗
現在我們已經定義了test;
SQL> select count(*) from test; 現在表里沒有記錄數
COUNT(*)
----------
0
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='TEST'; 現在分配了1個區
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 0 65536
[oracle@secdb1 ~]$ sqlldr userid=ls/ls control=leo_test.ctl data=leo_test.data log=leo_test.log 傳統方式加載數據
LS@LEO> select count(*) from test; 已經成功加載了100萬條數據
COUNT(*)
----------
1000000
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='TEST'; 100萬條數據占用28個區
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 0 65536
TEST 1 65536
TEST 2 65536
TEST 3 65536
TEST 4 65536
TEST 5 65536
TEST 6 65536
TEST 7 65536
TEST 8 65536
TEST 9 65536
TEST 10 65536
TEST 11 65536
TEST 12 65536
TEST 13 65536
TEST 14 65536
TEST 15 65536
TEST 16 1048576
TEST 17 1048576
TEST 18 1048576
TEST 19 1048576
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 20 1048576
TEST 21 1048576
TEST 22 1048576
TEST 23 1048576
TEST 24 1048576
TEST 25 1048576
TEST 26 1048576
TEST 27 1048576
28 rows selected
SQL> delete from test; 刪除100萬條數據
1000000 rows deleted.
SQL> commit; 提交
Commit complete.
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='TEST';
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 0 65536
TEST 1 65536
TEST 2 65536
TEST 3 65536
TEST 4 65536
TEST 5 65536
TEST 6 65536
TEST 7 65536
TEST 8 65536
TEST 9 65536
TEST 10 65536
TEST 11 65536
TEST 12 65536
TEST 13 65536
TEST 14 65536
TEST 15 65536
TEST 16 1048576
TEST 17 1048576
TEST 18 1048576
TEST 19 1048576
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 20 1048576
TEST 21 1048576
TEST 22 1048576
TEST 23 1048576
TEST 24 1048576
TEST 25 1048576
TEST 26 1048576
TEST 27 1048576
28 rows selected
把數據都刪除了還占用空間,oracle的delete操作不回收空間,只是把自己的記錄標記為刪除,實際呢還占用的空間不釋放
[oracle@secdb1 ~]$ sqlldr userid=ls/ls control=leo_test.ctl data=leo_test.data log=leo_test.log 第二次傳統方式加載數據
SQL> select count(*) from test; 已經成功加載了100萬條數據
COUNT(*)
----------
1000000
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='TEST';
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 0 65536
TEST 1 65536
TEST 2 65536
TEST 3 65536
TEST 4 65536
TEST 5 65536
TEST 6 65536
TEST 7 65536
TEST 8 65536
TEST 9 65536
TEST 10 65536
TEST 11 65536
TEST 12 65536
TEST 13 65536
TEST 14 65536
TEST 15 65536
TEST 16 1048576
TEST 17 1048576
TEST 18 1048576
TEST 19 1048576
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 20 1048576
TEST 21 1048576
TEST 22 1048576
TEST 23 1048576
TEST 24 1048576
TEST 25 1048576
TEST 26 1048576
TEST 27 1048576
28 rows selected
使用傳統方式加載數據,會掃描原來的空數據塊,會把新加載的數據插入到空數據塊內,看我們還是使用原來的28個區
SQL> delete from test; 這是第二次刪除100萬條數據
1000000 rows deleted.
SQL> commit; 提交
Commit complete.
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='TEST';
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 0 65536
TEST 1 65536
TEST 2 65536
TEST 3 65536
TEST 4 65536
TEST 5 65536
TEST 6 65536
TEST 7 65536
TEST 8 65536
TEST 9 65536
TEST 10 65536
TEST 11 65536
TEST 12 65536
TEST 13 65536
TEST 14 65536
TEST 15 65536
TEST 16 1048576
TEST 17 1048576
TEST 18 1048576
TEST 19 1048576
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 20 1048576
TEST 21 1048576
TEST 22 1048576
TEST 23 1048576
TEST 24 1048576
TEST 25 1048576
TEST 26 1048576
TEST 27 1048576
28 rows selected
delete還是不回收空間,我們依然占用著28個區
[oracle@secdb1 ~]$ sqlldr userid=ls/ls control=leo_test.ctl data=leo_test.data log=leo_test.log direct=true 直接方式加載數據
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='TEST';
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 0 65536
TEST 1 65536
TEST 2 65536
TEST 3 65536
TEST 4 65536
TEST 5 65536
TEST 6 65536
TEST 7 65536
TEST 8 65536
TEST 9 65536
TEST 10 65536
TEST 11 65536
TEST 12 65536
TEST 13 65536
TEST 14 65536
TEST 15 65536
TEST 16 1048576
TEST 17 1048576
TEST 18 1048576
TEST 19 1048576
SEGMENT_NAME EXTENT_ID BYTES
-------------------------------------------------------------------------------- ---------- ----------
TEST 20 1048576
TEST 21 1048576
TEST 22 1048576
TEST 23 1048576
TEST 24 1048576
TEST 25 1048576
TEST 26 1048576
TEST 27 1048576
TEST 28 1048576
TEST 29 1048576
TEST 30 1048576
TEST 31 1048576
TEST 32 1048576
TEST 33 1048576
TEST 34 1048576
TEST 35 1048576
TEST 36 1048576
TEST 37 1048576
TEST 38 1048576
TEST 39 1048576
TEST 40 1048576
TEST 41 1048576
TEST 42 1048576
TEST 43 1048576
TEST 44 1048576
TEST 45 1048576
TEST 46 1048576
TEST 47 1048576
48 rows selected
發現同樣的100萬條記錄,竟然占用了48個區,傳統加載只用了28個,而我們使用直接加載到多了20個數據塊,
對了直接加載不掃描原來的空數據塊,會在所有數據塊之后加載新的數據塊插入數據修改高水位線HWM,
當提交事務之后,把高水位線移到新數據之后,其他的用戶就可以看見了。
比較直接加載使用conventional 和direct方式產生的redo大小(可以通過/*+ append */模擬直接加載)。
明確:直接加載與logging配合下并不能顯著的減少redo日志量
直接加載與nologging配合下可以大幅度的減少redo日志量
SQL> create table leo_t1 as select * from test where 1=2; 創建leo_t1表
Table created.
SQL> alter table leo_t1 logging; 設置leo_t1表logging模式
Table altered.
SQL> set autotrace traceonly;
SQL> insert into leo_t1 select * from leo_test_sqlload where rownum <= 20000; 采用傳統方式加載2萬條記錄
20000 rows created.
Statistics 統計信息
----------------------------------------------------------
1071 recursive calls
2668 db block gets
1860 consistent gets
386 physical reads
1680404 redo size 這是產生的日志量1680404
680 bytes sent via SQL*Net to client
603 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
20000 rows processed
SQL> rollback; 回滾操作,使用undo表空間
Rollback complete.
SQL> insert /*+ append */ into leo_t1 select * from leo_test_sqlload where rownum <= 20000; 使用直接加載方式插入2萬條記錄
20000 rows created.
Statistics
----------------------------------------------------------
94 recursive calls
268 db block gets
1294 consistent gets
202 physical reads
1627260 redo size 當leo_t1為logging屬性時,直接加載和傳統加載產生redo日志差不多
664 bytes sent via SQL*Net to client
617 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
20000 rows processed
小結:這是因為在logging模式下,所有的數據塊的改變都會產生redo日志,為以后恢復做準備,這時候直接加載沒有多大的優勢。
直接加載與nologging配合下可以大幅度的減少redo日志量
重大前提
如果你的數據庫開啟了force_logging=yes模式,那么不管你是傳統加載還是直接加載都不會減少redo產生量
所以要想大幅度減少redo日志就必須滿足3個條件
(1)關閉force_logging選項 alter database no force logging; 啟動 alter database force logging;
(2)數據對象級別nologging模式 alter table leo_t1 nologging;
(3)直接加載 insert /*+ append */ into
數據庫歸檔與redo日志量關系
數據庫處于歸檔模式
當表模式為logging狀態時,無論是否使用append模式,都會生成redo.當表模式為nologging狀態時,只有append模式,不會生成redo。
數據庫處于非歸檔模式
無論是在logging還是nologing的模式下,append的模式都不會生成redo,而no append模式下都會生成redo。
SQL> alter database no force logging;
SQL> select force_logging from v$database; 已經關閉force_logging選項
FOR
---
NO
SQL> alter table leo_t1 nologging; 設置leo_t1表nologging模式
Table altered.
SQL> select logging from user_tables where table_name='LEO_T1';
LOG
---
NO
SQL> select count(*) from leo_t1; 0條記錄
COUNT(*)
----------
0
SQL> select index_name from user_indexes where table_name='LEO_T1'; 表上沒有索引
no rows selected
SQL> insert /*+ append */ into leo_t1 select * from leo_test_sqlload where rownum <= 20000; 直接加載
20000 rows created.
Statistics
----------------------------------------------------------
1443 recursive calls
649 db block gets
1702 consistent gets
1519 physical reads
44900 redo size 直接加載產生的redo日志非常少
658 bytes sent via SQL*Net to client
617 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
9 sorts (memory)
0 sorts (disk)
20000 rows processed
SQL> rollback;
Rollback complete.
LS@LEO> insert into leo_t1 select * from leo_test_sqlload where rownum <= 20000; 傳統加載
20000 rows created.
Statistics
----------------------------------------------------------
4 recursive calls
2207 db block gets
1534 consistent gets
441 physical reads
1634064 redo size 傳統加載產生的redo日志非常非常的多
673 bytes sent via SQL*Net to client
603 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
20000 rows processed
小結:直接加載與nologging配合下可以大幅度的減少redo日志量,因為插入的數據不產生redo日志,
所以在插入后要做備份操作,一旦數據損壞,就要使用備份來恢復,不能使用redo來恢復。注意要關閉force_logging選項
以上就是“Oracle數據庫的事務日志怎么理解”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。