הבלוג של גרי רשף

02/06/2010

Read Committed Snapshot, Allow Snapshot Isolation

Filed under: Uncategorized — תגיות: — גרי רשף @ 08:32

Read Committed Snapshot

נניח שפתחנו טרנזקציה ועדכנו רשומה בטבלה מבלי לבצע Commit או Rollback לטרנזקציה.
מי שינסה לעדכן אותה רשומה- יתקע וימתין עד שהרשומה תשתחרר.
מי שישלוף את הרשומה בעזרת (With (NoLock או בעזרת (With (ReadUnCommitted יקבל את הרשומה המעודכנת, תוך שהוא מסתכן בכך שיתבצע Rollback והמידע שקיבל יתגלה כשגוי.
מה יקרה אם ננסה לשלוף את הרשומה בעזרת (With (ReadCommitted או ללא כל חיווי? האם נקבל את הרשומה לפני תחילת הטרנזקציה הפתוחה, או שנצטרך להמתין עד שהטרנזקציה תיסגר?
התשובה לכך תלויה בהגדרת Read Commited Snapshot של הדטבייס שניתן לברר אותו כך:

Select    name,

        is_read_committed_snapshot_on

From    sys.databases 

Where    database_id=DB_ID();

ברירת המחדל היא Off (כלומר- 0) ואז המערכת תמתין לסיום הטרנזקציה,

אך ניתן לשנות את ההגדרה ל-On (כלומר-1) או ל-Off (כלומר- 0):

Alter Database MyDB Set Read_Committed_Snapshot Off;

Go

ואז המערכת תציג את הערכים לפני פתיחת הטרנזקציה.

דוגמה- ניצור דטבייס במצב Off, ניצור טבלה, נכניס פנימה ערך, נפתח טרנזקציה ונשנה אותו:

If DB_ID('MyDB') Is Not Null Drop Database MyDB;

Go

Create Database MyDB;

Go

 

If Object_ID('T_Try001') Is Not Null Drop Table T_Try001;

Go

Create Table T_Try001(I Int);

Go

Insert Into T_Try001 Select 1;

Go

 

Begin Tran

Update T_Try001 Set I=I+2;

Go

נפתח Query חדש ב-SSMS שיפנה לדטבייס MyDB,

נריץ בו אחת משתי הפקודות הבאות ונקבל 3 (הערך לאחר השינוי בטרנזקציה הפתוחה):

Select * From T_Try001 With (NoLock);

 

Select * From T_Try001 With (ReadUnCommitted);

לעומת זאת, אם נריץ בו אחת משתי הפקודות הבאות, היא תתקע ותמתין לסיום הטרנזקציה:

Select * From T_Try001 With (ReadCommitted);

 

Select * From T_Try001;

רק אם נחזור למסך הראשון בו נפתחה הטרנזקציה ונסיים אותה בהצלחה על ידי פקודת Commit – הפקודות יסיימו ויחזירו את הערך 3.

נחזור כעת על כל התרגיל עם Read Committed Snapshot במצב On.

נשנה קודם כל את ההגדרה של הדטבייס:

Alter Database MyDB Set Read_Committed_Snapshot On

Go

(אם הפקודה לשינוי הגדרת הדטבייס נתקעת- נעבור למסך השני, ונעבור בו לדטבייס אחר כדי לשחרר אותו לפקודה הנ"ל (למשל- Use tempdb), וכשתסתיים בהצלחה נחזור (Use MyDB))

כעת פקודת Select * From T_Try001 לא תיתקע אלא תסתיים בהצלחה, אבל ללא השינויים שבטרנזקציה הפתוחה.

לסיכום- אם אחד המשתמשים פותח טרנזקציה ומעדכן נתונים – ניתן בכל רגע לגשת לכל אחת משתי הגרסאות: הגרסה לפני פתיחת הטרנזקציה, והגרסה הכוללת את כל השינויים שנעשו בטרנזקציה.

מכיוון שמדובר בשינוי של נתונים- הרשומות נעולות לשינויים עבור כל המשתמשים האחרים על ידי זה שפתח את הטרנזקציה – כל עוד היא פתוחה.

Read Committed Snapshot קובע האם ברירת המחדל תהיה לפנות לנתונים לפני פתיחת הטרנזקציה (On) או להיתקע ולהמתין לסיום הטרנזקציה ולנתונים המעודכנים (Off).

Allow Snapshot Isolation

בניגוד לפקודת Read Committed Snapshot שהיא פקודה "מגיבה" למצב בו אחד המשתמשים נועל רשומות וכתוצאה מכך יש אי בהירות לגבי נתוני ה-Commited,

פקודת Allow Snapshot Isolation היא פקודה "יוזמת" של המשתמש שמעוניין להגן על עצמו מפני שינויים של משתמשים אחרים, ו"להקפיא" לעצמו מצב נתון של הדטבייס שאותו יוכל לתחקר ולא יגלה תוך כדי כך שהנתונים משתנים. הוא אינו נועל דבר לאיש זולת עצמו: האחרים יכולים להמשיך ולשנות את הנתונים, ואילו עבורו הם לא ישתנו.

Snapshot Isolation Level או Row Versioning: המערכת שומרת עבורו ב-tempdb את הגרסה הקודמת של הרשומות שהשתנו (מבחינה פיזית), אם כי לוגית – הם עדיין בטבלה מבחינתו.

נשנה את הגדרת בסיס הנתונים, ניצור שתי טבלאות ונכניס לתוכן רשומה לדוגמה:

Alter Database MyDB Set Allow_Snapshot_Isolation On;

Go

 

If Object_ID('T_Try001') Is Not Null Drop Table T_Try001;

Go

Create Table T_Try001(I Int);

Go

Insert Into T_Try001 Select 1;

Go

Select    * From    T_Try001;

 

If Object_ID('T_Try002') Is Not Null Drop Table T_Try002;

Go

Create Table T_Try002(I Int);

Go

Insert Into T_Try002 Select 1;

Go

Select    * From    T_Try002;

נפתח כעת Query חדש ב-SSMS,

נעבוד במצב של Snapshot Isolation (קודם איפשרנו את השימוש וכעת בחרנו להשתמש בו),

נפתח טרנזקציה

ונשלוף נתונים מ-T_Try001:

Set Transaction Isolation Level Snapshot;

Begin Tran

    Select * From T_Try001;

השליפה מציגה את הערך 1 כצפוי.

נחזור ל-Query הראשי ונשנה את הערכים בשתי הטבלאות:

Update T_Try001 Set I=2;

Update T_Try002 Set I=2;

Go

נחזור ל-Query השני ונשלוף את הנתונים משתי הטבלאות:

Select * From T_Try001;

Select * From T_Try002;

שימו לב שבשתיהן הערך הוא 1 (כלומר- גם בזו ששלפנו ממנה נתונים קודם וגם בזו שלא שלפנו ממנה). הווה אומר- המערכת שומרת לנו גרסה של כל בסיס הנתונים ולא רק של טבלאות מסויימות (למי שרגיל שמה שננעל לאחר פקודת Begin Tran זו הטבלה בה התבצע שינוי).

נפתח כעת Query נוסף (שלישי) ונשלוף בו נתונים משתי הטבלאות:

Set Transaction Isolation Level Snapshot;

Begin Tran

    Select * From T_Try001;

    Select * From T_Try002;

בשתיהן מופיעים הערכים המעודכנים – 2.

נחזור ל-Query הראשי, נעדכן שוב את הטבלאות, וניצור טבלה נוספת:

Update T_Try001 Set I=3;

Update T_Try002 Set I=3;

Go

 

If Object_ID('T_Try003') Is Not Null Drop Table T_Try003;

Go

Create Table T_Try003(I Int);

Go

Insert Into T_Try003 Select 3;

Go

Select    * From    T_Try003;

נעבור ל-Query השני ואחר כך לשלישי, ובשניהם נבדוק את הערכים בטבלאות, ואת תכולת טבלת המערכת sys.objects (האובייקטים במערכת):

Select * From T_Try001;

Select * From T_Try002;

Select * From sys.objects Where name Like 'T_Try00%'

1. יש כרגע שלוש גרסאות שונות של הטבלאות, ובכל אחד מה-Queries נראה גרסה אחרת של נתונים משתי הטבלאות הראשונות.

2. לטבלאות המערכת לא נשמרת גרסה, וניתן לראות בה שנוצרה טבלה חדשה T_Try003.

3. אם ננסה לשלוף נתונים מתוך T_Try003 ב-Query השני או השלישי – נקבל הודעת שגיאה, הטרנזקציה תיסגר, ונתוני הגרסה ילכו לאיבוד. זה גם מה שיקרה אם נשנה את מבנה אחת הטבלאות.

4. פניה לטבלה בדטבייס אחר בו אין Snapshot Isolation Level עלולה להיות בעייתית, וכדאי לציין במפורש (With (ReadCommitted או (With (ReadUnCommitted.

5. ברירת המחדל ל-Snapshot Isolation Level היא Off, וניתן לברר מה ההגדרה הנוכחית כך:

Select    name,

        snapshot_isolation_state

From    sys.databases 

Where    database_id=DB_ID();

מודעות פרסומת

תגובה אחת »

  1. האם ניתן להפעיל RCSI ברמת שאילתא? (בדומה ל-with nolock)?

    תגובה של איתי — 20/02/2013 @ 10:25


RSS feed for comments on this post. TrackBack URI

כתיבת תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s

יצירה של אתר חינמי או בלוג ב־WordPress.com.

%d בלוגרים אהבו את זה: