Concurrent transaction locking

לאור כמה שיחות עם אנשים אני מתכוון לסקור כאן בקצרה את עניין נעילות ה- DB.
אני לא מדבר על נעילות יזומות ( מפורשות ) כאשר ה – CLIENT מבקש נעילה על אזורים מסוימים ב- DATABASE ( כל VENDOR  מאפשר SYNTAX שונה וכן נעילות שונות ).
אלא אני מדבר על נעילות שה – DATABASE  עושה בעצמו על מנת לשמור על עקביות של נתונים, על מנת לנהל נתונים...

בואו ניקח את ה – scenario  הבא:
Client B (Isolation level = read committed) מנסה לקרוא נתונים מטבלה בזמן ש-  client A נמצא בתוך טרנזקציה ועושה שינויים על הטבלה הזאת. האם client B  ינעל ויחכה עד ש- client A  יסיים את הטרנזקציה?

לאחרונה שמעתי מיותר מדי אנשים את התשובה – נעילה, כלומר client B ינעל ולא יוכל לבצע את השאילתא עד ש- clinet B לא יגמור את הטרנזקציה.

ובכן – התשובה היא מאכזבת – תלוי.
במה זה תלוי – זה תלוי במימוש הטרנזקציות הפנימי של אותו db vendor.
במידה ואותו vendor   לא מנהל גרסאות מקבילות של אותה רשומה , אז כדי להבטיח read committed  הוא יצטרך לנעול את הטבלה או האזור לקריאה עד שלא יתבצע commit  על הנתונים.

ניהול של גרסאות מקבילות של אותה רשומה על מנת למנוע נעילה של הרשומה לקריאה במקביל לשינוי הוא משהו מאוד בסיסי ביכולות שאנחנו מצפים מה – database  שלנו.
אותי בתור client  לא צריך לעניין שיש clients  אחרים שמשנים את הרשומה וטרם ביצעו commit. ( במידה ואני ב- isolation read committed ).

ל – MSSQL לקח זמן להבין את זה והם הצטרפו די מאוחר לתמיכה בגרסאות שונות לאותה רשומה וכיום הם תומכים ב –row version.
התמיכה הזאת נעשית דרך הגדרת הDB בתור SNAPSHOT.והתמיכה החלה החל מ-2005.
SQL Server 2005 introduces a new snapshot isolation level to enhance concurrency for OLTP applications. In earlier versions of SQL Server, concurrency was based solely on locking, which caused blocking and deadlocking problems for some applications. Snapshot isolation, by contrast, depends on enhancements to row versioning and is intended to improve performance by avoiding reader-writer blocking scenarios.

בואו נדגים את המקרה שתארנו על שני DB שונים- mysql, mssql (2005)

יצירת הטבלה :
MySql:
create table TestLock)
       IK INT auto_increment NOT NULL,
       MyName NVARCHAR(200) not null,
       primary key (IK)
)type=innodb;
insert into TestLock(MyName) values (1);
insert into TestLock(MyName) values (2);
insert into TestLock(MyName) values (3);
insert into TestLock(MyName) values (4);

Client A:
00:
Begin;
insert into TestLock(MyName) values (5);

//Not committed!!!

Client b:
01:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Begin;
Select * from TestLock;

// No problem – we get committed data – no lock

Mssql :
createtable TestLock(
       IK INT IDENTITY NOT NULL,
       MyName NVARCHAR(200) not null,
       primary key (IK)
    )

insert into TestLock(MyName) values (1);
insert into TestLock(MyName) values (2);
insert into TestLock(MyName) values (3);
insert into TestLock(MyName) values (4);

we will distinguish between two db types – snapshot on and off.

Snapshot off:
Client A:
00:
set transaction isolation level  read committed  set implicit_transactions off 
go
set implicit_transactions on 
go
insert into TestLock(MyName) values (5);

//Not committed!!!

Client b:
01:
set transaction isolation level  read committed  set implicit_transactions off 
go
set implicit_transactions on 
go
Select * from TestLock;
//Lock – because mssql lock the last rows of the table since it need to add data to them.
Mssql doesn't lock the table. It lock the area that it need (it depend on the block size … ), so if we limit the select query range to range that not include the lock area the read will not be blocked.
For example:
Select * from testlock where IK < 4
//No lock !!!!
If we turn on the snapshot (in the db and in the transaction committed_snapshot) – No lock needed, so select all will work even there is a parallel uncommitted transaction that insert data to the table.


אין תגובות:

הוסף רשומת תגובה