ProHoster > Blog > yönetim > PostgreSQL Antipatterns: "Yalnızca bir tane olmalı!"
PostgreSQL Antipatterns: "Yalnızca bir tane olmalı!"
SQL'de, "nasıl" yürütülmesi gerektiğini değil, "neyi" başarmak istediğinizi tanımlarsınız. Dolayısıyla “Duyulduğu gibi yazılır” tarzında SQL sorguları geliştirme sorunu da ön plana çıkıyor. SQL'de koşulları hesaplamanın özellikleri.
Bugün son derece basit örnekler kullanarak bunun kullanım bağlamında nelere yol açabileceğini görelim. GROUP/DISTINCT и LIMIT onlarla.
Şimdi, eğer istekte yazdıysanız “önce bu işaretleri birleştirin ve ardından tüm kopyaları atın, sadece bir tane kalmalı her anahtar için kopyala" - bağlantıya hiç ihtiyaç duyulmasa bile tam olarak bu şekilde çalışacaktır.
Ve bazen şanslısınız ve "sadece işe yarıyor", bazen performans üzerinde hoş olmayan bir etkiye sahip oluyor ve bazen geliştiricinin bakış açısından tamamen beklenmedik etkiler veriyor.
Belki o kadar muhteşem olmayabilir ama...
“Tatlı çift”: KATIL + AYRIŞTIR
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition;
Ne istedikleri belli olacak Y'de yerine getirilen koşulla ilgili kayıtların bulunduğu X kayıtlarını seçin. aracılığıyla bir istek yazdı JOIN - birkaç kez bazı pk değerleri aldım (Y'de tam olarak kaç tane uygun girişin göründüğü). Nasıl kaldırılır? Kesinlikle DISTINCT!
Her X kaydı için birkaç yüz ilgili Y kaydının olması ve ardından kopyaların kahramanca kaldırılması özellikle "memnun edicidir"...
Nasıl düzeltilir? Başlangıç olarak sorunun şu şekilde değiştirilebileceğini anlayın: "Y'de yerine getirilen koşulla EN AZ BİR BİRİNİN bulunduğu X kayıtlarını seçin" - sonuçta Y kaydının kendisinden hiçbir şeye ihtiyacımız yok.
İç içe MEVCUTLAR
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
);
PostgreSQL'in bazı sürümleri, EXISTS'te ortaya çıkan ilk girişi bulmanın yeterli olduğunu, eskilerin ise bunu yapmadığını anlıyor. Bu nedenle her zaman belirtmeyi tercih ederim LIMIT 1 içinde EXISTS.
YANAL BİRLEŞİM
SELECT
X.*
FROM
X
, LATERAL (
SELECT
Y.*
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
) Y
WHERE
Y IS DISTINCT FROM NULL;
"Neden daha fazla ödeyesiniz": DISTINCT [ON] + LIMIT 1
Bu tür sorgu dönüşümlerinin ek bir yararı, aşağıdaki durumda olduğu gibi yalnızca bir veya birkaç tanesine ihtiyaç duyulması durumunda kayıt aramasını kolayca sınırlandırma yeteneğidir:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Şimdi isteği okuyoruz ve DBMS'nin ne yapması önerildiğini anlamaya çalışıyoruz:
işaretlerin bağlanması
X.pk tarafından benzersiz
kalan girişlerden birini seçin
Peki ne aldın? "Sadece bir giriş" benzersiz olanlardan - peki bunu benzersiz olmayanlardan alırsak sonuç bir şekilde değişir mi?.. “Peki fark yoksa neden daha fazla ödeyelim?”
SELECT
*
FROM
(
SELECT
*
FROM
X
-- сюда можно подсунуть подходящих условий
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Ve tamamen aynı konu GROUP BY + LIMIT 1.
"Sadece sormam gerekiyor": örtülü GROUP + LIMIT
Farklı zamanlarda benzer şeyler oluyor boşluk kontrolleri istek ilerledikçe işaretler veya CTE'ler:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ...
Toplama işlevleri (count/min/max/sum/...) açık talimatlar olmadan bile setin tamamında başarıyla yürütülür GROUP BY. Sadece ile LIMIT pek dost canlısı değiller.
Geliştirici düşünebilir “Eğer orada kayıtlar varsa, o zaman LIMIT'den fazlasına ihtiyacım yok”. Ama bunu yapma! Çünkü taban için:
istediklerini say tüm kayıtlara göre
istedikleri kadar satır ver
Hedef koşullara bağlı olarak aşağıdaki değişikliklerden birinin yapılması uygundur:
(count + LIMIT 1) = 0üzerindeNOT EXISTS(LIMIT 1)
(count + LIMIT 1) > 0üzerindeEXISTS(LIMIT 1)
count >= Nüzerinde(SELECT count(*) FROM (... LIMIT N))
“Gram cinsinden ağırlığı ne kadardır”: DISTINCT + LIMIT
SELECT DISTINCT
pk
FROM
X
LIMIT $1
Deneyimsiz bir geliştirici, isteğin yürütülmesinin durdurulacağına içtenlikle inanabilir. Karşımıza çıkan ilk farklı değerlerden 1$’ı bulduğumuz anda.
Gelecekte bir ara bu, yeni bir düğüm sayesinde işe yarayabilir ve çalışacaktır. Dizin Taramayı Atla, uygulaması şu anda üzerinde çalışılıyor, ancak henüz değil.
Şimdilik ilk tüm kayıtlar geri alınacak, benzersizdir ve talep edilen tutar yalnızca onlardan iade edilecektir. Eğer böyle bir şey istiyorsak özellikle üzücü 1 $ = 4ve tabloda yüzbinlerce kayıt var...