- Postgres’i daha üretken ve güvenli kullanmaya yardımcı olan pratik kalıpları derleyen bir yazı
- Her kalıp küçük olsa da biriktiğinde büyük fark yaratır
UUID birincil anahtar kullanımı
- UUID rastgele olduğu için sıralama veya indeks performansı açısından dezavantajlara sahiptir
- Sayısal ID’lere göre daha fazla alan kaplar
- Ancak şu avantajları vardır
- Veritabanına bağlanmadan da UUID üretilebilir
- Dışarıya güvenle açığa vurulabilir
gen_random_uuid() kullanılarak UUID’nin birincil anahtar olarak otomatik üretilmesi sağlanabilir
created_at ve updated_at alanlarını her zaman ekleyin
- Hata ayıklama sırasında kaydın ne zaman oluşturulduğunu ve değiştirildiğini bilmek çok faydalıdır
updated_at, trigger aracılığıyla otomatik güncellenecek şekilde ayarlanabilir
- Fonksiyon bir kez oluşturulur, trigger ise her tabloya uygulanmalıdır
Yabancı anahtarlarda on update/delete restrict ayarı kullanın
- Yabancı anahtar kısıtları tanımlanırken
on update restrict on delete restrict mutlaka kullanılmalıdır
- Veri silinirken yanlışlıkla zincirleme silme yaşanmasını önler
- Depolama alanı ucuzdur ama veriyi geri getirmek çok zordur; bu yüzden temkinli davranmak daha iyidir
Şema kullanımı önerilir
- Varsayılan şema
public olsa da uygulama büyüdükçe ayrı şemalara bölmek daha iyidir
- Şemalar namespace gibi çalışır ve farklı şemalar arasında da join yapılabilir
- Tablo sayısı arttıkça şema kullanımı okunabilirlik ve bakım açısından avantaj sağlar
Enum tablo kalıbını kullanın
- PostgreSQL’in enum tipi veya check constraint’i yerine enum tablo yaklaşımı daha esnektir
- Enum değerleri ayrı tabloda tutulursa metadata eklemek veya enum değerlerini genişletmek kolaylaşır
- Kısıtlar, enum tablosundaki değerlere yabancı anahtarla referans verilerek korunur
Tablo adlarını tekil verin
- Tablo adlarını çoğul yerine tekil vermek tercih edilir
- Sorgu yazarken tekil adlar daha açıktır; çoğul adlar iyelik ya da anlamsal karışıklık yaratabilir
Join tablolarını mekanik biçimde adlandırın
- Çoktan çoğa ilişki için kullanılan join tablolarını, iki tablo adını birleştirerek adlandırmak güvenli ve nettir
- Örnek:
person_pet
- Kombinasyon üzerine benzersiz indeks eklenerek tekrarlar önlenebilir
Silme yerine soft delete kullanın
- Veriyi gerçekten silmek yerine, silinme zamanını gösteren
revoked_at gibi bir timestamp alanı kullanmak daha iyidir
- Bu sayede yalnızca silinip silinmediği değil, ne zaman silindiği de izlenebilir
- Boolean değerden daha fazla bilgi sunduğu için timestamp daha faydalıdır
Durumu (status) log tablosuyla ifade edin
- Durumu tek bir sütunla ifade etmek yerine, durum değişikliği geçmişi ayrı bir tabloda saklanmalıdır
- Durumun gerçekleştiği zaman
valid_at sütununda açıkça belirtilir
- En güncel durumu hızlı sorgulamak için
latest bayrağı ile benzersiz indeks + trigger ayarlanır
- Bu yaklaşım, asenkron event işleme veya sıralamanın karışabileceği durumlarda avantaj sağlar
Özel satırlar için system_id ekleyin
- Yalnızca enum tablolarında değil, belirli “sistem satırları” gereken durumlar da vardır
- Nullable bir
system_id metin alanı eklenip benzersiz indeks tanımlanır
system_id sayesinde belirli satırlar açık biçimde sorgulanabilir
View’ları asgari düzeyde kullanın
- View’lar karmaşık sorguları soyutlamak için faydalıdır ama bakımı zordur
- Bir sütun kaldırıldığında view’ın yeniden oluşturulması gerekir
- View üstüne view kurmak performans ve okunabilirlik sorunları yaratır
- Bu yüzden yalnızca gerektiği kadar ve dikkatli kullanılmalıdır
JSON sorgularını aktif biçimde kullanın
- Postgres yalnızca JSON saklamada değil, JSON döndüren sorgularda da çok güçlüdür
- İç içe ilişkiler tek sorguda JSON biçiminde döndürülebilir
- N+1 problemi olmadan gereken tüm veriler tek seferde alınabilir
- Dezavantajları: tip bilgisinin kaybolması, tüm verinin aynı anda belleğe yüklenmesi gerekmesi
- Buna rağmen performans ve yapı açısından avantajları daha büyüktür
4 yorum
> Join tablosuna mekanik olarak ad verin
Ad verirken böyle bir kuralın olması başlı başına güzel bence~
UUID7'yi düşünürsek zaman sırasına göre sıralama mümkün olmaz mı?
PostgreSQL'de UUID'yi birincil anahtar olarak kullanma hakkında yazısına da göz atmak faydalı olabilir.
soft delete sırasında timestamp ekleme yöntemi güzelmiş.
Birincil anahtar olarak UUID kullanılırsa zamana göre sıralama yapılamayacağı için, snowflake ID veya ULID kullanmak da iyi bir seçenek olabilir. Ancak bu durumda her sunucunun bir sequence number tutması gerekiyor.