Menu

SQLite Primary Key: INTEGER, Composite ve AUTOINCREMENT

SQLite'ta primary key nasıl çalışır? INTEGER PRIMARY KEY, composite key, AUTOINCREMENT ve yeni başlayanları şaşırtan o meşhur NULL detayı.

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

SQLite Primary Key Aslında Ne İşe Yarar?

SQLite primary key, bir tablodaki her satırı tekil olarak tanımlayan sütundur (ya da sütun kombinasyonudur). İki satır aynı primary key değerini taşıyamaz. SQLite bu kuralı sizin yerinize uygular ve satırları hızlıca bulmak için bu anahtarı kullanır.

En sade kullanım, anahtarı doğrudan sütunun yanına yazmaktır:

id vermedin ama SQLite senin yerine bir tane uydurdu. Bu bir sihir değil — INTEGER PRIMARY KEY için geçerli olan özel bir durum ve başka bir şey yazmadan önce kavramanız gereken bir konu.

INTEGER PRIMARY KEY neden özeldir?

Çoğu veritabanında primary key, sadece eşsiz bir indekstir. Ama SQLite'ta her sıradan tablonun zaten satırları içeride tanımlamak için kullandığı, gizli bir 64-bit tam sayı vardır: rowid. Bir sütunu tam olarak INTEGER PRIMARY KEY şeklinde tanımladığında, o sütun doğrudan rowid'in kendisi olur. Ekstra indeks yok, ekstra alan yok — senin id'in ile satırın fiziksel konumu artık aynı şey.

id ve rowid aslında aynı kolondur, sadece iki farklı isimle anılırlar. id üzerinden yapılan aramalar doğrudan satıra gider — gezilecek ikinci bir ağaç yoktur. SQLite için standart tavsiye de bu yüzdendir: sayısal bir primary key istiyorsanız, INTEGER PRIMARY KEY ifadesini aynen bu şekilde yazın. INT değil, BIGINT değil, INTEGER NOT NULL PRIMARY KEY de değil (aslında bu sonuncusu çalışır, ama tipin mutlaka INTEGER olması şart).

Diğer tipler de iş görür — sadece ayrı bir unique index oluşturulur. Sorun değil, ama o kadar derli toplu olmaz.

SQLite AUTOINCREMENT genelde gereksizdir

Başka veritabanlarından gelen bir refleksle çoğu kişi id INTEGER PRIMARY KEY AUTOINCREMENT yazar. Oysa SQLite'taki AUTOINCREMENT anahtar kelimesi, isminin çağrıştırdığından çok daha dar bir iş yapar ve çoğu durumda buna ihtiyacınız olmaz.

AUTOINCREMENT olmadan, INTEGER PRIMARY KEY kolonu otomatik olarak mevcut en büyük rowid'in bir fazlasıyla doldurulur. Son satırı silerseniz, sonraki insert o id'yi tekrar kullan_abilir_.

AUTOINCREMENT ile birlikte SQLite, o ana kadar kullanılmış en yüksek id'yi sqlite_sequence adlı yan tabloda tutar ve silme işlemi olsa bile o değerleri bir daha asla kullanmaz.

plain tablosu 3 numaralı id'yi yeniden kullandı. AUTOINCREMENT olan tablo ise 4'e atladı. id'lerin tekrar kullanılmasını yasaklamak için gerçek bir nedeniniz yoksa — denetim, silinmeden sonra hâlâ duran dış referanslar gibi — AUTOINCREMENT kullanmayın. Her insert'te fazladan bir yazma maliyeti getiriyor ve ayrı bir kayıt tablosu tutuyor.

SQLite Composite Primary Key (Bileşik Birincil Anahtar)

Bazen tek bir sütun yetmez. Örneğin kullanıcıları rollere bağlayan bir ara tabloyu benzersiz kılan şey, (user_id, role_id) çiftidir. Böyle durumlarda anahtarı tablo seviyesinde tanımlayın:

Çiftin tüm tabloda benzersiz olması gerekir — (1, 10) yalnızca bir kez görünebilir. Sütunlardan herhangi biri tek başına istediği kadar tekrar edebilir. Bütün mesele de bu zaten: her kullanıcının birden fazla rolü olabilir, her rol birden fazla kullanıcıya atanabilir, ama belirli bir kullanıcı-rol eşleşmesi en fazla bir kez var olur.

SQLite composite primary key, listelenen sütunları kapsayan ayrı bir indeks oluşturur. Bu indeks rowid'in yerine geçmez — bu ayrıcalık yalnızca tek bir INTEGER PRIMARY KEY sütununa tanınır.

Primary Key'de NULL Tuzağı

PostgreSQL veya MySQL'den gelenleri şaşırtan bir tuhaflık var: standart bir SQLite tablosunda, INTEGER PRIMARY KEY dışındaki bir primary key sütunu NULL değer alabiliyor. Bu, SQLite ekibinin geriye dönük uyumluluk uğruna düzeltmediği eski bir hata.

NULL değerli iki satır primary key kontrolünü atlayarak tabloya girdi. Bunun çözümü, integer olmayan tüm primary key sütunlarına açıkça NOT NULL eklemektir:

Ya da NULL-in-PK hatasının düzeltildiği bir STRICT tablo kullanın. Her primary key sütununa NOT NULL yazma alışkanlığı ucuz bir sigortadır.

Primary Key ve UNIQUE Farkı

İkisi de yinelenen kayıtları engeller. Aralarındaki farklar şunlar:

  • Bir tablonun en fazla bir primary key'i olur, ama istediğiniz kadar UNIQUE kısıtı tanımlayabilirsiniz.
  • Primary key, tablonun "ana" kimliğidir — foreign key'ler varsayılan olarak ona işaret eder.
  • INTEGER PRIMARY KEY rowid olur; UNIQUE olarak işaretlenmiş bir integer sütun olmaz.
  • UNIQUE sütunlar birden fazla NULL değeri kabul eder (her NULL ayrı bir değer sayılır).

id, satırın kimliğidir. email ve username da tekildir ama bunlar iş alanına ait özelliklerdir; zamanla değişebilirler, oysa id değişmemelidir.

Sonradan Primary Key Eklemek (Genelde: Eklemeyin)

SQLite'ın ALTER TABLE komutu oldukça kısıtlıdır. ALTER TABLE ... ADD PRIMARY KEY gibi bir şey çalıştıramazsınız — böyle bir ifade yoktur. Eğer primary key tanımlamayı unuttuysanız ve tablo zaten dolu durumdaysa, izlenecek yol tabloyu yeniden oluşturmaktır:

Bu, SQLite'ta klasik bir tablo göçü (migration) dansı. Gerçek kodda bunu mutlaka bir transaction içine al; başka tablolar bu tabloya foreign key ile bağlıysa kısa süreliğine foreign key kontrollerini de devre dışı bırak. Buradan çıkacak ders şu: primary key'i en başta, CREATE TABLE aşamasında doğru kur.

Hızlı kontrol listesi

Yeni bir tablo yazarken kendine şunları sor:

  • Bu satırın doğal ve benzersiz bir kimliği var mı? Tek bir tam sayıysa, INTEGER PRIMARY KEY kullan.
  • Kimlik aslında birden fazla sütunun bileşimi mi (yani bir join tablosu)? O zaman tablo seviyesinde PRIMARY KEY (col_a, col_b) tanımla.
  • Anahtarın türü metin ya da tam sayı dışında bir şey mi? NOT NULL ifadesini açıkça ekle.
  • AUTOINCREMENT'a gerçekten ihtiyacın var mı? Büyük ihtimalle yok.
  • Tablo küçük, çoğunlukla okunuyor ve primary key'i tam sayı değil mi? WITHOUT ROWID seçeneğini değerlendir (rowid dokümanında ayrıntılı ele alınıyor).

Sırada: rowid

INTEGER PRIMARY KEY yukarıda "rowid'in bir takma adı" olarak kısaca geçti — ama rowid aslında her standart SQLite tablosunun altındaki temel yapı taşı ve onu doğrudan anlamak fazlasıyla işe yarıyor. Bir sonraki sayfanın konusu tam olarak bu.

Sıkça Sorulan Sorular

SQLite'ta primary key nasıl tanımlanır?

CREATE TABLE ifadenizdeki bir kolona PRIMARY KEY eklemeniz yeterli, örneğin id INTEGER PRIMARY KEY. Birden fazla kolonu kapsayan bir anahtar istiyorsanız tablo seviyesinde tanımlama yapın: PRIMARY KEY (col_a, col_b). Tek şart: kolon ya da kombinasyon satırlar arasında benzersiz olmalı.

INTEGER PRIMARY KEY ile diğer primary key'ler arasında ne fark var?

INTEGER PRIMARY KEY özel bir durumdur: tablonun yerleşik rowid değerine takma ad olur ve doğrudan B-tree içinde tutulur, ekstra bir indeks oluşturulmaz. Başka bir tip kullanırsanız ya da composite key tanımlarsanız SQLite ayrı bir unique index açar. Tek kolonlu sayısal id'ler için INTEGER PRIMARY KEY hem daha hızlı hem de daha az yer kaplar.

SQLite primary key'inde AUTOINCREMENT kullanmam şart mı?

Genellikle hayır. INTEGER PRIMARY KEY zaten NULL ekleyince otomatik olarak benzersiz bir rowid atar. AUTOINCREMENT ise sadece şunu garanti eder: silinen id'ler bir daha asla kullanılmaz — ama bunun bedeli ekstra bir sqlite_sequence tablosudur. Bu monoton id davranışına özel ihtiyacınız yoksa kullanmayın.

Primary key kolonum neden NULL değer kabul ediyor?

Bu eski bir bug, ama geriye dönük uyumluluk için korunuyor: normal tablolarda INTEGER olmayan bir primary key kolonu, açıkça NOT NULL yazmadığınız sürece NULL kabul edebiliyor. Tek istisna INTEGER PRIMARY KEY — o asla NULL almaz. Garantici olmak için her primary key kolonuna NOT NULL yazın ya da kuralın düzgün uygulandığı STRICT tablolar kullanın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA