Web Geliştirme

PostgreSQL mi MySQL mi: JSON İndeksleme, Destek Takvimi ve Kırıcı Değişiklikler

28 Dec 2025
12 dakika okuma
İninia Teknoloji
40

PostgreSQL ve MySQL arasındaki seçim 2026'da artık özellik listesiyle yapılmıyor; ikisi de olgun. Kararı iki şey veriyor: veri modelinizin şekli (JSON ağırlıklı mı, ilişkisel mi, coğrafi mi) ve ekibinizin operasyon alışkanlığı. Bu yazı, iki tarafın gerçekten farklılaştığı beş noktayı, MySQL 8.4 ve 9.0 ile gelen kırıcı değişiklikleri ve Laravel tarafında davranış farkı üreten yerleri veriyor. Sürüm bağlamı: 25 Eylül 2026 itibarıyla PostgreSQL 18 güncel majör, MySQL tarafında 8.4 ve 9.7 LTS sürümleri var ve MySQL 8.0, 21 Nisan 2026'da Premier Support'tan çıkıp Sustaining Support kapsamına girdi.

Destek takvimi: kararı bu tablo daraltıyor

PostgreSQL İlk yayın Destek sonu
1825 Eylül 202514 Kasım 2030
1726 Eylül 20248 Kasım 2029
1614 Eylül 20239 Kasım 2028
1430 Eylül 202112 Kasım 2026 — iki ay kaldı

PostgreSQL'in politikası net: her majör sürüm ilk yayınından itibaren beş yıl destekleniyor (bkz. PostgreSQL Versioning Policy). Bu, yükseltme planınızı takvime bağlamanızı kolaylaştırıyor. PostgreSQL 14 üzerinde çalışan bir üretim sisteminiz varsa yükseltme penceresi kapanıyor.

MySQL tarafında model farklı: LTS ve Innovation sürümleri ayrışıyor ve Oracle'ın destek kademeleri (Premier, Extended, Sustaining) devreye giriyor. Bugün önerilen hat 8.4 LTS veya 9.7 LTS.

MySQL 8.4 ve 9.0 kırıcı değişiklikleri: yükseltmeden önce bunları kontrol edin

Bu iki sürümün getirdiği değişiklikler, eski uygulamaları sessizce kırabilecek türden:

  • mysql_native_password. MySQL 8.4.0'dan itibaren varsayılan olarak devre dışı; açmak için sunucuyu --mysql-native-password=ON ile başlatmanız veya [mysqld] bölümüne eklemeniz gerekiyor. MySQL 9.0.0'da sunucu tarafında tamamen kaldırıldı ve sunucu, CLIENT_PLUGIN_AUTH yeteneği olmayan eski istemcilerin mysql_native kimlik doğrulama isteklerini reddediyor. default_authentication_plugin değişkeni de kaldırıldı.
  • Eski replikasyon ifadeleri gitti. CHANGE MASTER TO, START SLAVE, STOP SLAVE, SHOW SLAVE STATUS, RESET MASTER, SHOW MASTER STATUS, PURGE MASTER LOGS: hepsi 8.4'te kaldırıldı, yerlerini SOURCE ve REPLICA karşılıkları aldı. Otomasyon betikleriniz bu komutları kullanıyorsa yükseltmede kırılır.
  • Kaldırılan diğerleri: expire_logs_days, have_ssl / have_openssl, keyring_file ve keyring_encrypted_file eklentileri (component karşılıklarına geçildi), authentication_fido (yerine authentication_webauthn), mysql_upgrade, mysqlpump, mysql_ssl_rsa_setup, FLUSH HOSTS.
  • restrict_fk_on_non_standard_key varsayılan ON. Standart dışı foreign key tanımları artık reddediliyor. Eski şemalarda bu, migration'ın patlaması demek.
Yükseltmeden önce yapılacak tek en yararlı iş: uygulamanızın bağlandığı kullanıcıların plugin sütununu kontrol edin (SELECT user, host, plugin FROM mysql.user;). Hâlâ mysql_native_password görüyorsanız, kullanıcıları caching_sha2_password'a geçirmeden yükseltmeyin. PHP istemci sürümünüzün bunu desteklediğini de doğrulayın.

JSON: burada fark özellik değil, indekslenebilirlik

Bu, iki veritabanı arasındaki en büyük pratik fark ve karar verdiren yer.

PostgreSQL tarafında jsonb ayrıştırılmış ikili biçimde saklanıyor, yeniden ayrıştırma gerekmediği için işlenmesi hızlı ve indekslenebiliyor. İki GIN operatör sınıfı var ve seçim önemli:

  • jsonb_ops (varsayılan) — anahtar varlık operatörleri ?, ?|, ?&, içerme operatörü @> ve jsonpath eşleştirme @?, @@ destekleniyor.
  • jsonb_path_ops: anahtar varlık operatörlerini desteklemiyor, ama @>, @? ve @@ çalışıyor. Dokümandaki karşılaştırma net: aynı veri üzerinde genellikle çok daha küçük ve özellikle sık geçen anahtarlar içeren sorgularda arama özgüllüğü daha iyi.

Uyarı: jsonb_path_ops, değer içermeyen yapılar için ({"a": {}} gibi) indeks girdisi üretmiyor; bu tür sorgular tam indeks taramasına düşüyor.

MySQL tarafında kural tek cümle: "JSON columns cannot be indexed directly." Çözüm bir generated column tanımlayıp onu indekslemek ya da JSON_VALUE() ile fonksiyonel indeks kurmak. Diziler için multi-valued index var (CAST(... AS ... ARRAY)) ve optimizer bunu MEMBER OF(), JSON_CONTAINS(), JSON_OVERLAPS() ile kullanıyor.

Ama kısıt listesi uzun: yalnızca InnoDB, indeks başına tek multi-valued key part, ASC/DESC yok, primary key olamaz, covering index olamaz, range ve index-only scan yok, foreign key'de kullanılamaz, ve oluşturma ALGORITHM=COPY ile yapılıyor (yani çevrimiçi oluşturma yok — büyük tabloda kilit) (bkz. MySQL 8.4 Reference Manual, CREATE INDEX).

Karar kuralı: veri modelinizin önemli bir kısmı JSON içinde yaşayacak ve o alanlara göre sorgulayacaksanız PostgreSQL. JSON'u yalnızca nadiren okunan bir metadata torbası olarak kullanıyorsanız fark önemsiz.

PostgreSQL 18 neyi değiştirdi

25 Eylül 2025'te yayımlanan PostgreSQL 18'in basın kitindeki somut başlıklar:

  • Asenkron I/O (AIO) alt sistemi. Her I/O isteğinin bitmesini sırayla beklemek yerine birden fazla isteği eşzamanlı gönderiyor. Basın kiti belirli senaryolarda 3 kata kadar performans kazancından söz ediyor; kapsam sequential scan, bitmap heap scan ve vacuum.
  • Majör sürüm yükseltmesinde planner istatistiklerinin korunması. Bu, yükseltme sonrası "her şey yavaşladı" döneminin en büyük sebebini ortadan kaldırıyor. pg_upgrade ayrıca paralel işleme ve yeni bir --swap bayrağı aldı.
  • Skip scan. Çok sütunlu B-tree indekslerinde, öndeki sütunlardan birinde = koşulu olmayan sorgular artık indeksten yararlanabiliyor.
  • Virtual generated columns: değeri saklamak yerine sorgu zamanında hesaplıyor.
  • uuidv7(): zaman damgasına göre sıralı rastgele UUID. Birincil anahtar olarak UUID kullanan şemalarda indeks parçalanmasını azaltıyor (bkz. PostgreSQL 18 Press Kit).
  • OAuth 2.0 kimlik doğrulama ve temporal constraints (PRIMARY KEY/UNIQUE için WITHOUT OVERLAPS, FOREIGN KEY için PERIOD).

Son madde, tarih aralığı çakışmasını uygulama katmanında kontrol eden herkesi ilgilendiriyor: rezervasyon, vardiya planlama, fiyat dönemi gibi modellerde çakışma kontrolü artık veritabanı kısıtı olarak tanımlanabiliyor.

VACUUM: PostgreSQL'i seçiyorsanız bu dört şeyi bilmek zorundasınız

MVCC'nin bedeli vacuum. Resmî doküman dört nedeni sayıyor ve dördü de operasyonel:

  1. Güncellenen veya silinen satırların kapladığı disk alanını geri kazanmak.
  2. Sorgu planlayıcının kullandığı veri istatistiklerini güncellemek.
  3. Index-only scan'i hızlandıran görünürlük haritasını (visibility map) güncellemek.
  4. Transaction ID veya multixact ID wraparound nedeniyle çok eski verinin kaybını önlemek.

Dördüncü madde teorik değil. Yoğun yazma yapan, autovacuum'u yetişemeyen bir sistemde veritabanı kendini yazmaya kapatabiliyor. Üretime PostgreSQL alıyorsanız ilk günden pg_stat_user_tables üzerinden n_dead_tup ve last_autovacuum izleyin. MySQL/InnoDB'de karşılık gelen bir kavram yok; bu, MySQL'in operasyonel olarak daha az sürpriz üretmesinin başlıca sebebi.

Laravel tarafında davranış farkı üreten iki yer

Aynı Eloquent kodu iki veritabanında farklı davranıyor ve bunlar test ortamı SQLite, üretim MySQL olan projelerde geç fark ediliyor.

ILIKE yalnızca PostgreSQL'de var. Resmî doküman açık: "This is not in the SQL standard but is a PostgreSQL extension." MySQL'de büyük-küçük harf duyarsız arama collation'a bağlı (varsayılan sunucu collation'ı utf8mb4_0900_ai_ci, yani zaten duyarsız). Veritabanından bağımsız yazmak için Laravel'in whereLike metodunu kullanın; dokümanına göre bu metotlar "database-agnostic" bir yol sunuyor, varsayılan olarak büyük-küçük harf duyarsız çalışıyor ve caseSensitive: true argümanı alıyor. Bir sınır var: duyarlı arama seçeneği SQL Server'da desteklenmiyor (bkz. PostgreSQL 18, Pattern Matching ve Laravel 12, Query Builder).

insertGetId PostgreSQL'de sütun adı bekliyor. Laravel dokümanı bunu açıkça yazıyor: PostgreSQL kullanırken insertGetId otomatik artan sütunun id adında olmasını bekliyor; farklı bir sekanstan kimlik almak istiyorsanız sütun adını ikinci parametre olarak geçirmeniz gerekiyor. id yerine uuid veya kayit_no kullanan eski şemalarda bu, MySQL'de çalışıp PostgreSQL'de patlayan bir satır.

Karar tablosu

Durum Seçim
Veri modelinin önemli kısmı JSON ve o alanlara göre sorgulanacakPostgreSQL
Coğrafi sorgu gerekiyorPostgreSQL (PostGIS)
Tarih aralığı çakışması bir iş kuralıPostgreSQL 18 (temporal constraints)
Ekip MySQL operasyonunu biliyor, veri modeli klasik ilişkiselMySQL 8.4 LTS
Yönetilen hizmet alınacak ve maliyet belirleyiciSağlayıcı fiyatını karşılaştırın; ikisi de her büyük bulutta var
Mevcut sistem MySQL 8.0'daÖncelik göç değil, LTS'e yükseltme. 8.0 Premier Support'tan çıktı.

Sırada ne var

İki komut çalıştırın. MySQL'deyseniz SELECT user, host, plugin FROM mysql.user; ile kimlik doğrulama eklentilerini kontrol edin; hâlâ mysql_native_password varsa yükseltme yolunuz kapalı demektir. PostgreSQL'deyseniz SELECT version(); ile majör sürümü ve pg_stat_user_tables üzerinden ölü satır sayısını kontrol edin.

Göç kararı verdiyseniz, en pahalı kalem şema dönüşümü değil, uygulama katmanındaki ham SQL sorguları oluyor. Bu işi planlamak için PostgreSQL sayfamıza bakabilir, altyapı tarafı için DevOps ve altyapı sayfasını inceleyebilir, kapsam çıkarmak için proje fiyat hesaplama aracını kullanabilirsiniz.

Sürüm ve davranış bilgileri 25 Eylül 2026 tarihinde birincil kaynaklardan doğrulanmıştır: postgresql.org sürümleme politikası ve PostgreSQL 18 basın kiti, PostgreSQL 18 dokümanı (JSON tipleri, rutin vacuum, desen eşleştirme), mysql.com EOL duyurusu, MySQL 8.4 Reference Manual "What Is New" bölümü, MySQL 9.0.0 sürüm notları, MySQL 8.4 indeks dokümanı ve Laravel sorgu oluşturucu dokümanı. Performans iddiaları projelerin kendi yayımladığı ölçümlerdir ve sizin iş yükünüze doğrudan aktarılamaz.

Bu konuda bir yazılım projesi mi planlıyorsunuz?

Projenizi birlikte analiz edip teknik yol haritasını çıkarabiliriz. Ücretsiz keşif görüşmesi için hemen yazın.

İninia Teknoloji

İstanbul Teknik Üniversitesi ARI Teknokent'te kurulu Ininia Teknoloji, 12+ yıllık deneyimle AR/VR, yapay zeka ve mobil uygulama alanlarında yenilikçi çözümler sunmaktadır.

Projeniz için profesyonel destek mi arıyorsunuz?

12+ yıllık deneyimimizle dijital dönüşümünüzü hızlandıralım.

Ücretsiz Görüşme Talep Et