2016年11月20日 星期日

SQL SERVER的 RowID


用過Oracle的人,他在使用SQL SERVER的時候,常會有個抱怨:「Oracle有rowid,為什麼SQL SERVER沒有」。雖然rowid一般是不會用到,但當要刪除重覆資料而只留下一筆的時候,rowid則是簡單好用的。
當然,SQL SERVER也有自己T-SQL語法,不用rowid也可以讓我們刪除重覆資料而僅保留一筆。

當我們查看執行計畫時,經常會看到一個「RID查閱」,它的意思是索引中沒有完全涵蓋所需要的欄位,所以需要從索引中經由RID指向至來源TABLE(Heap)中的某筆紀錄,以取得所需欄位資料。從這點來看,SQL SERVER是有類似於Oracle的rowid的。













其實SQL SERVER的DB中,每個TABLE的每筆資料,都有一個唯一的識別碼(Row Identifier --RID),執行計畫的「RID查閱」及「交易紀錄的Recovery」都會用到它。
RID是由 fileID:pageID:slotID所組成,在每個DB中它是個唯一值。如果你細看它的組成份子,可以看出其實RID就是指資料的「實體存放位址」。

我們可以利用SQL SERVER的虚擬欄位「%%lockres%%」(應該是SQL 2008含以上才有),來查看或取得每筆資料的RID:































以C1=10這筆資料為例,RID為「1:174917:0」,代表這筆資料的實體存放位址在
這個DB的第1個檔案(NTUB.mdf),第174917頁,第0個slot(slot從0起算)。

我們可以再用dbcc page確認一下,果然第174917頁的slot 0就是C1=10的這筆資料。


















虚擬欄位 %%lockres%% 取得的資訊,嚴格的說,是將RID Format過後呈現的格式。真正的RID二進位值可以用「%%physloc%%」來取得,從某個角度來說%%lockres%%可以說是%%physloc%%的十進位格式。

它除了可以用來讓我們知道它的實體存放位置外,也可以用來當查詢的條件














不過,用它當where條件,是沒辦法走index的,它只能是Table Scan。

RID它對於有心去探究SQL SERVER內部的人,是方便的。
對於一般使用者來說,其實也有一個用處,就是可以用它來刪除重覆的資料僅保留一筆。
舉例來說,有個table,當初建的時後,沒有加PK或unique index,現在要對欄位C1加上unique key,但因資料已經重覆,加不上去。此時我們需要將重覆的資料刪除但保留其中一筆。


















以上圖的例子,C1其實應該是唯一值,但目前TABLE已存在許多重覆資料。

我們可以利用RID,用簡單的語法將重覆資料刪除,只保留一筆













 再執行查詢,檢查已無重覆資料

































PS:
刪除重覆資料僅保留一筆也有正規的T-SQL語法可以做到,上面的例子只是便於說明RID。日常的操作上,應儘量使用正規的T-SQL。

平常我們會使用sp_lock來觀察系統的鎖定情況























請看上圖的recsource欄位,是不是很眼熟呢?沒錯,它指的就是 %%lockres%%。我想這也是 %%lockres%%(Lock Resource) 命名的由來吧!
或許你已經想到,可以用sp_lock結果集中的resource,透過 %%lockres%% 去查詢鎖定的實際資料。

RID是SQL SERVER內部用於識別資料實體存放位址的一個指標,對於一般工作上的需求,請儘量使用正規的T-SQL去完成。

如果是Clustered Table,它的%%lockres%%,顯示出來的是key的hash值..

沒有留言:

張貼留言