達夢6.0試用之併發和鎖機制
前幾天ITPUB的熊建國主編和我聯絡,希望我能參加國產資料庫達夢的適用活動,並寫幾篇使用感受。本來最近手工的事情比較多,本打算推辭的,不過熊主編再三邀請,而且強調並非是槍手文,只要寫出真實使用感受即可。既然如此,我就本著支援國產資料庫的原則,寫幾篇試用感受。
由於本人唯一熟悉的資料庫就是Oracle,因此所有的對比都是與Oracle資料庫進行對比,在這個過程中,將盡可能避免將對Oracle資料庫的喜愛之情帶進來,爭取站在一個比較公正的位置上來進行評價。
這一篇簡單介紹一下達夢資料庫的鎖機制和併發控制。
達夢的鎖機制和Oracle的並不相同,Oracle和其他資料庫相比最突出的特點就是鎖的實現,一方面是行級鎖,而且鎖並非資源,只是佔用極少的儲存空間;另一方面Oracle沒有讀鎖,讀不阻塞寫,寫也不會阻塞讀。即使DB2、SQLSERVER等資料庫也無法做到這一點,顯然不能要求達夢達到這樣的標準。
看看達夢的鎖實現:
SQL>CREATE TABLE T
2 (ID NUMBER,
3 NAME VARCHAR(30),
4 AGE NUMBER);
CREATE TABLE T
(ID NUMBER,
NAME VARCHAR(30),
AGE NUMBER);
time used: 45.975(ms) clock tick:76680990.
SQL>INSERT INTO T
2 VALUES (1, 'A', 10);
INSERT INTO T
VALUES (1, 'A', 10)
1 rows affected
time used: 0.473(ms) clock tick:770450.
SQL>INSERT INTO T
2 VALUES (2, 'B', 20);
INSERT INTO T
VALUES (2, 'B', 20)
1 rows affected
time used: 0.423(ms) clock tick:698510.
SQL>INSERT INTO T
2 VALUES (3, 'C', 30);
INSERT INTO T
VALUES (3, 'C', 30)
1 rows affected
time used: 0.391(ms) clock tick:643640.
SQL>COMMIT;
COMMIT;
time used: 11.657(ms) clock tick:19480330.
SQL>SELECT * FROM T;
SELECT * FROM T;
ID NAME AGE
1 1 A 10
2 2 B 20
3 3 C 30
3 rows got
time used: 0.448(ms) clock tick:739460.
建立了一個測試表之後,下面看看達夢是否採用行級鎖來鎖定記錄:
SQL>UPDATE T
2 SET AGE = 20
3 WHERE ID = 1;
UPDATE T
SET AGE = 20
WHERE ID = 1;
1 rows affected
time used: 0.554(ms) clock tick:917730.
需要注意,在進行這個測試的時候,需要確保AUTOCOMMIT是關閉的。
在另外的會話中更新ID為2的記錄,這時會話被阻塞:
SQL>UPDATE T
2 SET AGE = 30
3 WHERE ID = 2;
在第一個會話中檢查系統的鎖狀態:
SQL>SELECT TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, ROW_ID
2 FROM SYSTEM.SYSDBA.V$LOCK
3 WHERE LTYPE != 'DICT';
SELECT TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, ROW_ID
FROM SYSTEM.SYSDBA.V$LOCK
WHERE LTYPE != 'DICT';
TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_ID
1 1245 TABLE IX 0 1026 0x0000000000000000
2 1246 TABLE IX 0 1026 0x0000000000000000
3 1245 ROW X 0 1026 0x000000000033FD31
4 1246 ROW S 1 1026 0x000000000033FD31
4 rows got
time used: 22.091(ms) clock tick:36925520.
可以看到,事務ID為1246並不是由於要獲取獨佔鎖而被阻塞,而是在查詢到被修改的記錄時被鎖定。
也就是說,在達夢資料庫中,寫是阻塞讀的。
如果要避免這種情況的產生,可以建立ID列上的索引。
首先,會話1提交是否鎖:
SQL>COMMIT;
COMMIT;
time used: 50.458(ms) clock tick:84356900.
這時會話2上UPDATE操作成功:
1 rows affected
time used: 6652041.104(ms) clock tick:3358507298.
下面再次檢查當前的鎖資訊:
SQL>SELECT TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, ROW_ID
2 FROM SYSTEM.SYSDBA.V$LOCK
3 WHERE LTYPE != 'DICT';
SELECT TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, ROW_ID
FROM SYSTEM.SYSDBA.V$LOCK
WHERE LTYPE != 'DICT';
TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_ID
1 1246 TABLE IX 0 1026 0x0000000000000000
2 1246 ROW X 0 1026 0x000000000033FD32
2 rows got
time used: 0.405(ms) clock tick:668360.
剛才被阻塞的事務1246現在獲得了獨佔鎖,可以放心當前鎖定的行並不是1245鎖定的記錄。看來達夢中實現的確實是行級鎖,不過達夢並沒有解決讀寫相互鎖定的問題。為了避免剛才的現象,在ID列增加索引:
SQL>COMMIT;
COMMIT;
time used: 11.548(ms) clock tick:19298280.
SQL>CREATE INDEX IND_T_ID
2 ON T(ID);
CREATE INDEX IND_T_ID
ON T(ID);
time used: 36.302(ms) clock tick:60422530.
下面再次執行剛才的操作:
SQL>UPDATE T
2 SET AGE = 30
3 WHERE ID = 1;
UPDATE T
SET AGE = 30
WHERE ID = 1;
1 rows affected
time used: 38.401(ms) clock tick:64196100.
會話一的UPDATE成功。
SQL>UPDATE T
2 SET AGE = 40
3 WHERE ID = 2;
UPDATE T
SET AGE = 40
WHERE ID = 2;
1 rows affected
time used: 0.467(ms) clock tick:772190.
而會話二執行UPDATE也成功了。
這時再次檢查鎖資訊:
SQL>SELECT TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, ROW_ID
2 FROM SYSTEM.SYSDBA.V$LOCK
3 WHERE LTYPE != 'DICT';
SELECT TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, ROW_ID
FROM SYSTEM.SYSDBA.V$LOCK
WHERE LTYPE != 'DICT';
TRX_ID LTYPE LMODE BLOCKED TABLE_ID ROW_ID
1 1247 TABLE IX 0 1026 0x0000000000000000
2 1249 TABLE IX 0 1026 0x0000000000000000
3 1249 ROW X 0 1026 0x000000000033FD32
4 1247 ROW X 0 1026 0x000000000033FD31
4 rows got
time used: 0.435(ms) clock tick:717070.
現在可以清晰的看到,兩個併發的事務分別鎖定同一張表的兩條不同的記錄。這說明達夢中實現了行級鎖定。雖然這個動態檢視提供的資訊如此直觀和清晰,甚至在Oracle中我們都不知道具體鎖定了哪條記錄,但是這也暴露了一個問題。就是在達夢資料庫中鎖是一種資源,資料庫需要記錄每條鎖定的記錄。當資料量過大的時候,為了避免消耗更多的資源,達夢資料庫會採用鎖升級的策略:
SQL>CREATE TABLE T_RECORD
2 (ID NUMBER);
CREATE TABLE T_RECORD
(ID NUMBER);
time used: 11.990(ms) clock tick:19871840.
SQL>INSERT INTO T_RECORD
2 SELECT ROWNUM FROM SYSTEM.SYSDBA.DUAL
3 CONNECT BY ROWNUM < 1000000;
INSERT INTO T_RECORD
SELECT ROWNUM FROM SYSTEM.SYSDBA.DUAL
CONNECT BY ROWNUM < 1000000;
1000000 rows affected
time used: 75496.092(ms) clock tick:1644487636.
SQL>COMMIT;
COMMIT;
time used: 41.571(ms) clock tick:69449680.
SQL>SELECT COUNT(*) FROM SYSTEM.SYSDBA.V$LOCK;
SELECT COUNT(*) FROM SYSTEM.SYSDBA.V$LOCK;
1 1
1 rows got
time used: 0.395(ms) clock tick:651870.
SQL>UPDATE T_RECORD
2 SET ID = ID + 1;
UPDATE T_RECORD
SET ID = ID + 1;
1000000 rows affected
time used: 15544.108(ms) clock tick:186236054.
SQL>SELECT COUNT(*) FROM SYSTEM.SYSDBA.V$LOCK;
SELECT COUNT(*) FROM SYSTEM.SYSDBA.V$LOCK;
1 803
1 rows got
time used: 2.850(ms) clock tick:4754460.
SQL>SELECT LTYPE, LMODE, COUNT(*)
2 FROM SYSTEM.SYSDBA.V$LOCK
3 WHERE LTYPE != 'DICT'
4 GROUP BY LTYPE, LMODE;
SELECT LTYPE, LMODE, COUNT(*)
FROM SYSTEM.SYSDBA.V$LOCK
WHERE LTYPE != 'DICT'
GROUP BY LTYPE, LMODE;
LTYPE LMODE
1 TABLE IX 1
2 TABLE X 1
3 ROW X 800
3 rows got
time used: 3.446(ms) clock tick:5750600.
可以看到,在獲取了800個行級鎖後,資料庫自動將行級鎖升級為表級鎖。
在Oracle中鎖並不是一種昂貴的資源,因此不會出現鎖升級的情況。在達夢中,由於鎖是一種資源,因此為了避免大量的持有鎖,達夢採用了升級鎖的方法,雖然這會在一定情況下影響併發性,但是這是資源權衡的結果,SQLSERVER等資料庫也是這樣實現的。
不過達夢資料庫中,似乎讀並不阻塞寫,嘗試建立一個100W記錄的表,在一個會話先開始一個SELECT * FROM TABLE的語法,然後在另一個會話執行一個UPDATE全表的語句。由於SELECT需要將結果列印到螢幕,因此SELECT語句在UPDATE之後完成,這顯然說明SELECT並沒有阻塞UPDATE。而且可以肯定SELECT是發生在UPDATE之前,因為再次執行同樣的SELECT語句就會被UPDATE更新操作鎖住。
總的來說,達夢資料庫的鎖機制雖然不能和Oracle的比,但是也已經不錯了,可以實現行級鎖定,而且讀並不阻塞寫。而且達夢資料庫還能實現多版本一致性讀,不過要實現這種方式需要修改初始化引數配置中的預設設定,而且可能會對效能造成一定的影響。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-669352/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 達夢6.0試用之PLSQL篇SQL
- 達夢6.0試用之SQL篇SQL
- 達夢6.0試用之資料字典
- 達夢6.0試用之架構篇架構
- 達夢6.0試用之測試環境搭建
- 達夢6.0試用之資料庫物件資料庫物件
- 達夢6.0試用之資料型別資料型別
- PostgreSQL 併發控制機制(2):表級鎖和行級鎖SQL
- 併發程式設計的鎖機制:synchronized和lock程式設計synchronized
- Java併發程式設計(05):悲觀鎖和樂觀鎖機制Java程式設計
- 達夢6.0 for Windows安裝Windows
- 圖解Janusgraph系列-併發安全:鎖機制(本地鎖+分散式鎖)分析圖解分散式
- 訂單系統中併發問題和鎖機制的探討
- Java併發程式設計之鎖機制之(ReentrantLock)重入鎖Java程式設計ReentrantLock
- Java併發程式設計之鎖機制之AQSJava程式設計AQS
- Java 併發機制底層實現 —— volatile 原理、synchronize 鎖優化機制Java優化
- Java併發程式設計之鎖機制之Lock介面Java程式設計
- Java併發程式設計之鎖機制之LockSupport工具Java程式設計
- MySQL優化系列(八)--鎖機制超詳細解析(鎖分類、事務併發、引擎併發控制)MySql優化
- MySQL的事務機制和鎖(InnoDB引擎、MVCC多版本併發控制技術)MySqlMVC
- HBase 事務和併發控制機制原理
- Java併發程式設計之鎖機制之Condition介面Java程式設計
- Java併發程式設計之鎖機制之引導篇Java程式設計
- YaoBase基於MVCC的無鎖化樂觀併發機制MVC
- DB2預設的事務及併發鎖機制DB2
- Java併發程式設計之鎖機制之ReentrantReadWriteLock(讀寫鎖)Java程式設計
- Mysql的鎖機制與PHP檔案鎖處理高併發簡單思路MySqlPHP
- 【Java基礎】執行緒和併發機制Java執行緒
- 【Storm篇】--Storm併發機制ORM
- Java 8 併發:同步和鎖Java
- 和朱曄一起復習Java併發(三):鎖(含鎖效能測試)Java
- redis(10)事務和鎖機制Redis
- 架構設計 | 高併發流量削峰,共享資源加鎖機制架構
- Java併發之等待/通知機制Java
- Java併發控制機制詳解Java
- PHP 鎖機制PHP
- SQLite鎖機制SQLite
- Mysql鎖機制MySql