Birinin Postgres hakkında bana söylemesini istediğim şeyler
(challahscript.com)- Postgres’in resmi dokümantasyonu harika, ancak Postgres 17 PDF’i 3.200 sayfa olduğu için, yeni başlayanların gerçek işe geçmeden önce şema tasarımını, SQL davranışlarını ve operasyonel tuzakları yalnızca dokümanlardan öğrenmesi zor
- Özel bir neden yoksa veriyi normalize edin; okuma performansı için yinelenen veri tutan denormalizasyon ise tutarsızlık ve yazma karmaşıklığı maliyetini beraberinde getirir
- SQL anahtar kelimeleri büyük/küçük harfe duyarlı değildir, ancak NULL “bilinmiyor” kavramına daha yakındır; bu yüzden genel dillerdeki
nullgibi karşılaştırırsanız beklenmedik sonuçlar alabilirsiniz psqliçinde pager,\x,.psqlrc,\pset null, otomatik tamamlama, ters eğik çizgi komutları ve\copyyi iyi kullanmak bile çıktı okunabilirliğini, keşfi ve CSV dışa aktarmayı büyük ölçüde kolaylaştırır- İndeksler, kilitler, transaction’lar ve JSONB güçlüdür; ancak sorgu planlarını ve operasyonel kısıtları bilmezseniz performans düşüşüne veya erişilebilirlik sorunlarına yol açabilir
Devasa resmi dokümantasyondan önce bilinmesi gereken bağlam
- Postgres resmi dokümantasyonu, mevcut sürüm 17 için US letter PDF olarak yazdırıldığında 3.200 sayfa, A4 olarak yazdırıldığında ise 3.024 sayfadır
- Postgres kullanmadan önce bilinmesi iyi olacak çok sayıda pratik bilgi vardır; bunların bir kısmı diğer SQL DBMS’ler için de geçerli olabilir, ancak geçerlilik kapsamı her zaman net değildir
Veriyi varsayılan olarak normalize edin
- Normalizasyon, veritabanı şemasında yinelenen veya gereksiz veriyi kaldırma sürecidir
documentstablosundauser_emaili doğrudan saklarsanız, kullanıcı e-postasını değiştirdiğinde o kullanıcıya ait tüm belge satırlarını güncellemeniz gerekir- Bunun yerine
documentsiçindeki her satırınusersgibi başka bir tablodaki satırıuser_idyabancı anahtarıyla referans almasını sağlayabilirsiniz
- Bunun yerine
- “1st normal form” gibi tüm normal formları ezberlemeniz gerekmez, ancak genel normalizasyon süreci genellikle bakımı daha kolay şemalara yol açar
- Denormalizasyon, belirli verileri her seferinde yeniden hesaplamadan hızlı okumak için yinelenen veri tutma yöntemidir
- Çalışan vardiya uygulamasında, bu yılın birikmiş toplam çalışma süresini her seferinde tüm shift duration değerlerini toplayarak hesaplamak yerine, periyodik olarak veya çalışma süresi değiştiğinde hesaplayıp saklayabilirsiniz
- Bu veri Postgres içinde tutulabileceği gibi Redis gibi bir cache katmanında da tutulabilir
- Denormalizasyonun neredeyse her zaman bir maliyeti vardır; bunun en tipik maliyetleri veri tutarsızlığı olasılığı ve artan yazma karmaşıklığıdır
Postgres projesinin “bunu yapmayın” tavsiyeleri
- Resmi Postgres wiki’sinde “Don’t do this” listesi bulunur
- Tüm maddeleri anlamıyor olmanız sorun değildir; anlamadığınız maddelerde aynı hatayı yapma olasılığınız da düşüktür
- Özellikle şu tavsiyeleri akılda tutmaya değer
- Metin saklamak için
texttype kullanın - Timestamp saklamak için
timestampz/time with time zonekullanın - Tablo adlarını snake_case ile verin
- Metin saklamak için
SQL’de kafa karıştırması kolay davranışlar
-
SQL anahtar kelimelerinin büyük harf olması gerekmez
- SQL anahtar kelimeleri büyük/küçük harfe duyarlı değildir
- Aşağıdaki sorgular aynı anlama gelir
SELECT * FROM my_table WHERE x = 1 AND y > 2 LIMIT 10; select * from my_table where x = 1 and y > 2 limit 10; SELECT * from my_table WHERE x = 1 and y > 2 LIMIT 10;- Bu özellik yalnızca Postgres’e özgü değildir
-
NULL, genel dillerdeki null/nil ile aynı değildir
- SQL’deki
NULL, genel programlama dillerindekinullya danilden çok “bilinmiyor” kavramına yakındır NULL = NULL,truedeğilNULLdöndürür- Taraflardan biri
NULLolan karşılaştırmalarda sonuç çoğunlukla yineNULLolur NULLkarşılaştırmaları için şu işlemleri kullanmanız gerekirx IS NULL:x,NULLisetruex IS NOT NULL:x,NULLdeğilsetruex IS NOT DISTINCT FROM y:x = yye benzer amaNULLü normal bir değer gibi ele alırx IS DISTINCT FROM y:x != y/x <> yye benzer amaNULLü normal bir değer gibi ele alır
WHEREbölümü yalnızca koşultrueolduğunda satır döndürürSELECT * FROM users WHERE title != 'manager',titledeğeriNULLolan satırları döndürmez- Çünkü
NULL != 'manager'sonucunun değeriNULLdür
COALESCE, birden çok argüman içindenNULLolmayan ilk değeri döndürür
COALESCE(NULL, 5, 10) = 5 COALESCE(2, NULL, 9) = 2 COALESCE(NULL, NULL) IS NULL - SQL’deki
psqli daha kullanışlı hale getirmek
-
Çıktı okunabilirliğini iyileştirme
- Çok sütunlu veya uzun değerli tabloları sorguladığınızda çıktı okunması zorsa pager kapalı olabilir
- Terminal pager, büyük metinleri veya
psqltablolarını görünüm alanı içinde kaydırarak incelemenizi sağlar - Çok sütunlu tablolar için
\pset expandedveya\xile expanded mode açabilirsiniz - Varsayılan olarak kullanmak isterseniz home dizininizdeki
~/.psqlrcdosyasına\xekleyebilirsiniz
-
NULL çıktısını daha belirgin hale getirme
- Varsayılan ayar, çıktı içinde
NULLolup olmadığını net biçimde göstermez psqliçindeNULLgösterim dizesini belirleyebilirsiniz
\pset null '[NULL]'- Unicode dizeler de kullanılabilir; bunu varsayılan yapmak için aynı komutu
~/.psqlrciçine ekleyebilirsiniz
- Varsayılan ayar, çıktı içinde
-
Otomatik tamamlama ve ters eğik çizgi komutlarını kullanma
psql, etkileşimli bir konsol gibi otomatik tamamlama destekler- Bir anahtar kelimenin veya tablo adının bir kısmını yazıp Tab’a bastığınızda geri kalanını tamamlayabilirsiniz
- Faydalı ters eğik çizgi komutları şunlardır
\?: tüm kısayolların listesi\d: relation, yani tablo ve sequence listesi ile sahiplerini gösterir\d+:\dye boyut ve bazı metadata bilgileri ekler\d table_name: tablo şeması, sütun tipleri, nullable durumu, varsayılan değerler, indeksler ve yabancı anahtar kısıtlarını gösterir\e: sorguyu,$EDITORortam değişkeninde ayarlı varsayılan editörde düzenler\h SQL_KEYWORD: ilgili SQL anahtar kelimesinin sözdizimini ve dokümantasyon bağlantısını gösterir
-
CSV dışa aktarma ve SELECT takma adları
\copyile sorgu sonuçlarını CSV olarak kaydedebilirsiniz
\copy (select * from some_table) to 'my_file.csv' CSV- Sütun adlarını ilk satıra eklemek için
HEADERseçeneğini kullanın
\copy (select * from some_table) to 'my_file.csv' CSV HEADER\copy, daha standart olanCOPYifadesinin gerektirdiği yükseltilmiş ayrıcalıklardan kaçınmanızı sağlarSELECTçıktı sütunlarınaASile takma ad verebilirsiniz
SELECT vendor, COUNT(*) AS number_of_backpacks FROM backpacks GROUP BY vendor ORDER BY number_of_backpacks DESC;GROUP BYveORDER BYiçinde,SELECTten sonra gelen sütun numaralarına referans verebilirsiniz
SELECT vendor, COUNT(*) AS number_of_backpacks FROM backpacks GROUP BY 1 ORDER BY 2 DESC;- Bu kısaltma yararlıdır, ancak production’a dağıtılan sorgularda kullanmamak daha iyidir
İndeksler eklendiğinde her zaman kullanılmaz
-
İndeksler ve sorgu planları
- İndeks, tablo satırlarını belirli alanlara göre bulmak için kullanılan bir veri yapısıdır; bir kısayol dizini gibi çalışır
- En yaygın indeks türü B-tree’dir ve
WHERE a = 3gibi tam eşitlik koşullarında veyaWHERE a > 5gibi aralık koşullarında çalışır - Postgres’e belirli bir indeksi kullanmasını doğrudan söyleyemezsiniz
- Postgres, her tablo için tuttuğu istatistiklere dayanarak bir indeksin, tabloyu baştan sona okuyan sequential scan’den daha hızlı olup olmayacağını tahmin eder
SELECT ... FROM ...ifadesinin başınaEXPLAINeklediğinizde, Postgres’in sorguyu nasıl çalıştıracağına dair sorgu planını görebilirsiniz- Sorgu planı okurken thoughtbot’un EXPLAIN ANALYZE rehberi, pganalyze dokümantasyonu, resmi dokümantasyon ve explain.depesz.com kaynaklarına bakabilirsiniz
-
Küçük tablolar ve çok sütunlu indeksler
- Yerel geliştirme veritabanındaki gibi az satırlı tablolarda indeksler çok fayda sağlamayabilir
- Örneğin 100 satır civarında bir tabloda Postgres, indeks yerine sequential scan’in daha hızlı olduğuna karar verebilir
- Postgres, çok sütunlu indeksleri destekler
CREATE INDEX CONCURRENTLY ON tbl (a, b);WHERE a = 1 AND b = 2gibi koşullar,avebüzerinde ayrı ayrı indeksler bulundurmaktan daha hızlı olabilir- Bunun nedeni, tek bir B-tree üzerinde gezinirken arama koşullarını verimli biçimde birleştirebilmesidir
(a, b)indeksi, yalnızcaaile filtreleyen sorguları da tek başınaaindeksi kadar hızlı hale getirirWHERE b = 5gibi sorgular hızlanabilir, ancak en iyi çözüm olmayabilir- Çünkü indeks önce
a, sonrabanahtarına göre sıralanmıştır; bu yüzdenbdeğerini bulmak için tümadeğerleri boyunca ilerlenmesi gerekebilir
- Çünkü indeks önce
- Birden fazla sütun kombinasyonuyla sorgu çalıştırmanız gerekiyorsa, çoğu zaman
(a, b)ile birlikte yalnızcabiçin de ayrı bir indeks tutulur - İhtiyaca göre
avebiçin ayrı tek sütunlu indekslere de güvenebilirsiniz
-
Prefix match için text_pattern_ops kullanın
- Materialized path yöntemiyle hiyerarşik dizinler saklıyor ve belirli bir prefix ile başlayan tüm descendant kayıtlarını bulmanız gerekiyor olabilir
SELECT * FROM directories WHERE path LIKE '/1/2/3/%'pathsütunu üzerinde varsayılan bir B-tree indeksi oluştursanız bile bu sorguda kullanılmayabilir
CREATE INDEX CONCURRENTLY ON directories (path);- Prefix match veya pattern match için gereken karakter bazlı sıralamayı mümkün kılmak istiyorsanız operator class belirtmeniz gerekir
CREATE INDEX CONCURRENTLY ON directories (path text_pattern_ops);
Kilitlerin ve transaction’ların yarattığı operasyonel sorunlar
-
Postgres’te kilitler
- Kilit (lock) ya da mutex, riskli işlerin aynı anda yalnızca tek bir istemci tarafından yapılmasını sağlayan mekanizmadır
- Veritabanında row, table, view gibi nesnelerin güncellenmesi ya tamamen başarılı olmalı ya da tamamen başarısız olmalıdır; eşzamanlı işlemler nedeniyle yalnızca bir kısmının başarılı olmasını önlemek için ilgili nesnelerde kilit alınır
- Postgres’in tablo kilidi seviyeleri, daha az kısıtlayıcı olandan daha kısıtlayıcı olana doğru birkaç basamaktan oluşur
ACCESS SHARE:SELECTROW SHARE:SELECT ... FOR UPDATEROW EXCLUSIVE:UPDATE,DELETE,INSERTSHARE UPDATE EXCLUSIVE:CREATE INDEX CONCURRENTLYSHARE:CREATE INDEX, ancakCONCURRENTLYolmadanACCESS EXCLUSIVE: birçokALTER TABLE,ALTER INDEXtürü
- Aynı tabloda şu işlemler mümkün olabilir ya da beklemek zorunda kalabilir
UPDATEsırasındaSELECT: mümkünUPDATEsırasındaCREATE INDEX CONCURRENTLY: mümkünSELECTsırasındaCREATE INDEX: mümkünSELECTsırasındaALTER TABLE: genellikle beklerALTER TABLEsırasındaSELECT: genellikle bekler
- Bazı
ALTER TABLEtürleri daha zayıf kilitler gerektirebilir; tüm bilgiler için resmi explicit locking dokümantasyonuna ve işlem türüne göre kilit çakışması rehberine bakabilirsiniz
-
Yavaş ALTER TABLE ve kilit kuyruğu
ALTER TABLEuzun sürerse, aynı tabloyu okuyanSELECTsorguları da bloke olabilir- Bu tablo bir web uygulamasındaki tüm isteklerin referans verdiği
usersgibi kritik bir tabloysa, istekler bekleyip timeout olabilir ve 503 döndürebilir - Yavaş
ALTER TABLEişlemlerinin yaygın nedenleri şunlardır- sabit olmayan bir default değere sahip sütun eklemek
- sütun tipini değiştirmek
- uniqueness constraint eklemek
- Postgres 11’den sonra, sütun eklerken tüm default değerlerin işlemi yavaşlatması sorunu düzeltildi; sorun çıkarabilecek olan sabit olmayan default’lardır
ALTER TABLEişleminin kendisi hızlı olsa bile, kilidi alana kadar çalışmaz- Uzun zamandır var olan bir dahili dashboard üzerindeki yavaş bir
SELECThâlâ çalışıyorsaALTER TABLEbeklemek zorunda kalabilir
- Uzun zamandır var olan bir dahili dashboard üzerindeki yavaş bir
- Postgres kilitleri bir kuyruk oluşturduğu için, bekleyen bir
ALTER TABLEın arkasına gelen aynı tablodaki sonraki sorgular da bekleyebilir - Aynı senaryo Migrations and exclusive locks yazısında daha ayrıntılı inceleniyor
-
Uzun transaction’lar da tehlikelidir
- Transaction, birden fazla veritabanı ifadesini hep-ya-hiç mantığıyla bir araya getirir;
BEGINile başlar veCOMMITile biter - Transaction içindeki değişiklikler diğer istemcilere görünmez;
COMMITolduğunda veritabanında görünür hale gelir - Para transferi gibi bir hesaptan bakiyenin düşmesi ve başka bir hesaba eklenmesinin birlikte başarılı olması ya da birlikte iptal edilmesi gereken işlemler için uygundur
- Bir transaction kilit aldıysa,
COMMITe kadar o kilidi elinde tutar BEGINsonrasında belirli bir row’uUPDATEedip masadan kalkarsanız, başka bir istemcinin aynı row üzerindekiDELETEişlemi transaction commit edilene kadar durur- Gerekenden uzun süre açık kalan transaction’lar, diğer istemcilerin sorgularını veya güncellemelerini engelleyebilir
- Transaction, birden fazla veritabanı ifadesini hep-ya-hiç mantığıyla bir araya getirir;
JSONB keskin bir araçtır
-
JSONB’nin performans ve şema sorunları
- JSONB esnektir, ancak yanlış kullanıldığında dezavantajları büyüktür
- Postgres, JSONB sütunlarının istatistiklerini takip etmez; bu yüzden tek bir JSONB sütunu üzerindeki eşitlik sorguları, normal sütunlar kümesi üzerindeki sorgulardan çok daha yavaş olabilir
- Bir örnekte JSONB yüzünden 2000 kat yavaşlama görülebilir
- JSONB sütununa fiilen her şey konabilir; bu onu güçlü yapar ama yapıya dair güvenceleri azaltır
- Normal tablolar için şemaya bakarak sorgu sonucunu tahmin edebilirsiniz; ancak JSONB’de key adının camelCase mi snake_case mi olduğu ya da bir durum alanının boolean mı enum mu olduğu net olmayabilir
- Normal Postgres verisinin sahip olduğu statik tip özellikleri JSONB için aynı şekilde geçerli değildir
-
JSONB tip karşılaştırmalarının tuhaflığı
backpackstablosundaki JSONBdatasütunundabrandalanıJanSportolan satırları bulmak istediğinizde şu sorgu çalışmaz
select * from backpacks where data['brand'] = 'JanSport';- Postgres, karşılaştırmanın sağ tarafındaki tipin sol tarafla eşleşmesini bekler; sağ taraf da geçerli bir JSON dokümanı olmalıdır
- JSON dokümanı; nesne, dizi, string, sayı, boolean veya null olmalıdır, bu nedenle tek başına
JanSportgeçerli JSON değildir - Doğru sorgu, ya JSON string ile karşılaştırmak ya da sol tarafı Postgres
texttipine dönüştürmek şeklindedir
select * from backpacks where data['brand'] = '"JanSport"'; select * from backpacks where data['brand'] = '"JanSport"'::jsonb; select * from backpacks where data->>'brand' = 'JanSport';- SQL’deki
NULLile JSONB’dekinullfarklı çalışır'null'::jsonb = 'null'::jsonb,truedöndürürkenNULL = NULLsonucuNULLdür
- JSONB için çok sayıda özel operatör ve fonksiyon vardır; bunları bir seferde akılda tutmak zordur
- Postgres’te JSON değerlerini metin olarak saklayan
JSONile bunları verimli bir ikili biçime dönüştürenJSONBbirlikte bulunur - JSONB’nin indekslenebilme gibi avantajları vardır;
JSONformatı ise daha özel durumlara yönelik düşünülebilir
2 yorum
Yapılmaması gerekenler; bir gün mutlaka okuyacağım.
Hacker News yorumları
PostgreSQL genel olarak büyük/küçük harfe duyarlıdır, ama SQL anahtar sözcüklerini büyük harfle yazmak çoğunlukla görsel örüntü eşleştirme yoluyla okunabilirliği artırma çabasıdır
Şart değil, ama başkasının sorgusunu debug etmem gerekse, küçük sözdizimi biçimlerine takılmadan tanımı hızlıca gözden geçirmek için bir prettifier’a atardım
Diğer dillerde kod biçimlendirmede olduğu gibi, tutarlı girintileme gibi görsel yapı da bariz kısımları anlamaya harcanan zamanı azaltır ve önemli olana odaklanmayı sağlar
Ancak
actuallyUsingCaseInIdentifiersgibi tanımlayıcılarda gerçekten büyük/küçük harf karıştırılmasından hiç hoşlanmıyorum; CLI’da kontrol etmek için çift tırnak gerektiren sütunlar görmek istememKimsenin görmeyeceği geçici bir sorguyu hızlıca yazıp atacak olsam büyük/küçük harfi umursamam, ama depoya commit edilecek SQL’de komutları ALL CAPS yazarım
Renkli ekranların olduğu günümüzde artık gerekli değil, ama bu eski bir hatıra; elimde kaynak yok
Yine de tırnak içindeki ve tırnaksız tanımlayıcıları karıştırmamak gerekir; iç yapıyı sorgulama da çoğunlukla standartlaşmış değildir, bu yüzden bunun pek önemi yok
PostgreSQL wiki’sindeki “don’t do this” maddesini ilk kez gördüm ve oldukça faydalı: https://wiki.postgresql.org/wiki/Don%27t_Do_This
Örneğin yeni şemalarda tablo kalıtımı gibi özellikleri devre dışı bırakıp, tekrar açmak için kasıtlı olarak karmaşık bir ayar gerektirmek daha doğru görünüyor
Burada geçen şeylerin çoğu yalnızca PostgreSQL’e özgü değil
NULL’un tuhaf davranışı, indeks sütun sırası gibi şeyler buna dahil; özellikle NULL ile indeks/unique kısıtlarının etkileşimi MySQL’de de sezgisel değilÖrneğin
emailalanı NULL olamaz,usernamealanı NULL olabilir olan bir kullanıcı tablosunda(email, username)unique kısıtı koyarsanız,usernamedeğeri NULL olan aynıemailbirden fazla kez eklenebilir. Çünkü NULL, başka bir NULL’a eşit değildirhttps://www.postgresql.org/docs/devel/sql-createtable.html#S...
Ters davranışın gerektiği kullanım senaryoları çok daha nadir
“İyi bir neden yoksa verileri normalize edin” deyip geçmek sorunlu
Yazarın bağlantı verdiği sayfada, normal olmayan form dahil normal formlar 11 tane olarak geçiyor; çoğu kişi bunların ne olduğunu bile bilmez ve bunlardan 7’sini zaten kullanmaz
İnsanları daha yüksek normal form arayışına sürüklememek gerekir
Yakın zamanda geçtiğim projede de bu tür birkaç sorunu düzeltmem gerekti; veriyi çoğaltmak için neredeyse hiç neden yok
İlk ipucu her gün VACUUM çalıştırmak
Başlarken bunu bilmiyordum; reddit veritabanında hiç VACUUM yapmadım ve bir gün mecburen çalıştırdığımda, bitmesini beklerken reddit neredeyse bir gün boyunca kapalı kaldı
reddit ölçeğinde transaction ID’lerin önce tükenmemiş olması şaşırtıcı
Geliştiricilerin normalizasyona daha fazla önem vermesini ve her şeyi JSONB sütunlarına tıkıştırmayı bırakmasını isterdim
Daha deneyimli geliştiriciler, doğru yanıtın anahtarlar dışında hiçbir şeyi yinelememek ve denormalizasyona ancak gerçekten istemeye istemeye başvurmak olduğunu bilirdi
Sonra Mongo gibi veritabanları ortaya çıkıp, normalizasyonun zor ya da anlamsız olduğu “veritabanı benzeri şeyler” sunarak bu junior’ları cesaretlendirdi; bunun sonucunda korkunç veritabanı tasarımları ve bakımı imkânsız çöp kuleleri kısa süreliğine serpilip gelişti
Şimdi sarkaç geri döndü ve normalize veritabanlarının avantajları yeniden keşfedildi, ancak JSON sütunları hâlâ kötü pratiklerin büyüyebileceği bir kaçış yolu olmaya devam ediyor
Birincisi, JSON saklamak. Bir web sunucusu üçüncü taraf bir API’yi çağırdığında ham API yanıtını bir JSONB sütununda saklayıp işlemi oradan yaparsa, o API’den kaynaklanan sorunları debug ederken denetlenebilir bir kayıt kalır
İkincisi, sum type saklamak. SQL’in sum type desteklememesi, SQL veritabanlarında veri modellemenin en büyük kusurlarından biri sayılabilir
Çeşitli geçici çözümler var ve “JSONB sütununa koyup uygulamada doğrula” da bunlardan biri; ama bu çözümlerin hiçbiri özellikle harika değil
JSONB içindeki değerleri ayrı sütunlara çıkarmadan, onun içinde kötü sorgular yazmıyorsanız, bunun başlı başına büyük bir sorun olduğunu düşünmüyorum
Çünkü kalıcılık gereksinimleri başarıyla karşılandığı sürece iyi tasarım üzerine düşünmeye yönelik güçlü bir baskı olmuyor
Bir DBMS’in üstüne bir DBMS daha inşa etmek doğru mu, tartışılır; ama mevcut durum her hâlükârda bu
Yeni bir sütun performansı bozarsa ya da sorun çıkarırsa geri alınabilmeli
İşin içinde CLI araçları varsa, ne kadar downtime’a katlanılabileceğini, şirket genelinde senkronize bir sürüm güncellemesinin mümkün olup olmadığını, yoksa bir süre hem eski hem yeni şemanın mı destekleneceğini de ele almak gerekir
Veritabanı ekibin ana ürününün bir parçası değilse, tüm bunlar eksik olabilir
Yeni başlayanlara yardımcı olmak için bu yazıyı yazdım: https://tomcam.github.io/postgres/
Yazı gerçekten iyi ve PostgreSQL belgelerinin 3200 sayfa olduğunu bilmiyordum
Bir süredir kullanıyorum ve ihtiyaç duydukça öğreniyorum; resmi belgeleri de epey seviyorum, belirli bir konu gerektiğinde ilgili yazıları okumayı da seviyorum
Yazarın https://challahscript.com/what_i_wish_someone_told_me_about_... adresine
(b, a)sütun indeksinin yalnızcabile sorgularken iyi çalıştığını eklemesi okuyucuya yardımcı olur gibiaile sorgulamadan bahsederken bu bir ölçüde ima ediliyor, ama daha açık yazmak fena olmazJSON/JSONB kısmını pek kullanmadığım için çok bakmadım
Gerçek sahada gördüğüm gülünç SQL’leri düşününce, Codd makalesini okuyup ilişkisel modelin ne olduğunu anlamaya çalışmakla başlamak iyi olurdu
Sadece 11 sayfa ve onu okumak bile dünyadaki acıyı azaltır
Bu yazının neredeyse tamamı MySQL gibi diğer MVCC veritabanları için de geçerli
Ayrıntılar farklı olabilir, ama MySQL de uzun transaction’lardan muzdarip oluyor ve
ALTERsırasında metadata lock alıyor; benzer eğlenceli sorunları var