ProgramlamaFullstack geliştirici

SQL'de bir hücrede çoklu değerleri depolamak ve analiz etmek için diziler ve dizi benzeri yapılarla nasıl çalışılır ve bu yaklaşım ne zaman makuldür?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Konunun Tarihi

Klasik SQL, bir hücrede birden fazla değer saklamayı öngörmez - ilişkisel model normalizasyon gerektirir. Ancak, günümüz görevlerinde sıkça 'etiket listesi', 'puanlama ölçeği' gibi türler bulunur; burada bir satır seviyesinde birden fazla değerle çalışmak kullanışlıdır. Bazı DBMS’ler (PostgreSQL, Oracle) ARRAY veri türü veya benzeri mekanizmalar sunar.

Sorun

Dizi kullanımı normalizasyon ilkesini ihlal eder, birçok işlemi (filtreleme, güncelleme, indeksleme) zorlaştırır ve ayrıca kodun DBMS'ler arasında taşınabilirliğini azaltır. Ancak, bazı durumlarda uygun veya zorunlu olabilir - örneğin, önbellekleme veya küçük değer listeleri üzerinde hızlı arama için.

Çözüm

  • PostgreSQL’de dizi desteği yerel olarak mevcuttur. Örnek:
CREATE TABLE products ( id SERIAL PRIMARY KEY, tags TEXT[] ); -- Eklemek: INSERT INTO products(tags) VALUES (ARRAY['eco','sale','hot']); -- Dizi üzerinde arama: SELECT * FROM products WHERE 'eco' = ANY (tags);
  • MySQL 5.x'de diziler yoktur, genellikle JSON veya ayırıcı dize ve çözümleme işlevleri kullanılır.
  • Oracle’da - koleksiyonlar, nested table/varray.
  • Optimum analitik görevler için normalizasyon daha iyidir (product_tags adında ilişkili bir ikincil tablo oluşturulması) ve JOIN kullanılması; dizi yalnızca özel durumlarda (performans veya özel gereksinimler) saklanmalıdır.

Anahtar özellikler:

  • Dizi gerçekten gerekli olduğunda ve DBMS bunu destekliyorsa kullanışlıdır.
  • Büyük dizilerde indeksleme ve filtreleme sorunları.
  • DBMS’ler arasında taşınamaz, desteği zorlaştırır.

Kandırmaca Soruları.

Dizinin bireysel elemanlarını indekslemek mümkün mü?

PostgreSQL’de - evet, GIN/GIST indeksleri aracılığıyla:

CREATE INDEX idx_tags ON products USING GIN (tags);

String sütunundaki ayırıcıyla değerin dizide bulunup bulunmadığını nasıl daha hızlı kontrol edelim?

SQL standart olarak bunu yapamaz, genellikle şablonla arama kullanılır:

SELECT * FROM users WHERE ',admin,' like concat('%,',role,',%');

Ama bu yaklaşım güvenilir değil ve yavaştır.

Dizide ne kadar değer saklanabilir ve ne kısıtlar?

Kısıtlama DBMS’e bağlıdır - örneğin PostgreSQL’de, sadece satır boyutuna (1-2 MB) bir kısıtlama vardır.

Tipik Hatlar ve Anti-Paternler

  • "Basitlik" uğruna dizileri bir hücrede tutmak ve analizi zorlaştırmak
  • Ayırıcıları dikkate almadan LIKE üzerinden değer filtrelemek
  • Dizi-satırları üzerindeki benzersizlik ve indekslemeye bel bağlamak

Gerçek Hayattan Bir Örnek

Olumsuz Durum

E-ticaret projesinde ürün etiketlerini bir sütunda virgülle string olarak saklamaya karar verildi. Etiket bazında ürünlerin hızlı araması çok zorlaştı, filtrelemede hatalar oldu ve etiketlerin tekrarı parse hatalarına sebep oldu.

Artılar:

  • "Basit" ve hızlı bir şekilde uygulanabilir

Eksiler:

  • Ölçeklendirme sırasında çok yavaş, sürdürmesi zor, değerlerin benzersizliğini garanti edemez

Olumlu Durum

PostgreSQL’de küçük, değişmez setler (kullanıcı rolleri) için ARRAY ve GIN indeksi kullanıldı. Büyük durumlar için - ayrı bir rol tablosu.

Artılar:

  • İndeks aracılığıyla ARRAY üzerinde hızlı arama
  • Gerekli yerlerde ilişkisel model ile uyumlu kalır

Eksiler:

  • Taşınamaz, DBMS'in gelişmiş özelliklerini bilmek gerekir