Menu

SQLite ROWID: Gizli Anahtar ve WITHOUT ROWID Kullanımı

SQLite'ta ROWID gerçekte nedir, INTEGER PRIMARY KEY tanımı onu nasıl sizin sütununuz haline getirir ve WITHOUT ROWID tabloları neden vardır?

Bu sayfada çalıştırılabilir editörler var — düzenle, çalıştır ve sonucu anında gör.

Her Tablonun Gizli Bir Sütunu Vardır

SQLite'ta sıradan bir tablo oluşturduğunuzda, aslında siz tanımlamadığınız halde tabloya eklenmiş olan bir sütun zaten vardır:

O rowid sütunu gerçekten var. SQLite, sıradan her tablonun her satırına, siz istemeseniz bile bir tane atar. 64 bit işaretli bir tam sayıdır, tablo içinde benzersizdir ve SQLite'ın B-tree depolamasında satırları bulmak için kullandığı asıl anahtardır. Tablonun omurgası gibi düşünün — geri kalan her şeyi düzenli tutan indeks.

Genellikle gözünüze çarpmaz çünkü SELECT * bu sütunu getirmez. Görmek için adıyla istemeniz gerekir.

ROWID'in Üç Takma Adı Vardır

rowid, başka veritabanları için yazılmış SQL'lerde sıkça karşımıza çıktığından, SQLite aynı sütun için üç farklı isim kabul eder:

rowid, oid ve _rowid_ aslında aynı gizli sütunu işaret eder. Eğer bu isimlerden biriyle gerçek bir sütun tanımlamışsanız, senin sütunun öncelik kazanır ve takma ad devre dışı kalır — ama olay bu kadar. Günlük kullanımda sadece rowid yazmanız yeterli.

Sihirli İfade: INTEGER PRIMARY KEY

Başka veritabanlarından gelenleri en çok şaşırtan kısım burası. Bir sütunu tam olarak INTEGER PRIMARY KEY şeklinde tanımlarsanız, o sütun ayrı olarak saklanmaz — doğrudan rowid'in kendisi olur:

rowid ile id aslında aynı sütunun iki farklı adı. id belirtmeden yapılan INSERT işlemlerinde SQLite otomatik olarak bir tam sayı atar (genelde mevcut en büyük rowid + 1). İşte tam da bu yüzden INTEGER PRIMARY KEY, SQLite'ta bir tabloya otomatik artan anahtar tanımlamanın en verimli yoludur — fazladan sütun yok, fazladan indeks yok, doğrudan rowid'in kendisi kullanılır.

Yazımın da harfi harfine doğru olması şart. INT PRIMARY KEY ile INTEGER PRIMARY KEY aynı şey değildir — burada INT ve INTEGER farklı davranır:

a tablosunda id ve rowid aynı değere sahip. Ama b tablosunda id sıradan bir sütun, rowid ise ayrı duran o gizli integer. Daha kötüsü, b.id insert sırasında otomatik dolmuyor — siz değer atayana kadar NULL kalıyor. Alias davranışını istiyorsanız tam haliyle INTEGER PRIMARY KEY yazmaya devam edin.

Insert Sonrası ROWID'i Almak

Bir INSERT işleminin ardından, çoğu zaman yeni atanan rowid'i öğrenmek istersiniz — genellikle bir alt kaydı bu satıra bağlamak için. SQLite bunun için last_insert_rowid() fonksiyonunu sunuyor:

Bu fonksiyon, mevcut bağlantıdaki en son başarılı insert işleminin rowid değerini döndürür. Çoğu veritabanı sürücüsü aynı değeri cursor.lastrowid ya da benzeri bir özellik üzerinden sunar. İlerleyen bölümlerde göreceğimiz RETURNING ifadesi de bu değeri doğrudan insert işleminin bir parçası olarak geri almanın başka bir yoludur.

ROWID Değerleri Kalıcı Değildir

Bir satırın rowid'i, satır var olduğu sürece sabit kalır; ancak ömür boyu geçerli bir kimlik değildir. VACUUM komutu rowid'leri yeniden numaralandırabilir; ayrıca bir satırı sildiğinizde o numara daha sonraki bir insert tarafından yeniden kullanılabilir:

Yeni satırın eski rowid'yi yeniden kullanıp kullanmayacağı sürüme ve duruma göre değişir — burada asıl mesele şu: rowid'nin sonsuza kadar benzersiz kalacağına güvenemezsiniz. Silme, VACUUM ve dışa aktarma işlemlerinden sonra bile ayakta kalan bir tanımlayıcıya ihtiyacınız varsa, kendi INTEGER PRIMARY KEY sütununuzu tanımlayın (bu değeri o satıra sabitler); özellikle hiçbir zaman tekrar kullanılmayan ve sürekli artan değerler istiyorsanız AUTOINCREMENT anahtar sözcüğünü de değerlendirin.

WITHOUT ROWID Tabloları

Bazen rowid istemediğiniz fazladan bir yüke dönüşür — bu özellikle gerçek anahtarınız tam sayı olmadığında geçerlidir. Mesela isme göre anahtarlanmış bir şehirler tablosu sonunda iki yapıyla çalışır: rowid B-ağacı ve birincil anahtarı zorunlu kılmak için name üzerinde ayrı bir indeks. WITHOUT ROWID bu ikisini tek bir yapıda birleştirir:

Artık name doğrudan depolama anahtarı haline geldi. name üzerinden yapılan aramalar bir dolaylılık katmanını atlıyor, üstelik tablo da daha küçük. Bunun karşılığında bazı şeylerden vazgeçiyorsunuz:

  • Artık rowid, oid ya da _rowid_ yok — bu sütunlar hiç var olmuyor.
  • Bu tabloya yapılan eklemelerde last_insert_rowid() güncellenmiyor.
  • Incremental BLOB I/O ve bazı replikasyon özellikleri kullanılamıyor.
  • Tablonun mutlaka bir PRIMARY KEY tanımı olması gerekiyor.

WITHOUT ROWID her duruma uyan bir varsayılan değil, ölçülü bir optimizasyondur. Birincil anahtarınız integer değilse ve tablo büyük ya da yoğun yazma alıyorsa devreye sokun. Sıradan integer anahtarlı tablolarda klasik rowid düzeni zaten en iyi seçenek.

Zihinsel Model

En özüne indirgersek:

  • Her sıradan SQLite tablosunda rowid adında, gizli bir 64-bit integer anahtar bulunur.
  • INTEGER PRIMARY KEY (tam olarak bu yazımla) sütununuzu bu anahtarın takma adına dönüştürür.
  • Yeni atanan değeri okumak için last_insert_rowid() kullanın.
  • Silmeden sonra rowid değerleri yeniden kullanılabilir, VACUUM ise bunları yeniden numaralandırabilir.
  • WITHOUT ROWID tabloları bu gizli anahtarı bırakıp doğrudan sizin tanımladığınız birincil anahtarı kullanır — integer olmayan anahtarlar için faydalıdır, ama bazı özelliklerden vazgeçirir.

Çoğu zaman rowid'i hiç düşünmezsiniz bile. id INTEGER PRIMARY KEY yazar, numaralandırmayı SQLite'a bırakır ve yolunuza devam edersiniz. Detaylar; depolamayı optimize ederken, eski şemaları okurken veya INT PRIMARY KEY ile INTEGER PRIMARY KEY arasındaki farkı merak ettiğinizde önem kazanır.

Sırada: NOT NULL ve DEFAULT

Satırın kimliği oturduğuna göre, sıradaki katman geri kalan sütunların makul değerler taşıdığından emin olmak. Bu işin büyük kısmını NOT NULL ve DEFAULT halleder — bir sonraki konumuz da bu.

Sıkça Sorulan Sorular

SQLite'ta ROWID nedir?

SQLite'taki her sıradan tabloda, her satırı benzersiz şekilde tanımlayan, 64-bit işaretli tam sayı tipinde gizli bir rowid sütunu bulunur. SQLite bunu B-tree depolamasında gerçek anahtar olarak dahili kullanır. Siz tanımlamamış olsanız bile SELECT rowid, * FROM t ile rahatça okuyabilirsiniz.

ROWID ile PRIMARY KEY arasındaki fark nedir?

rowid her zaman vardır; primary key ise sizin tanımladığınız bir şeydir. Burada kritik istisna INTEGER PRIMARY KEY: bu sütun ayrı bir sütun olmak yerine doğrudan rowid için bir alias haline gelir. Diğer tüm primary key türleri (text, composite veya tam yazılmamış INT PRIMARY KEY) rowid'in yerine değil, onun yanında saklanır.

WITHOUT ROWID ne işe yarar?

WITHOUT ROWID, SQLite'a gizli rowid'i atlamasını ve sizin tanımladığınız PRIMARY KEY'i gerçek depolama anahtarı olarak kullanmasını söyler. Tam sayı olmayan anahtarlı tablolarda yerden tasarruf sağlayıp aramayı hızlandırabilir; ancak last_insert_rowid() ve incremental BLOB I/O gibi bazı özellikleri devre dışı bırakır. Varsayılan olarak değil, bilinçli kullanın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA