SQL Server’da Satırın Fiziksel Konumu (%%physloc%%)

Oracle’da satırların disk üzerindeki fiziksel konumunu döndüren ROWID komutu bulunmaktadır. Bu tür komutlar değerleri veritabanında tutulmadığı o anda hesaplandığı için sahte komut(pseudo-column) olarak tanımlanır. Birçok veritabanı yönetim sisteminde her satır için arka tarafta bir ID bilgisi tutulmaktadır. Fakat bu değerleri geliştirilerin okuması zor olabiliyor. SQL Server 2005’te aynı amaç için %%lockres%% komutu eklendi. Bu komutun SQL Server 2008’deki karşılığı %%physloc%% komutudur. SQL Server 2005 tarafında aşağıdaki gibi kullanıyoruz.

SELECT *,%%lockres%% FROM OGRENCI


Şekilde görüldüğü gibi SQL Server her satırı tekil bir RID değeriyle ayırmış durumda. Bu adres bilgisi verinin bulunduğu Data File:Page:Row Slot değerini içermektedir.
Kaynak kilitlemesi doğrudan fiziksel alan üzerinden olmaktadır. Bunu aşağıdaki gibi net bir şekilde görebiliriz. OGRENCI tablosu üzerinde 2 INSERT ve 1 UPDATE işlemi gerçekleştireceğiz. Transaction açıkken tablonun lock durumuna bakacağız. Aktif kilitlemeleri görmek için sys.dm_tran_locks isimli DMV kullanılabilir.

BEGIN TRAN

UPDATE OGRENCI SET AdSoyad='Serdar' WHERE AdSoyad='Ömer'
INSERT OGRENCI VALUES('Berk')
INSERT OGRENCI VALUES('Berk')

SELECT
    o.NAME obj_name, l.resource_description, l.request_mode, l.request_status, request_owner_type, request_session_id,
    ogr.*
FROM sys.dm_tran_locks l
    INNER JOIN sys.dm_exec_sessions s on l.request_session_id = s.session_id
    INNER JOIN sys.partitions p on l.resource_associated_entity_id = p.hobt_id
    INNER JOIN sys.objects o ON o.object_id = p.object_id
    CROSS APPLY (SELECT *
                         FROM OGRENCI (NOLOCK)
                         WHERE %%lockres%% = l.resource_description) ogr
ROLLBACK


Şekilde de görüldüğü gibi SQL Server ilgili satırlar üzerinde exclusive lock (X) türünde bir kilit yerleştirmiş.
SQL Server 2008’de aynı komut çalışmakla birlikte %%physloc%% isminde yeni komut eklendi.

SELECT *,%%physloc%% FROM OGRENCI


SQL Server 2008’deki bu komut hexadecimal türünde değer döndürmektedir. Bu değerin kolayca okunabilmesi için sys.fn_PhysLocFormatter fonksiyonu kullanılır.

SELECT %%physloc%% AdresHex,
sys.fn_PhysLocFormatter(%%physloc%%) Adres,
* FROM OGRENCI


“Zeynep” kaydı 1 nolu data file içerisindeki 79 nolu data page içerisindeki 2 nolu slotta bulunmaktadır.
Daha önceki makalelerimde anlattığım gibi bir data page yapısını görmek için DBCC PAGE komutu kullanılabilir. Bu komut aşağıdaki parametreleri alır.

  • Database ID veya Database Adı
  • Data File Numarası
  • Data Page Numarası
  • Sayfa içeriğinin detay seviyesi (ne kadar detay yazdırılacak)
  • 0 = Başlık
  • 1 = Başlık ve Satırlar için hex açıklama
  • 2 = Başlık ve Page seviyesinde detay
  • 3 = Başlık ve Satırların detaylı içeriği

DBCC PAGE ({dbid|dbname}, pagenum [,print option] [,cache] [,logical])

DBCC TRACEON(3604)
DBCC PAGE (Deneme, 1, 79, 3)
DBCC TRACEOFF(3604)

DBCC execution completed. If DBCC printed error messages, contact your system administrator.
PAGE: (1:79)
BUFFER:
BUF @0x00000007A5FD1140
bpage = 0x00000007A582E000 bhash = 0x0000000000000000 bpageno = (1:79)
bdbid = 8 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 22529 bstat = 0xc0010b
blog = 0xca2159bb bnext = 0x0000000000000000
PAGE HEADER:
Page @0x00000007A582E000
m_pageId = (1:79) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8000
m_objId (AllocUnitId.idObj) = 65 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594042187776
Metadata: PartitionId = 72057594041204736 Metadata: IndexId = 0
Metadata: ObjectId = 165575628 m_prevPage = (0:0) m_nextPage = (0:0)
pminlen = 4 m_slotCnt = 5 m_freeCnt = 8005
m_freeData = 177 m_reservedCnt = 0 m_lsn = (288:608:2)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = 0
Allocation Status
GAM (1:2) = ALLOCATED SGAM (1:3) = ALLOCATED
PFS (1:1) = 0x61 MIXED_EXT ALLOCATED 50_PCT_FULL DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED
Slot 0 Offset 0x60 Length 16
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 16
Memory Dump @0x000000004804A060
0000000000000000: 30000400 01000001 00100041 686d6574 ?0..........Ahmet
Slot 0 Column 1 Offset 0xb Length 5 Length (physical) 5
AdSoyad = Ahmet
Slot 1 Offset 0x70 Length 16
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 16
Memory Dump @0x000000004804A070
0000000000000000: 30000400 01000001 00100041 686d6574 ?0..........Ahmet
Slot 1 Column 1 Offset 0xb Length 5 Length (physical) 5
AdSoyad = Ahmet
Slot 2 Offset 0x80 Length 17
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 17
Memory Dump @0x000000004804A080
0000000000000000: 30000400 01000001 0011005a 65796e65 ?0..........Zeyne
0000000000000010: 70???????????????????????????????????p
Slot 2 Column 1 Offset 0xb Length 6 Length (physical) 6
AdSoyad = Zeynep
Slot 3 Offset 0x91 Length 15
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 15
Memory Dump @0x000000004804A091
0000000000000000: 30000400 01000001 000f00d6 6d6572????0..........Ömer
Slot 3 Column 1 Offset 0xb Length 4 Length (physical) 4
AdSoyad = Ömer
Slot 4 Offset 0xa0 Length 17
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 17
Memory Dump @0x000000004804A0A0
0000000000000000: 30000400 01000001 0011004d 65686d65 ?0..........Mehme
0000000000000010: 74???????????????????????????????????t
Slot 4 Column 1 Offset 0xb Length 6 Length (physical) 6
AdSoyad = Mehmet
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

Bu komutun gerçek hayatta kullanıldığı alanlardan biri üzerinde herhangi bir unique key olmayan tablolardaki çift kayıtların silinmesidir. Bu kayıtları silmek için kayıt değerlerin göre gruplama yapıp en düşük veya en yüksek fiziksel konuma sahip olanlar hariç diğerleri silinir. OGRENCI tablosunda 2 tane “Ahmet” değeri vardı bunları tek düşürmek için aşağıdaki kod yeterli olacaktır.

DELETE OGRENCI
WHERE OGRENCI.%%physloc%%
NOT IN (SELECT MIN(%%physloc%%)
        FROM OGRENCI
        GROUP BY AdSoyad);

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Time limit is exhausted. Please reload CAPTCHA.