達夢6.0試用之併發和鎖機制

yangtingkun發表於2010-07-24

前幾天ITPUB的熊建國主編和我聯絡,希望我能參加國產資料庫達夢的適用活動,並寫幾篇使用感受。本來最近手工的事情比較多,本打算推辭的,不過熊主編再三邀請,而且強調並非是槍手文,只要寫出真實使用感受即可。既然如此,我就本著支援國產資料庫的原則,寫幾篇試用感受。

由於本人唯一熟悉的資料庫就是Oracle,因此所有的對比都是與Oracle資料庫進行對比,在這個過程中,將盡可能避免將對Oracle資料庫的喜愛之情帶進來,爭取站在一個比較公正的位置上來進行評價。

這一篇簡單介紹一下達夢資料庫的鎖機制和併發控制。

 

 

達夢的鎖機制和Oracle的並不相同,Oracle和其他資料庫相比最突出的特點就是鎖的實現,一方面是行級鎖,而且鎖並非資源,只是佔用極少的儲存空間;另一方面Oracle沒有讀鎖,讀不阻塞寫,寫也不會阻塞讀。即使DB2SQLSERVER等資料庫也無法做到這一點,顯然不能要求達夢達到這樣的標準。

看看達夢的鎖實現:

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是關閉的。

在另外的會話中更新ID2的記錄,這時會話被阻塞:

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.

可以看到,事務ID1246並不是由於要獲取獨佔鎖而被阻塞,而是在查詢到被修改的記錄時被鎖定。

也就是說,在達夢資料庫中,寫是阻塞讀的。

如果要避免這種情況的產生,可以建立ID列上的索引。

首先,會話1提交是否鎖:

SQL>COMMIT;
COMMIT;

time used: 50.458(ms) clock tick:84356900.

這時會話2UPDATE操作成功:


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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章