jekcms veritabanı, içerik, kullanıcılar, medya ve ayarları modellemek için yaklaşık iki düzine tablo kullanır — ayrı bir taksonomi katmanı, WordPress tarzı bir options tablosu yoktur. Gönderi meta verilerini anahtar-değer tablosunda saklamak gibi bazı kararlar, ham sorgu performansının önünde esnekliği tercih eder.
Merkezi tablo, blog gönderilerini ve sayfaları tek bir tabloda type sütunuyla saklayan posts'tur — bu sütun açık uçlu bir özel içerik türleri kümesi değil, ENUM('post', 'page')'dir. Bu, şemayı basit tutar: kategori ve etiket ilişkileri, yorumlar, oylar ve SEO meta verisi, satır bir blog gönderisi mi yoksa statik bir sayfa mı olduğuna bakılmaksızın tek bir posts.id'ye işaret eder. Ödün, çoğu içerik sorgusunun bir WHERE type = 'post' koşulu taşımasıdır; bu yüzden type bir taramaya güvenmek yerine kendi indeksine sahiptir.
Gönderi Meta Verisi: Esneklik mi Performans mı?
Gönderi meta verisi, posts.id'ye bağlı bir anahtar-değer tablosu olan post_meta'da yaşar. Bu tasarım esnekliği en üst düzeye çıkarır — yeni bir meta alanı eklemek şema değişikliği gerektirmez — ancak bilinen bir performans maliyeti vardır: bir gönderi ve meta verisini almak her zaman ya ikinci bir sorgu ya da bir JOIN gerektirir. jekcms bunu, gönderi başına bir sorgu yerine bir grup gönderi ID'si için meta veriyi tek bir sorguda toplu yükleyerek hafifletir; böylece listeleme sayfaları bu maliyeti N kez ödemez.
Settings Tablosu: Site Genelinde Yapılandırma
settings tablosu, site genelindeki yapılandırmayı gruplanmış anahtar-değer satırları olarak saklar — her satırın bir group'u, bir key'i, tipli bir value'su ve bir autoload bayrağı vardır. Autoload olarak işaretlenmiş satırlar bootstrap sırasında tek bir sorguda belleğe çekilir; bu yüzden sık okunan ayarlar (site adı, aktif tema, önbellek bayrakları) istek başına ek maliyet getirmez. Nadiren okuduğunuz ayarlar autoload'ı atlayıp ihtiyaç halinde çekilebilir.
Büyük Kurulumlar İçin Sorunlu Tablolar
Büyük kurulumlarda performans sorunlarına en çok yol açması muhtemel tablo post_meta'dır — varsayılan şema post_id ve meta_key'i tek bir bileşik indeks yerine ayrı ayrı indeksler; bu yüzden belirli bir gönderide belirli bir meta anahtarını aramak yine de tek bir indekse çarpmak yerine iki indeksi kesiştirmek zorunda kalır. Ağır meta kullanımı olan sitelerde (SEO alanları, özel alanlar, revizyon verisi) bileşik bir indeks eklemek kendi başınıza yapmaya değer bir şeydir; varsayılan olarak orada değildir. Dikkat edilmesi gereken diğer tablo sessions'tır — eski oturumlar periyodik olarak temizlenmezse satırlar birikir.
Tablo Listesi
jekcms'in şeması, WordPress tarzı bir içerik/taksonomi/meta ayrımı yerine amaca göre düzenlenmiş yaklaşık iki düzine tablodan oluşur:
Icerik: posts, post_meta, categories, tags,
post_categories, post_tags, comments, media
SEO ve etkilesim: seo_meta, post_votes, post_revisions
Kullanicilar ve erisim: users, sessions, api_tokens, blocked_ips
Site yapisi: settings, themes, menus, menu_items, redirects
Otomasyon: scheduled_tasks, automation_logs,
social_queue, analytics_cache, newsletter_subscribers
Ayrı bir content_queue tablosu, temel şemaya değil içerik sihirbazının kendi kurulum adımına eklenir — yalnızca bu özelliği kullandıysanız mevcuttur.
Büyüme Kalıpları
- İçerik tabloları doğrusal büyür — ayda 30 gönderi
posts'a ~30 satır, her gönderinin kullandığı meta anahtarı sayısı kadar dapost_meta'ya satır ekler mediatablosu her küçük resim boyutu için ayrı bir satır oluşturmaz — her yükleme tek bir satırdır ve üretilen boyut varyantları (thumbnail'den Open Graph'a yedi tane) aynı satırdaki birthumbnailssütununda JSON olarak saklanırsessionsve dosya tabanlı sayfa önbelleği girişleri periyodik temizlik olmadan sınırsız büyür
posts Tablosu, Sadeleştirilmiş
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
author_id INT UNSIGNED NOT NULL,
title VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL,
content LONGTEXT,
type ENUM('post','page') NOT NULL DEFAULT 'post',
status ENUM('draft','pending','published','scheduled','trash') DEFAULT 'draft',
visibility ENUM('public','private','password') DEFAULT 'public',
published_at DATETIME NULL,
content_modified_at DATETIME NULL,
UNIQUE KEY uk_slug (slug),
KEY idx_status (status),
KEY idx_type (type),
KEY idx_published (published_at),
FULLTEXT KEY ft_search (title, content)
);
Slug'ın tüm tablo genelinde benzersiz olduğuna, tür bazında sınırlı olmadığına dikkat edin — bir gönderi ve bir sayfa aynı slug'ı paylaşamaz; bu da önceden içerik türünü bilmeye gerek kalmadan URL çözümlemesini belirsizlikten arındırır. content_modified_at özellikle belirtmeye değer: genel updated_at zaman damgasından ayrı izlenir, tam olarak rutin sistem dokunuşlarının (görüntülenme sayaçları, arka plan SEO geçişleri) site haritanızda veya yapısal verinizde gerçek bir içerik güncellemesi gibi görünmemesi için.
En Etkili İsteğe Bağlı İndeks
ALTER TABLE post_meta ADD INDEX idx_post_meta_lookup (post_id, meta_key);
Bu, gönderilen şemanın bir parçası değildir; ancak on binlerce meta satırı olan bir sitede eklemek genellikle mevcut en ucuz tek sorgu-performansı kazancıdır — yerleşik idx_post ve idx_key indeksleri aramayı zaten büyük ölçüde daraltır, bu yüzden bileşik indeks eksik bir indeksi düzeltmekten çok bir incelik katmandır.
Neden JSON Sütunlar Yerine Anahtar-Değer Tablosu?
Paylaşımlı hosting sıklıkla sınırlı ya da hiç JSON desteği olmayan MySQL 5.6/5.7 veya MariaDB sürümleri çalıştırır. post_meta'daki anahtar-değer kalıbı bunların hepsinde aynı şekilde çalışır; bu, müşterinin hostunun sunduğu veritabanı sürümü ne olursa olsun değişiklik yapılmadan çalışması gereken bir ürün için önemlidir. jekcms'in verinin her iki tarafını da kontrol ettiği yerlerde — bir media satırındaki boyut varyantları gibi — gerçek bir JSON sütunu kullanılır, çünkü bu veri keyfi bir üçüncü taraf meta verisi değildir ve aynı geriye dönük uyumluluk garantisine ihtiyaç duymaz.
Yedekler ve Şema Değişiklikleri
- jekcms şema değişikliklerini kendi veritabanı tablosunda izlemez — yönetilecek bir
migrationstablosu yoktur. Kurulu sürüm birversion.jsondosyasında kaydedilir; mevcut siteler için şema değişiklikleri, numaralı bir migration çalıştırıcısı yerine imzalı manifest tabanlı güncelleyici aracılığıyla uygulanan normal çekirdek güncellemelerinin bir parçası olarak gelir. - Canlı bir yedekleme sırasında InnoDB tablolarını kilitlememek için
mysqldumpdışa aktarımlarında--single-transactionkullanın content_queue, mevcutsa, bir parti işlenmesi tamamlandıktan sonra güvenle temizlenebilir
Listeleme Sayfalarında N+1 Sorgularından Kaçınma
20 gönderiyi meta verileriyle birlikte göstermenin saf yolu, gönderiler için bir sorgu artı her gönderinin meta verisi için gönderi başına bir sorgudur — en az 21 sorgu, her gönderinin birden fazla meta anahtarına ihtiyacı varsa daha da fazla. jekcms bunu önce tüm gönderi ID'lerini yükleyerek, ardından o toplu grup için ilgili tüm post_meta satırlarını tek bir sorguda çekerek önler:
SELECT post_id, meta_key, meta_value
FROM post_meta
WHERE post_id IN (?, ?, ?, ...)
ORDER BY post_id, meta_key;
Sonuç, post_id'ye göre anahtarlanan bellek içi bir diziye gruplanır; böylece bir listeleme sayfasının meta maliyeti, sayfada kaç gönderi olursa olsun iki sorguda kalır — biri gönderiler için, biri tüm meta verileri için.