Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MenzeletDB

MenzeletDB, yüksek performanslı, sütun tabanlı (columnar) bir SQL veritabanı sistemidir.

Geleneksel veritabanlarının satır tabanlı hantallığı yerine, analitik sorgularda (OLAP) yüksek hızda sonuç veren modern bir depolama ve sorgu motoru felsefesini benimser.

Öne Çıkan Özellikler

  • Tam SQL desteğiSELECT, WHERE, ORDER BY, JOIN, GROUP BY, CTE, alt sorgu…
  • 200+ yerleşik fonksiyon — Zengin aggregate, scalar, window, tarih/saat fonksiyonları
  • 10 JOIN türü — INNER, LEFT/RIGHT/FULL OUTER, CROSS, NATURAL, LEFT/RIGHT SEMI, LEFT/RIGHT ANTI
  • Güvenli kimlik doğrulama — Şifreler hash + salt ile korunur, zamanlama saldırısı önlemi
  • Rol tabanlı erişim kontrolü (RBAC) — Hassas yetki yönetimi
  • Çok dilli arayüz — Türkçe, İngilizce, İspanyolca
  • WAL koruması — Write-Ahead Log ile çökme kurtarma
  • Dil duyarlı sıralama — Türkçe ı/i ayrımı, Unicode collation
  • Hiyerarşik ad alanı — Farklı veritabanlarında aynı isimli tablolar
  • Çoklu platform — Windows, Linux, macOS

Temel Kavramlar

KavramAçıklama
Veritabanı (DB)Tabloları gruplayarak organize eden mantıksal birim. Dosya sisteminde bir klasördür (data/<db_adı>/).
TabloSatır ve sütunlardan oluşan veri kümesi. Sıkıştırılmış sütun tabanlı formatta saklanır.
FlushBellekteki yazma tamponunun diske yazılması. Otomatik veya COMPACT komutuyla tetiklenir.
WALHer yazma işleminin önce kaydedildiği çökme kurtarma günlüğü.
İndeksBelirli sütunlarda hızlı arama yapısı (aralık veya eşitlik sorguları için).
KatalogTablo şema meta verilerini yöneten sistem.

Bu Kitap Hakkında

Bu dokümantasyon aşağıdaki bölümlerden oluşur:

  • Başlangıç — Kurulum, ilk çalıştırma ve istemci bağlantısı
  • SQL Referansı — Veritabanı, tablo, sütun tipleri, veri işlemleri, fonksiyonlar, JOIN’ler, indeksler
  • Yönetim — Kimlik doğrulama, kullanıcı/rol yönetimi, konfigürasyon, yedekleme
  • Operasyon — Derleme, Docker, izleme (monitoring)
  • Ekler — Diğer veritabanlarından göç, sorun giderme, komut referansı

Kurulum

Kurulum Sihirbazı ile Kurulum (Önerilen)

En kolay kurulum yöntemi, grafiksel kurulum sihirbazını (menzelet-setup) kullanmaktır. Bu araç adım adım sizi yönlendirir ve tüm yapılandırmayı otomatik yapar.

İndirme

GitHub Releases sayfasından işletim sisteminize uygun paketi indirin:

PlatformDosya
Windowsmenzelet-setup.exe
Linuxmenzelet-setup-<versiyon>-linux-x86_64.tar.gz

Çalıştırma

Windows:

menzelet-setup.exe

Linux:

tar xzf menzelet-setup-*.tar.gz
chmod +x menzelet-setup
./menzelet-setup

Sihirbaz Adımları

Kurulum sihirbazı şu adımları içerir:

  1. Hoş Geldiniz — Karşılama ekranı
  2. Dil Seçimi — Türkçe, İngilizce veya İspanyolca
  3. SA Şifresi — Süper kullanıcı (sa) şifresi belirleme
  4. Özet — Seçimlerin onayı
  5. İlerleme — Yapılandırma dosyası oluşturma, master DB hazırlama, servis kurulumu
  6. Tamamlandı — Kurulum sonucu

Varsayılan Dizinler

Kurulum sihirbazı aşağıdaki varsayılan dizinleri kullanır:

BileşenWindowsLinux
VeriC:\ProgramData\MenzeletDB\data/var/lib/menzelet/data
YapılandırmaC:\Program Files\MenzeletDB\menzelet.toml/etc/menzelet/menzelet.toml
BinaryC:\Program Files\MenzeletDB/opt/menzelet

Docker ile Hızlı Başlangıç

Geliştirme ortamı kurmadan MenzeletDB’yi hemen denemek için Docker kullanın:

# Docker image oluştur (repo kök dizininden)
docker build -t atifdag/menzelet:latest -f build/docker/Dockerfile .

# Tek komutla başlat
docker run -d \
  --name menzelet \
  -p 4600:4600 \
  -e MENZELET_SA_PASSWORD=güçlüŞifre123 \
  atifdag/menzelet:latest

# İstemci ile bağlan
docker exec -it menzelet /opt/menzelet/menzelet-cli 127.0.0.1:4600

Docker Compose ile başlatma ve detaylı Docker yapılandırması için bkz: Docker

İlk Çalıştırma

MenzeletDB’yi ilk kez çalıştırmanın iki yolu vardır: Kurulum Sihirbazı (önerilen) veya Docker.

Kurulum Sihirbazı ile (Önerilen)

Kurulum sihirbazını (menzelet-setup) kullandıysanız, tüm yapılandırma ve bootstrap işlemleri otomatik olarak tamamlanmıştır. Sunucuyu doğrudan başlatabilirsiniz:

Windows:

"C:\Program Files\MenzeletDB\menzelet-server.exe"

Linux:

/opt/menzelet/menzelet-server

Veya servis olarak kurulduysa:

Linux (systemd):

sudo systemctl start menzelet
sudo systemctl status menzelet

Windows (servis):

Start-Service MenzeletDB
Get-Service MenzeletDB

Kurulum sihirbazı hakkında detaylı bilgi için bkz: Kurulum


Konsol ile Bootstrap

Kurulum sihirbazı kullanmadan, sunucuyu doğrudan çalıştırarak da ilk kurulumu yapabilirsiniz.

Windows:

"C:\Program Files\MenzeletDB\menzelet-server.exe" --config "C:\Program Files\MenzeletDB\menzelet.toml"

Linux:

/opt/menzelet/menzelet-server --config /etc/menzelet/menzelet.toml

Bootstrap (İlk Kurulum)

Sunucu ilk kez başlatıldığında data/master/ dizini otomatik oluşturulur. Bu sırada konsoldan sa (süper kullanıcı) şifresi istenir:

menzelet başlıyor...
Konfigürasyon yüklendi: menzelet.toml
İlk kurulum: sa şifresi belirleniyor...
sa şifresi: ________
sa şifresi (tekrar): ________
master DB oluşturuldu.
TCP sunucu başladı: 127.0.0.1:4600

Önemli: sa şifresini güvenli bir yerde saklayın. Bu şifre tek yönlü hash olarak saklanır ve geri alınamaz.

Bootstrap Sırasında Neler Olur?

  1. data/ kök dizini kontrol edilir, yoksa oluşturulur
  2. data/master/ klasörü oluşturulur
  3. Konsoldan sa şifresi iki kez alınır (doğrulama)
  4. 16-byte rastgele salt üretilir
  5. Şifre hash’lenerek güvenli biçimde saklanır
  6. Sistem Parquet dosyaları seed verileriyle oluşturulur:
Dosyaİçerik
mnz_users.parquetsa kullanıcısı (hash + salt)
mnz_roles.parquet4 yerleşik rol
mnz_user_roles.parquetsamnz_sys_admin eşlemesi
mnz_role_permissions.parquetRol-permission eşlemeleri
mnz_tables.parquetTablo katalog meta verileri (boş)

Normal Başlatma

İlk kurulumdan sonraki her başlatmada:

  1. data/master/ dizini tespit edilir
  2. Sistem tabloları kaydedilir
  3. Katalog meta verileri yüklenir (mnz_tables.parquet + catalog.delta)
  4. Kullanıcı veritabanları taranır ve tabloları kaydedilir
  5. WAL dosyaları kontrol edilir; varsa kurtarma (replay) yapılır
  6. Bloom filter dosyaları yüklenir
  7. Hiyerarşik ad alanı oluşturulur
  8. Bağlantı havuzu ön-ısınma (warm_up) yapılır
  9. TCP sunucu başlatılır
TCP sunucu başladı: 127.0.0.1:4600

Docker ile İlk Çalıştırma

Docker kullanılırken sa şifresi ortam değişkeniyle belirlenir:

docker run -d \
  --name menzelet \
  -p 4600:4600 \
  -e MENZELET_SA_PASSWORD=güçlüŞifre123 \
  atifdag/menzelet:latest

Not: MENZELET_SA_PASSWORD ortam değişkeni yalnızca ilk kurulumda (bootstrap) kullanılır. Sonraki başlatmalarda etkisizdir.

İstemci Bağlantısı

menzelet-cli

MenzeletDB istemcisi, interaktif bir komut satırı arayüzüdür. Sunucuyla TCP üzerinden length-prefix framing protokolü ile haberleşir.

Bağlanma

# Geliştirme modunda:
cargo run -p menzelet_cli -- 127.0.0.1:4600

# Release modunda:
./target/release/menzelet-cli 127.0.0.1:4600

# Varsayılan adres (menzelet.toml'dan okunur):
./target/release/menzelet-cli

# Docker container içinden:
docker exec -it menzelet /opt/menzelet/menzelet-cli 127.0.0.1:4600

CLI Bayrakları

BayrakAçıklama
--lang <dil>Arayüz dilini geçersiz kılar (tr, en, es)
--pingSunucu sağlık kontrolü (PING/PONG), hemen çıkar
--helpKullanım bilgisi gösterir

Bağlantı Başarılı Olduğunda

menzelet v0.2.0
Bağlandı: 127.0.0.1:4600
Kimlik doğrulaması için: LOGIN <kullanıcı_adı> <parola>
menzelet>

Kimlik Doğrulama

Her yeni bağlantıda LOGIN komutu zorunludur. Kimlik doğrulamadan önce SQL veya INDEX komutları reddedilir.

menzelet> LOGIN sa güçlüŞifre123
Giriş başarılı. Hoş geldiniz, sa!
menzelet>

Hatalı şifrede bağlantı otomatik olarak kapatılır (güvenlik nedeniyle).

Hızlı Başlangıç Senaryosu

Bağlantı kurduktan ve giriş yaptıktan sonra temel işlemler:

-- Veritabanı oluştur
CREATE DATABASE test_db

-- Veritabanını seç
USE test_db

-- Tablo oluştur
CREATE TABLE musteriler (id INT NOT NULL, ad VARCHAR, sehir VARCHAR)

-- Veri ekle
INSERT INTO musteriler VALUES (1, 'Ahmet', 'İstanbul')
INSERT INTO musteriler VALUES (2, 'Mehmet', 'Ankara')
INSERT INTO musteriler VALUES (3, 'Ayşe', 'İzmir')

-- Sorgula
SELECT * FROM musteriler WHERE sehir = 'İstanbul'

-- Türkçe sıralama
SELECT ad, sehir FROM musteriler ORDER BY collate(ad)

Bağlantıyı Kapatma

menzelet> EXIT

veya QUIT komutu.

Protokol Notu

MenzeletDB, length-prefix framing protokolü kullanır (her mesajın başına 4 byte u32 big-endian uzunluk eklenir). Bu nedenle:

  • telnet ve nc (netcat) gibi satır tabanlı araçlar kullanılamaz
  • Her zaman menzelet-cli ikili dosyası kullanılmalıdır
  • Sağlık kontrolü için: menzelet-cli --ping

Veritabanı (DATABASE)

MenzeletDB klasör bazlı yaklaşım kullanır: her veritabanı dosya sisteminde bir klasördür (data/<db_adı>/).

Oluşturma (CREATE DATABASE)

CREATE DATABASE musteri_db
  • data/musteri_db/ klasörü oluşturulur
  • Veritabanı adı küçük harf, boşluksuz olmalıdır
  • Aynı isimli veritabanı varsa hata döner

Birden fazla veritabanı oluşturma:

CREATE DATABASE satis_db
CREATE DATABASE analitik_db
CREATE DATABASE test_db

Seçme (USE)

USE musteri_db
  • Sonraki tüm tablo işlemleri seçilen veritabanı üzerinde çalışır
  • USE komutu çalıştırılmadan tablo işlemleri yapılamaz (master DB dışında)

Listeleme (SHOW DATABASES)

SHOW DATABASES

Örnek çıktı:

master
musteri_db
satis_db
analitik_db

Silme (DROP DATABASE)

DROP DATABASE test_db
  • data/test_db/ klasörü ve içindeki tüm Parquet/WAL/flush dosyaları silinir
  • Bu işlem geri alınamaz

Koruma Kuralları

KuralÖrnekSonuç
master DB silinemezDROP DATABASE masterHata
Aktif bağlantısı olan DB silinebilirDROP DATABASE musteri_dbBaşarılı (dikkatli kullanın)

Güncelleme

MenzeletDB’de veritabanı adı değiştirme (ALTER DATABASE RENAME) komutu desteklenmez.

Alternatif yöntem:

-- 1. Yeni veritabanı oluştur
CREATE DATABASE musteri_db_v2

-- 2. Yeni veritabanında tabloları oluştur ve verileri taşı
USE musteri_db_v2
CREATE TABLE siparisler (id INT NOT NULL, tutar FLOAT)
INSERT INTO siparisler SELECT * FROM menzelet.musteri_db.siparisler

-- 3. Eski veritabanını sil
DROP DATABASE musteri_db

Hiyerarşik ad alanı: Tablolara tam nitelikli isimle de erişilebilir: menzelet.<db_adı>.<tablo_adı>. Bu sayede farklı veritabanlarındaki tablolara USE komutu olmadan erişmek mümkündür.

Dosya Sistemi Eşlemesi

SQL KomutuDosya Sistemi İşlemi
CREATE DATABASE xmkdir data/x/
DROP DATABASE xrmdir data/x/ (tüm içerikle birlikte)
USE xSession’ın aktif DB’sini değiştir
SHOW DATABASESdata/ altındaki klasörleri listele

master Veritabanı

master, MenzeletDB’nin sistem veritabanıdır. İlk kurulumda (bootstrap) otomatik oluşturulur ve silinemez.

İçindeki sistem tabloları:

Tabloİçerik
mnz_usersKullanıcılar (şifreler hash + salt ile korunur)
mnz_rolesRoller (4 yerleşik + kullanıcı tanımlı)
mnz_user_rolesKullanıcı-rol eşlemeleri
mnz_role_permissionsRol-permission eşlemeleri
mnz_tablesTablo katalog meta verileri

Tablo (TABLE)

Her tablo dosya sisteminde sıkıştırılmış bir dosya olarak saklanır (data/<db_adı>/<tablo_adı>.parquet).

Oluşturma (CREATE TABLE)

Söz dizimi:

CREATE TABLE <tablo_adı> (<sütun1> <tip> [NOT NULL], <sütun2> <tip>, ...)

Temel örnek:

CREATE TABLE urunler (id INT, urun_adi VARCHAR, fiyat FLOAT)

NOT NULL kısıtı ile:

CREATE TABLE siparisler (
    id INT NOT NULL,
    musteri_id INT NOT NULL,
    siparis_tarihi DATE,
    toplam_tutar DECIMAL,
    durum VARCHAR
)

Tüm veri tiplerini gösteren örnek:

CREATE TABLE tip_ornekleri (
    tam_sayi INT,
    buyuk_sayi BIGINT,
    kucuk_sayi SMALLINT,
    minik_sayi TINYINT,
    ondalikli FLOAT,
    ondalikli32 FLOAT32,
    metin VARCHAR,
    mantiksal BOOL,
    tarih DATE,
    zaman_damgasi TIMESTAMP,
    zaman_utc TIMESTAMPTZ,
    sabit_ondalik DECIMAL,
    ikili_veri BLOB,
    benzersiz_id UUID
)

Not: Tip adları büyük/küçük harf duyarsızdır. INT, int, Int — hepsi geçerlidir.

Desteklenen veri tipleri hakkında detaylı bilgi için bkz: Sütun Tipleri

Listeleme (SHOW TABLES)

SHOW TABLES

Aktif veritabanındaki tüm tabloları listeler.

Tablo Şemasını Görüntüleme (DESCRIBE TABLE)

DESCRIBE TABLE urunler
-- veya kısaca:
DESCRIBE urunler

Örnek çıktı:

Column        | Type     | Nullable
--------------+----------+---------
id            | Int32    | NO
urun_adi      | Utf8     | YES
fiyat         | Float64  | YES
aktif         | Boolean  | YES

CLI kısayolu: \d urunler komutu ile aynı sonuç alınabilir.

Silme (DROP TABLE)

DROP TABLE urunler
  • data/<db_adı>/urunler.parquet dosyası silinir
  • İlişkili yardımcı dosyalar (flush, WAL, Bloom filter) da temizlenir
  • Bu işlem geri alınamaz

Koruma Kuralları

KuralÖrnekSonuç
Sistem tabloları silinemezDROP TABLE mnz_usersHata
mnz_ ön ekli tablolar korunurDROP TABLE mnz_rolesHata

Güncelleme (ALTER TABLE)

MenzeletDB aşağıdaki ALTER TABLE işlemlerini destekler:

Sütun Ekleme (ADD COLUMN)

Mevcut bir tabloya yeni bir nullable sütun ekler. Mevcut satırlarda yeni sütun NULL değerini alır.

ALTER TABLE urunler ADD COLUMN stok INT
ALTER TABLE urunler ADD COLUMN aciklama VARCHAR
ALTER TABLE urunler ADD COLUMN olusturma_tarihi TIMESTAMP

NOT NULL + DEFAULT ile Sütun Ekleme (ADD COLUMN NOT NULL DEFAULT)

Mevcut bir tabloya NOT NULL kısıtlı ve varsayılan değerli bir sütun ekler. Mevcut tüm satırlara belirtilen varsayılan değer yazılır.

ALTER TABLE urunler ADD COLUMN durum VARCHAR NOT NULL DEFAULT 'aktif'
ALTER TABLE urunler ADD COLUMN sira INT NOT NULL DEFAULT 0

Not: DEFAULT değeri metin için tek tırnak içinde, sayısal değerler için doğrudan yazılır.

Sütun Silme (DROP COLUMN)

Mevcut bir tablodan sütun siler. Mevcut veri yeniden yazılır.

ALTER TABLE urunler DROP COLUMN eski_sutun

Dikkat: Sistem tablolarının sütunları silinemez.

Sütunu NOT NULL Yapma (SET NOT NULL)

Mevcut bir sütunu NOT NULL kısıtlı olarak işaretler. Mevcut veride NULL değer varsa işlem reddedilir.

ALTER TABLE urunler ALTER COLUMN urun_adi SET NOT NULL

Önemli: Önce tablodaki NULL değerleri temizleyin veya güncelleyin, ardından SET NOT NULL uygulayabilirsiniz.

Tablo Yeniden Adlandırma (RENAME TO)

Mevcut bir tabloyu yeni bir isimle yeniden adlandırır. İlişkili tüm dosyalar da yeniden adlandırılır.

ALTER TABLE urunler RENAME TO malzemeler

Not: İlişkili indeksler yeniden oluşturulmalıdır. Sistem tabloları (mnz_ ön ekli) yeniden adlandırılamaz.

Desteklenmeyen ALTER TABLE İşlemleri

Aşağıdaki işlemler henüz desteklenmez:

-- Bu komutlar çalışmaz:
ALTER TABLE urunler ALTER COLUMN fiyat TYPE BIGINT     -- Tip değişikliği
ALTER TABLE urunler ADD CONSTRAINT pk PRIMARY KEY (id)  -- Kısıt ekleme
ALTER TABLE urunler RENAME COLUMN eski TO yeni          -- Sütun yeniden adlandırma

Dosya Sistemi Eşlemesi

SQL KomutuDosya Sistemi İşlemi
CREATE TABLE t (...)data/<db>/t.parquet oluştur
DROP TABLE tdata/<db>/t.parquet ve ilişkili dosyaları sil
SHOW TABLESAktif veritabanındaki tabloları listele

Tablo Dosya Yapısı

Bir tablonun disk üzerindeki görünümü:

data/musteri_db/
  ├── siparisler.parquet            ← Ana veri dosyası
  ├── siparisler.wal                ← Çökme kurtarma günlüğü
  ├── siparisler.bloom              ← Tekrar kontrol filtresi
  ├── siparisler-flush-0001.parquet ← 1. flush dosyası
  ├── siparisler-flush-0002.parquet ← 2. flush dosyası
  └── urunler.parquet               ← Başka bir tablo

Compaction

Flush dosyalarını ana veri dosyasıyla birleştirmek için:

COMPACT siparisler

Bu işlem:

  1. Tüm flush dosyalarını (siparisler-flush-*.parquet) okur
  2. Base Parquet ile birleştirir
  3. Tek bir yeni base Parquet dosyası yazar
  4. Eski flush dosyalarını siler

Sütun Tipleri

Desteklenen Veri Tipleri

Tip adları büyük/küçük harf duyarsızdır. INT, int, Int — hepsi geçerlidir.

SQL TipiEşdeğerlerBoyutAçıklama
INTINTEGER, INT324 byte32-bit tam sayı (-2^31 … 2^31-1)
BIGINTINT648 byte64-bit tam sayı
SMALLINTINT162 byte16-bit tam sayı (-32768 … 32767)
TINYINTINT81 byte8-bit tam sayı (-128 … 127)
FLOATFLOAT648 byteÇift hassasiyetli ondalıklı sayı
FLOAT324 byteTek hassasiyetli ondalıklı sayı
VARCHARTEXT, STRINGDeğişkenUTF-8 metin
BOOLBOOLEAN1 bittrue / false
DATE4 byteTarih (YYYY-MM-DD)
TIMESTAMP8 byteZaman damgası (mikrosaniye hassasiyeti)
TIMESTAMPTZ8 byteZaman damgası + UTC
DECIMAL16 byte38 basamak, 10 ondalık
BLOBDeğişkenİkili veri
UUID16 byte128-bit benzersiz tanımlayıcı

Tip Eşanlamlıları

Aşağıdaki tip grupları dahili olarak aynı Arrow tipine eşlenir:

  • VARCHAR / TEXT / STRINGUtf8 (performans ve depolama farkı yoktur)
  • INT / INTEGER / INT32Int32
  • BIGINT / INT64Int64
  • FLOAT / FLOAT64Float64
  • BOOL / BOOLEANBoolean

NOT NULL Kısıtı

Sütun tanımlarına NOT NULL eklenebilir:

CREATE TABLE urunler (
    id INT NOT NULL,
    urun_adi VARCHAR NOT NULL,
    fiyat FLOAT
)
  • NOT NULL kısıtı şema meta verilerinde korunur
  • Sunucu yeniden başlatıldığında da geçerli kalır

UUID Sütunları

UUID değerleri 16-byte sabit boyutlu binary olarak saklanır.

UUID Üretimi

MenzeletDB uuid() fonksiyonunu içerir. Bu fonksiyon UUID v4 formatında rastgele bir benzersiz tanımlayıcı üretir ve VARCHAR (metin) tipinde döner:

-- uuid() ile otomatik UUID üretimi
SELECT uuid() AS yeni_id
-- Sonuç: "c4a1f2e8-3b7d-4a9c-8f1e-6d2a5b8c9e0f"

Not: uuid() fonksiyonu metin tipinde değer döner, ancak MenzeletDB UUID sütunlarını binary olarak saklar. Doğrudan INSERT için istemci tarafında dönüşüm gerekebilir.

UUID İndeksleme

UUID sütunlarında Hash ve BTree indeksleme desteklenir.

NULL Davranışı

DurumDavranış
Aggregate fonksiyonlar (SUM, AVG, MIN, MAX)NULL değerleri atlar
COUNT(*)NULL dahil tüm satırları sayar
COUNT(sütun)NULL hariç sayar
COALESCE(a, b, ...)İlk NULL olmayan değeri döner
NULLIF(a, b)a = b ise NULL döner
IS NULL / IS NOT NULLNULL kontrolü
-- NULL kontrolü örnekleri
SELECT * FROM urunler WHERE fiyat IS NOT NULL
SELECT COALESCE(fiyat, 0.0) AS fiyat FROM urunler
SELECT NULLIF(indirimli_fiyat, 0.0) FROM urunler

Tip Dönüşümü (CAST)

-- INT → VARCHAR
SELECT CAST(id AS VARCHAR) FROM urunler

-- VARCHAR → INT
SELECT CAST('42' AS INT)

-- FLOAT → INT (ondalık kısmı kesilir)
SELECT CAST(3.7 AS INT)  -- Sonuç: 3

-- Tarih dönüşümleri
SELECT CAST('2024-01-15' AS DATE)
SELECT CAST('2024-01-15 10:30:00' AS TIMESTAMP)

Veri İşlemleri (DML)

INSERT — Veri Ekleme

Strict Mod (Varsayılan)

Aynı birincil anahtarla tekrar INSERT yapılırsa hata döner. Birincil anahtar ilk sütun değeridir.

INSERT INTO urunler VALUES (1, 'Klavye', 450.00, true)
INSERT INTO urunler VALUES (2, 'Mouse', 250.00, true)
INSERT INTO urunler VALUES (3, 'Monitör', 3500.00, true)

-- Aynı anahtar tekrar eklenirse hata:
INSERT INTO urunler VALUES (1, 'Kulaklık', 200.00, true)
-- Hata: Anahtar zaten mevcut: '1'

Upsert Mod (INSERT OR REPLACE)

Mevcut anahtarı sessizce günceller:

INSERT OR REPLACE INTO urunler VALUES (1, 'Kulaklık', 200.00, true)
-- OK: id=1 satırı 'Kulaklık' olarak güncellendi

Veri Akışı

INSERT → WAL (günlüe yaz) → Bellek tamponu
       → Tampon doldu mu?
          → Evet → Diske flush (sıkıştırılmış dosya)
          → Hayır → Bellekte bekle

SELECT — Veri Sorgulama

Temel Sorgular

-- Tüm satırları getir
SELECT * FROM urunler

-- Belirli sütunlar
SELECT urun_adi, fiyat FROM urunler

-- Koşullu sorgu
SELECT * FROM urunler WHERE fiyat > 100

-- Sıralama
SELECT urun_adi, fiyat FROM urunler ORDER BY fiyat DESC

-- Limit
SELECT * FROM urunler ORDER BY fiyat DESC LIMIT 10

Birden Fazla Koşul

-- AND / OR
SELECT * FROM siparisler WHERE musteri_id = 5 AND durum = 'tamamlandi'
SELECT * FROM urunler WHERE fiyat < 100 OR aktif = false

-- IN listesi
SELECT * FROM urunler WHERE id IN (1, 3, 5, 7)

-- BETWEEN
SELECT * FROM urunler WHERE fiyat BETWEEN 100 AND 500

-- LIKE kalıp eşlemesi
SELECT * FROM urunler WHERE urun_adi LIKE '%Klavye%'

-- IS NULL / IS NOT NULL
SELECT * FROM urunler WHERE fiyat IS NOT NULL

Gruplama ve Toplama

-- Basit gruplama
SELECT musteri_id, COUNT(*) AS siparis_sayisi
FROM siparisler
GROUP BY musteri_id
ORDER BY siparis_sayisi DESC

-- Birden fazla aggregate
SELECT musteri_id,
       COUNT(*) AS siparis_sayisi,
       SUM(tutar) AS toplam,
       AVG(tutar) AS ortalama
FROM siparisler
GROUP BY musteri_id

-- HAVING filtresi
SELECT musteri_id, COUNT(*) AS siparis_sayisi
FROM siparisler
GROUP BY musteri_id
HAVING COUNT(*) > 5

DISTINCT

SELECT DISTINCT musteri_id FROM siparisler
SELECT DISTINCT sehir FROM musteriler ORDER BY collate(sehir)

CASE İfadesi

SELECT urun_adi, fiyat,
    CASE
        WHEN fiyat < 100 THEN 'ucuz'
        WHEN fiyat < 1000 THEN 'orta'
        ELSE 'pahalı'
    END AS fiyat_grubu
FROM urunler

Alt Sorgu (Subquery)

-- WHERE'de alt sorgu
SELECT * FROM urunler
WHERE fiyat > (SELECT AVG(fiyat) FROM urunler)

-- IN ile alt sorgu
SELECT * FROM musteriler
WHERE id IN (SELECT musteri_id FROM siparisler WHERE tutar > 1000)

CTE (Common Table Expression)

WITH aylik_satis AS (
    SELECT date_part('month', tarih) AS ay,
           SUM(tutar) AS toplam
    FROM siparisler
    GROUP BY date_part('month', tarih)
)
SELECT ay, toplam
FROM aylik_satis
WHERE toplam > 10000
ORDER BY ay

UNION

SELECT urun_adi FROM urunler WHERE fiyat < 100
UNION ALL
SELECT urun_adi FROM urunler WHERE aktif = false

-- UNION (tekrarlıları kaldırır)
SELECT sehir FROM musteriler
UNION
SELECT sehir FROM tedarikciler

Dil Duyarlı Sıralama

-- Türkçe alfabetik sıralama (ı, i, ö, ü, ç, ş, ğ düzgün sıralanır)
SELECT isim FROM musteriler ORDER BY collate(isim)

-- Azalan sırada
SELECT urun_adi, fiyat FROM urunler ORDER BY collate(urun_adi) DESC

-- Birden fazla kriter
SELECT isim, sehir FROM musteriler ORDER BY collate(sehir), collate(isim)

collate() fonksiyonu locale-duyarlı sıralama anahtarı üretir. Varsayılan locale menzelet.toml dosyasındaki [collation] default_locale ayarıyla belirlenir.

Türkçe sıralama kuralları:

KuralAçıklama
ç, c’den sonra gelircay < çay < dağ
ğ, g’den sonra gelirgaz < ğül < hal
ı ve i farklı harflerdirışık < istanbul
ö, o’dan sonra gelirordu < öğle < para
ş, s’den sonra gelirsal < şal < tal
ü, u’dan sonra geliruzay < üzüm < vadi

Not: collate() olmadan ORDER BY isim Unicode byte sıralaması kullanır; Türkçe için yanlış sonuç verebilir.

JOIN Sorguları

SELECT s.siparis_id, u.urun_adi, s.miktar
FROM siparisler s
JOIN urunler u ON s.urun_id = u.id

Tüm JOIN türleri ve detaylı örnekler için bkz: JOIN Türleri

UPDATE — Veri Güncelleme

-- Tek sütun güncelle
UPDATE urunler SET fiyat = 500.00 WHERE id = 1

-- Birden fazla sütun
UPDATE urunler SET fiyat = 600.00, aktif = false WHERE id = 2

-- Koşullu güncelleme
UPDATE siparisler SET durum = 'iptal' WHERE toplam_tutar = 0

DELETE — Veri Silme

-- Koşullu silme
DELETE FROM urunler WHERE id = 3

-- Birden fazla koşul
DELETE FROM siparisler WHERE durum = 'iptal' AND tarih < '2024-01-01'

SQL Fonksiyonları

MenzeletDB, 200’den fazla yerleşik SQL fonksiyonu destekler. Ayrıca dil duyarlı sıralama için collate() özel fonksiyonu sunucuya kayıtlıdır.

Aggregate (Toplama) Fonksiyonları

Aggregate fonksiyonlar NULL değerleri atlar (COUNT(*) hariç).

FonksiyonAçıklamaÖrnek
COUNT(*)Tüm satırları sayar (NULL dahil)SELECT COUNT(*) FROM urunler
COUNT(sütun)NULL olmayan satırları sayarSELECT COUNT(fiyat) FROM urunler
SUM(sütun)Sayısal toplamSELECT SUM(fiyat) FROM urunler
AVG(sütun)OrtalamaSELECT AVG(fiyat) FROM urunler
MIN(sütun)Minimum değerSELECT MIN(fiyat) FROM urunler
MAX(sütun)Maksimum değerSELECT MAX(fiyat) FROM urunler
MEDIAN(sütun)Medyan değerSELECT MEDIAN(fiyat) FROM urunler
ARRAY_AGG(sütun)Değerleri diziye toplarSELECT ARRAY_AGG(urun_adi) FROM urunler
BIT_AND(sütun)Bitwise ANDSELECT BIT_AND(bayraklar) FROM ayarlar
BIT_OR(sütun)Bitwise ORSELECT BIT_OR(bayraklar) FROM ayarlar
BOOL_AND(sütun)Tümü true mi?SELECT BOOL_AND(aktif) FROM urunler
BOOL_OR(sütun)Herhangi biri true mi?SELECT BOOL_OR(aktif) FROM urunler
STDDEV(sütun)Standart sapmaSELECT STDDEV(fiyat) FROM urunler
VARIANCE(sütun)VaryansSELECT VARIANCE(fiyat) FROM urunler

Gruplama Örnekleri

SELECT musteri_id,
       COUNT(*) AS siparis_sayisi,
       SUM(tutar) AS toplam,
       AVG(tutar) AS ortalama,
       MIN(tutar) AS en_dusuk,
       MAX(tutar) AS en_yuksek
FROM siparisler
GROUP BY musteri_id
HAVING SUM(tutar) > 10000
ORDER BY toplam DESC

Metin (String) Fonksiyonları

FonksiyonAçıklamaÖrnek
LOWER(s)Küçük harfe çevirirSELECT LOWER('MENZELeT')'menzelet'
UPPER(s)Büyük harfe çevirirSELECT UPPER('menzelet')'MENZELET'
LENGTH(s)Karakter sayısıSELECT LENGTH('merhaba')7
CHAR_LENGTH(s)LENGTH ile aynıSELECT CHAR_LENGTH('abc')3
BIT_LENGTH(s)Bit cinsinden uzunlukSELECT BIT_LENGTH('abc')24
OCTET_LENGTH(s)Byte cinsinden uzunlukSELECT OCTET_LENGTH('abc')3
SUBSTR(s, pos, len)Alt metin çıkarır (1-tabanlı)SELECT SUBSTR('menzelet', 1, 3)'men'
LEFT(s, n)Soldan n karakterSELECT LEFT('menzelet', 3)'men'
RIGHT(s, n)Sağdan n karakterSELECT RIGHT('menzelet', 3)'let'
CONCAT(a, b, ...)BirleştirirSELECT CONCAT('men', 'ze', 'let')'menzelet'
CONCAT_WS(sep, ...)Ayırıcı ile birleştirirSELECT CONCAT_WS('-', 'a', 'b', 'c')'a-b-c'
REPLACE(s, old, new)Metin değiştirirSELECT REPLACE('abc', 'b', 'x')'axc'
REVERSE(s)Ters çevirirSELECT REVERSE('abc')'cba'
REPEAT(s, n)TekrarlarSELECT REPEAT('ab', 3)'ababab'
TRIM(s)Baş/son boşluk silerSELECT TRIM(' abc ')'abc'
LTRIM(s)Soldan boşluk silerSELECT LTRIM(' abc')'abc'
RTRIM(s)Sağdan boşluk silerSELECT RTRIM('abc ')'abc'
LPAD(s, len, fill)Soldan doldururSELECT LPAD('42', 5, '0')'00042'
RPAD(s, len, fill)Sağdan doldururSELECT RPAD('42', 5, '0')'42000'
INITCAP(s)Her kelimenin baş harfi büyükSELECT INITCAP('hello world')'Hello World'
ASCII(s)İlk karakterin ASCII koduSELECT ASCII('A')65
CHR(n)ASCII koddan karakterSELECT CHR(65)'A'
STARTS_WITH(s, prefix)Ön ek kontrolüSELECT STARTS_WITH('abc', 'ab')true
ENDS_WITH(s, suffix)Son ek kontrolüSELECT ENDS_WITH('abc', 'bc')true
CONTAINS(s, sub)İçerik kontrolüSELECT CONTAINS('abc', 'bc')true
STRPOS(s, sub)Alt metin pozisyonuSELECT STRPOS('abcdef', 'cd')3
SPLIT_PART(s, d, n)Ayırıcıyla böl, n. parçaSELECT SPLIT_PART('a-b-c', '-', 2)'b'
TRANSLATE(s, from, to)Karakter çevirisiSELECT TRANSLATE('abc', 'abc', 'xyz')'xyz'
TO_HEX(n)Sayıyı hex metin yaparSELECT TO_HEX(255)'ff'
LEVENSHTEIN(a, b)Düzenleme mesafesiSELECT LEVENSHTEIN('abc', 'axc')1
uuid()Rastgele UUID v4 üretirSELECT uuid()'c4a1...'
OVERLAY(s, r, pos, len)Metin üzerine yazarSELECT OVERLAY('abcdef' PLACING 'XX' FROM 3 FOR 2)

Matematik Fonksiyonları

FonksiyonAçıklamaÖrnek
ABS(x)Mutlak değerSELECT ABS(-5)5
CEIL(x)Yukarı yuvarlamaSELECT CEIL(3.2)4
FLOOR(x)Aşağı yuvarlamaSELECT FLOOR(3.8)3
ROUND(x, d)YuvarlaSELECT ROUND(3.456, 2)3.46
TRUNC(x, d)KesSELECT TRUNC(3.456, 2)3.45
SQRT(x)KarekökSELECT SQRT(16)4
CBRT(x)KüpkökSELECT CBRT(27)3
POW(x, y)Üs almaSELECT POW(2, 10)1024
EXP(x)e^xSELECT EXP(1)2.718...
LN(x)Doğal logaritmaSELECT LN(2.718)~1.0
LOG(base, x)LogaritmaSELECT LOG(10, 100)2
LOG10(x)10 tabanında logSELECT LOG10(1000)3
LOG2(x)2 tabanında logSELECT LOG2(8)3
PI()Pi sabitiSELECT PI()3.14159...
RANDOM()0-1 arası rastgeleSELECT RANDOM()
SIGN(x)İşaret (-1, 0, 1)SELECT SIGN(-5)-1
FACTORIAL(n)FaktöriyelSELECT FACTORIAL(5)120
GCD(a, b)En büyük ortak bölenSELECT GCD(12, 8)4
LCM(a, b)En küçük ortak katSELECT LCM(4, 6)12
DEGREES(rad)Radyandan dereceyeSELECT DEGREES(PI())180
RADIANS(deg)Dereceden radyanaSELECT RADIANS(180)3.14...
SIN(x)SinüsSELECT SIN(PI()/2)1
COS(x)KosinüsSELECT COS(0)1
TAN(x)TanjantSELECT TAN(PI()/4)~1
ASIN(x)Ark sinüsSELECT ASIN(1)1.5707...
ACOS(x)Ark kosinüsSELECT ACOS(1)0
ATAN(x)Ark tanjantSELECT ATAN(1)0.7853...
ATAN2(y, x)İki argümanlı ark tanjantSELECT ATAN2(1, 1)0.7853...
ISNAN(x)NaN kontrolüSELECT ISNAN(0.0/0.0)
ISZERO(x)Sıfır kontrolüSELECT ISZERO(0)true
NANVL(x, alt)NaN ise alternatifSELECT NANVL(val, 0.0)

Koşullu Fonksiyonlar

FonksiyonAçıklamaÖrnek
COALESCE(a, b, ...)İlk NULL olmayanSELECT COALESCE(fiyat, 0.0)
NULLIF(a, b)Eşitse NULLSELECT NULLIF(fiyat, 0.0)
GREATEST(a, b, ...)En büyük değerSELECT GREATEST(3, 7, 1)7
LEAST(a, b, ...)En küçük değerSELECT LEAST(3, 7, 1)1
IFNULL(a, b)NULL ise b dönerSELECT IFNULL(fiyat, 0.0)
NVL(a, b)IFNULL ile aynıSELECT NVL(fiyat, 0.0)
NVL2(a, b, c)a NULL değilse b, NULL ise cSELECT NVL2(fiyat, 'var', 'yok')

Tarih / Saat Fonksiyonları

FonksiyonAçıklamaÖrnek
NOW()Geçerli UTC zaman damgasıSELECT NOW()
CURRENT_DATEBugünün tarihiSELECT CURRENT_DATE
CURRENT_TIMEŞu anki saatSELECT CURRENT_TIME
CURRENT_TIMESTAMPNOW() ile aynıSELECT CURRENT_TIMESTAMP
TODAY()CURRENT_DATE ile aynıSELECT TODAY()
date_part(birim, tarih)Tarih bileşeni çıkarırSELECT date_part('year', NOW())
EXTRACT(birim FROM tarih)SQL standart bileşen çıkarmaSELECT EXTRACT(MONTH FROM tarih)
date_trunc(birim, tarih)Tarihi keserSELECT date_trunc('month', NOW())
date_bin(interval, ts, origin)Zaman aralığına hizalarSELECT date_bin(INTERVAL '1 hour', ts, '2024-01-01')
to_timestamp(s)Metinden timestampSELECT to_timestamp('2024-01-15 10:30:00')
to_date(s, fmt)Metinden tarihSELECT to_date('15/01/2024', '%d/%m/%Y')
to_char(ts, fmt)Tarihten metinSELECT to_char(NOW(), '%Y-%m-%d')
from_unixtime(epoch)Unix epoch’tan timestampSELECT from_unixtime(1705315800)
to_unixtime(ts)Timestamp’tan epochSELECT to_unixtime(NOW())
make_date(y, m, d)Bileşenlerden tarihSELECT make_date(2024, 1, 15)
make_time(h, m, s)Bileşenlerden saatSELECT make_time(10, 30, 0)
Interval aritmetiğiTarihe süre eklemeSELECT NOW() + INTERVAL '10 days'

Tarih Bileşenleri (date_part / EXTRACT)

Kullanılabilir birimler: year, month, day, hour, minute, second, week, dow (haftanın günü), doy (yılın günü), quarter, epoch

SELECT date_part('year', siparis_tarihi) AS yil,
       date_part('month', siparis_tarihi) AS ay,
       COUNT(*) AS siparis_sayisi
FROM siparisler
GROUP BY yil, ay
ORDER BY yil, ay

Regex Fonksiyonları

FonksiyonAçıklamaÖrnek
REGEXP_LIKE(s, pattern)Kalıp eşleşmesiSELECT REGEXP_LIKE('abc123', '[0-9]+')true
REGEXP_MATCH(s, pattern)Eşleşen grubu dönerSELECT REGEXP_MATCH('abc123', '([0-9]+)')
REGEXP_REPLACE(s, p, r)Kalıpla değiştirirSELECT REGEXP_REPLACE('abc123', '[0-9]', 'X')
REGEXP_COUNT(s, pattern)Eşleşme sayısıSELECT REGEXP_COUNT('abcabc', 'abc')2

Hash Fonksiyonları

FonksiyonAçıklamaÖrnek
MD5(s)MD5 hashSELECT MD5('menzelet')
SHA224(s)SHA-224 hashSELECT SHA224('menzelet')
SHA256(s)SHA-256 hashSELECT SHA256('menzelet')
SHA384(s)SHA-384 hashSELECT SHA384('menzelet')
SHA512(s)SHA-512 hashSELECT SHA512('menzelet')
DIGEST(s, algo)Belirtilen algoritmaSELECT DIGEST('abc', 'blake3')

Kodlama Fonksiyonları

FonksiyonAçıklamaÖrnek
ENCODE(veri, format)Binary → metinSELECT ENCODE(blob_sutun, 'base64')
DECODE(metin, format)Metin → binarySELECT DECODE('AQID', 'base64')

Desteklenen formatlar: base64, hex

Window (Pencere) Fonksiyonları

Window fonksiyonları OVER (...) ifadesiyle kullanılır.

FonksiyonAçıklama
ROW_NUMBER()Satır numarası (1’den başlar)
RANK()Sıralama (eşitlerde aynı numara, sonraki atlar)
DENSE_RANK()Sıralama (eşitlerde aynı numara, sonraki atlamaz)
NTILE(n)n gruba eşit böler
LAG(sütun, n)n satır önceki değer
LEAD(sütun, n)n satır sonraki değer
FIRST_VALUE(sütun)Penceredeki ilk değer
LAST_VALUE(sütun)Penceredeki son değer
NTH_VALUE(sütun, n)Penceredeki n. değer
CUME_DIST()Kümülatif dağılım
PERCENT_RANK()Yüzdelik sıralama

Window Örnekleri

-- Satır numarası
SELECT ROW_NUMBER() OVER (ORDER BY fiyat DESC) AS sira,
       urun_adi, fiyat
FROM urunler

-- Bölüm bazlı sıralama
SELECT kategori, urun_adi, fiyat,
       RANK() OVER (PARTITION BY kategori ORDER BY fiyat DESC) AS sira
FROM urunler

-- Bir önceki değerle karşılaştırma
SELECT tarih, tutar,
       LAG(tutar, 1) OVER (ORDER BY tarih) AS onceki_tutar,
       tutar - LAG(tutar, 1) OVER (ORDER BY tarih) AS fark
FROM gunluk_satis

-- Kümülatif toplam
SELECT tarih, tutar,
       SUM(tutar) OVER (ORDER BY tarih) AS kumulatif_toplam
FROM gunluk_satis

-- LAST_VALUE (pencere çerçevesi gerekir)
SELECT urun_adi,
       LAST_VALUE(urun_adi) OVER (
           ORDER BY fiyat
           ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
       ) AS en_pahali
FROM urunler

Özel Fonksiyon: collate()

MenzeletDB’ye özgü, locale-duyarlı sıralama fonksiyonu:

-- Türkçe alfabetik sıralama
SELECT isim FROM musteriler ORDER BY collate(isim)

Detaylı kullanım için bkz: Veri İşlemleri — Dil Duyarlı Sıralama

Diğer Fonksiyonlar

FonksiyonAçıklamaÖrnek
VERSION()Sunucu sürümüSELECT VERSION()

JOIN Türleri

MenzeletDB 10 farklı JOIN türünü destekler. JOIN stratejisi optimizer tarafından otomatik seçilir.

Örnek Tablolar

Bu bölümdeki tüm örnekler aşağıdaki tablolara dayanır:

-- Tablo tanımları
CREATE TABLE musteriler (id INT NOT NULL, ad VARCHAR, sehir VARCHAR)
CREATE TABLE siparisler (id INT NOT NULL, musteri_id INT, tutar FLOAT, tarih DATE)
CREATE TABLE urunler (id INT NOT NULL, ad VARCHAR, fiyat FLOAT)
CREATE TABLE siparis_detay (siparis_id INT, urun_id INT, miktar INT)

-- Örnek veriler
INSERT INTO musteriler VALUES (1, 'Ahmet', 'İstanbul')
INSERT INTO musteriler VALUES (2, 'Mehmet', 'Ankara')
INSERT INTO musteriler VALUES (3, 'Ayşe', 'İzmir')
INSERT INTO musteriler VALUES (4, 'Fatma', 'Bursa')

INSERT INTO siparisler VALUES (101, 1, 500.00, '2024-01-15')
INSERT INTO siparisler VALUES (102, 2, 750.00, '2024-01-20')
INSERT INTO siparisler VALUES (103, 1, 300.00, '2024-02-10')
INSERT INTO siparisler VALUES (104, 5, 100.00, '2024-02-15')

1. INNER JOIN

Her iki tabloda eşleşen satırları döner.

SELECT m.ad, s.tutar, s.tarih
FROM musteriler m
INNER JOIN siparisler s ON m.id = s.musteri_id
adtutartarih
Ahmet500.002024-01-15
Mehmet750.002024-01-20
Ahmet300.002024-02-10

musteri_id=5 (siparisler) ve id=3,4 (musteriler) eşleşme olmadığı için sonuçta yer almaz.

2. LEFT OUTER JOIN

Sol tablodaki tüm satırları döner; sağda eşleşme yoksa NULL.

SELECT m.ad, s.tutar
FROM musteriler m
LEFT JOIN siparisler s ON m.id = s.musteri_id
adtutar
Ahmet500.00
Ahmet300.00
Mehmet750.00
AyşeNULL
FatmaNULL

Ayşe ve Fatma’nın siparişi yok ama sonuçta yer alır (tutar = NULL).

3. RIGHT OUTER JOIN

Sağ tablodaki tüm satırları döner; solda eşleşme yoksa NULL.

SELECT m.ad, s.tutar, s.musteri_id
FROM musteriler m
RIGHT JOIN siparisler s ON m.id = s.musteri_id
adtutarmusteri_id
Ahmet500.001
Mehmet750.002
Ahmet300.001
NULL100.005

musteri_id=5 olan siparişin müşterisi yok (ad = NULL).

4. FULL OUTER JOIN

Her iki tablodaki tüm satırları döner; eşleşme yoksa NULL.

SELECT m.ad, s.tutar
FROM musteriler m
FULL OUTER JOIN siparisler s ON m.id = s.musteri_id
adtutar
Ahmet500.00
Ahmet300.00
Mehmet750.00
AyşeNULL
FatmaNULL
NULL100.00

5. CROSS JOIN

Kartezyen çarpım — her satır diğer tablodaki her satırla eşleşir.

SELECT m.ad, u.ad AS urun
FROM musteriler m
CROSS JOIN urunler u

4 müşteri x N ürün = 4N satır sonuç.

6. NATURAL JOIN

Aynı isimli sütunlarda otomatik eşleşme yapar.

-- Her iki tabloda 'id' sütunu varsa otomatik eşleşir
SELECT * FROM musteriler NATURAL JOIN siparisler

Dikkat: Sütun isimlerinin tam olarak eşleşmesi gerekir. Beklenmedik sonuçlara yol açabileceğinden açık ON koşulu tercih edilir.

7. LEFT SEMI JOIN

Sol tabloda sağla eşleşen satırları döner; sağ tablo sütunları dahil edilmez.

SELECT m.ad, m.sehir
FROM musteriler m
LEFT SEMI JOIN siparisler s ON m.id = s.musteri_id
adsehir
Ahmetİstanbul
MehmetAnkara

Siparişi olan müşteriler. IN veya EXISTS alt sorgusunun performanslı alternatifi.

Eşdeğer standart SQL:

SELECT ad, sehir FROM musteriler
WHERE id IN (SELECT musteri_id FROM siparisler)

8. RIGHT SEMI JOIN

Sağ tabloda solla eşleşen satırları döner; sol tablo sütunları dahil edilmez.

SELECT s.id, s.tutar
FROM musteriler m
RIGHT SEMI JOIN siparisler s ON m.id = s.musteri_id

9. LEFT ANTI JOIN

Sol tabloda sağla eşleşmeyen satırları döner.

SELECT m.ad, m.sehir
FROM musteriler m
LEFT ANTI JOIN siparisler s ON m.id = s.musteri_id
adsehir
Ayşeİzmir
FatmaBursa

Hiç siparişi olmayan müşteriler. NOT IN veya NOT EXISTS alt sorgusunun performanslı alternatifi.

Eşdeğer standart SQL:

SELECT ad, sehir FROM musteriler
WHERE id NOT IN (SELECT musteri_id FROM siparisler)

10. RIGHT ANTI JOIN

Sağ tabloda solla eşleşmeyen satırları döner.

SELECT s.id, s.tutar, s.musteri_id
FROM musteriler m
RIGHT ANTI JOIN siparisler s ON m.id = s.musteri_id
idtutarmusteri_id
104100.005

Müşteri kaydı olmayan (geçersiz müşteri ID) siparişler.

Çoklu JOIN

SELECT m.ad AS musteri,
       u.ad AS urun,
       sd.miktar,
       u.fiyat * sd.miktar AS toplam
FROM siparisler s
INNER JOIN musteriler m ON s.musteri_id = m.id
INNER JOIN siparis_detay sd ON s.id = sd.siparis_id
INNER JOIN urunler u ON sd.urun_id = u.id
ORDER BY toplam DESC

Self JOIN

Aynı tabloyu kendisiyle birleştirir:

-- Aynı şehirdeki müşteri çiftleri
SELECT a.ad AS musteri1, b.ad AS musteri2, a.sehir
FROM musteriler a
INNER JOIN musteriler b ON a.sehir = b.sehir AND a.id < b.id

JOIN Optimizasyonu

MenzeletDB optimizer’ı JOIN stratejisini otomatik seçer:

StratejiKullanım Durumu
Hash JoinEşitlik koşulu (ON a.id = b.id), büyük tablolar
Nested LoopEşitsizlik koşulları, küçük tablolar
Sort-Merge JoinHer iki tablo sıralı olduğunda

Sorgu planını görmek için EXPLAIN kullanılabilir:

EXPLAIN SELECT m.ad, s.tutar
FROM musteriler m JOIN siparisler s ON m.id = s.musteri_id

İndeks Kullanımı

MenzeletDB, büyük tablolarda hızlı arama için bellek içi (in-memory) indeksler destekler.

İndeks Türleri

TürEn İyi KullanımKarmaşıklık
HashEşitlik aramaları (WHERE id = 5)O(1)
BTreeAralık aramaları (WHERE fiyat BETWEEN 100 AND 500)O(log N)

İndeks Komutları

İndeks Listesi

INDEX LIST

Tüm aktif in-memory indeksleri gösterir.

Eşitlik Araması (Hash İndeks)

INDEX LOOKUP urunler urun_adi Klavye

urunler tablosunda urun_adi sütununda Klavye değerini arar.

Aralık Araması (BTree İndeks)

INDEX SCAN urunler fiyat 100 500

urunler tablosunda fiyat sütununda 100 ile 500 arasındaki değerleri arar.

Desteklenen İndeks Değer Tipleri

TipAçıklama
IntTam sayı
StrMetin
DateTarih
TimestampZaman damgası
DecimalOndalıklı sayı
Uuid16-byte binary UUID

Otomatik İndeks Kullanımı

MenzeletDB optimizer’ı WHERE koşullarında indeks kullanılabilir sütunları otomatik tespit eder:

  • IndexLookupRule: Mantıksal planda Filter + TableScan kalıbını tespit eder ve varolan indeks üzerinden arama yapar
  • Boş sonuç optimizasyonu: İndeks araması boş dönerse EmptyRelation ile gerçek disk taraması yapılmaz
  • Epoch doğrulaması: İndeks versiyon numarası (epoch) ile tablo versiyon numarası (data_version) eşleşmezse indeks kullanılmaz (stale indeks koruması)

Bloom Filter

MenzeletDB, INSERT işlemlerinde duplicate key kontrolü için Bloom filter kullanır:

  • Her tablo için {tablo}.bloom dosyası oluşturulabilir
  • Kirschner-Mitzenmacher double hashing, FPR (False Positive Rate) ~%0.1
  • Bincode ile diske kalıcı olarak saklanır (save() / load())
  • INSERT strict modda: Bloom filter “yok” derse kesin yok; “var” derse Parquet’ten doğrulanır

Desteklenmeyen ve Kısmi Desteklenen Özellikler

MenzeletDB, sütun tabanlı (columnar) bir analitik veritabanıdır. Geleneksel RDBMS’lerden (SQL Server, Oracle, PostgreSQL) farklı olarak bazı özellikler kasıtlı olarak desteklenmez, bazıları ise kısmi destek sunar.

Kısmi Destek

Transaction (İşlem)

Durum: Kısmi destek — yalnızca INSERT buffer’lama

MenzeletDB, BEGIN / COMMIT / ROLLBACK komutlarını destekler, ancak yalnızca INSERT (ve INSERT OR REPLACE) komutları transaction kapsamında buffer’lanır. DDL komutları (CREATE/DROP/ALTER TABLE, CREATE/DROP VIEW vb.) transaction içinde engellenir.

-- Desteklenen akış:
BEGIN
INSERT INTO urunler VALUES (1, 'Klavye', 450.00)
INSERT INTO urunler VALUES (2, 'Mouse', 250.00)
COMMIT    -- Her iki INSERT sırasıyla çalıştırılır

-- Geri alma:
BEGIN
INSERT INTO urunler VALUES (3, 'Monitör', 3500.00)
ROLLBACK  -- Buffer temizlenir, hiçbir veri yazılmaz

Davranış detayları:

  • BEGIN / BEGIN TRANSACTION: Transaction modunu başlatır. İç içe BEGIN engellenir.
  • COMMIT: Buffer’daki INSERT’leri sırasıyla çalıştırır. Kısmi başarı durumunda kaç komutun başarılı/başarısız olduğu raporlanır.
  • ROLLBACK: Buffer’ı temizler, hiçbir yazma gerçekleşmez.
  • DDL komutları (CREATE TABLE, DROP VIEW vb.) transaction içinde reddedilir.
  • SELECT, SHOW gibi okuma komutları transaction içinde normal çalışır.

Desteklenmeyen:

-- Bu komutlar MenzeletDB'de çalışmaz:
SAVEPOINT sp1;
ROLLBACK TO SAVEPOINT sp1;
ACID ÖzelliğiDurumAçıklama
AtomicityKısmiBEGIN/COMMIT ile INSERT grubu atomik; kısmi hata raporlanır
ConsistencyEvetNOT NULL kısıtı, tip kontrolü
IsolationYokEşzamanlı yazmalarda izolasyon seviyesi yok
DurabilityEvetWAL ile çökme kurtarma

ALTER TABLE

Durum: Kısmi destek — 5 işlem türü

Desteklenen işlemler:

-- Nullable sütun ekleme
ALTER TABLE urunler ADD COLUMN stok INT

-- NOT NULL + DEFAULT ile sütun ekleme (mevcut satırlara default yazılır)
ALTER TABLE urunler ADD COLUMN durum VARCHAR NOT NULL DEFAULT 'aktif'

-- Sütun silme
ALTER TABLE urunler DROP COLUMN eski_sutun

-- Sütunu NOT NULL olarak işaretleme (mevcut NULL kontrolü yapılır)
ALTER TABLE urunler ALTER COLUMN ad SET NOT NULL

-- Tablo yeniden adlandırma
ALTER TABLE urunler RENAME TO malzemeler

Desteklenmeyen işlemler:

-- Bu komutlar MenzeletDB'de çalışmaz:
ALTER TABLE urunler ALTER COLUMN fiyat TYPE BIGINT;     -- Tip değişikliği
ALTER TABLE urunler ADD CONSTRAINT pk PRIMARY KEY (id); -- Kısıt ekleme
ALTER TABLE urunler RENAME COLUMN eski TO yeni;         -- Sütun yeniden adlandırma

Detaylı ALTER TABLE kullanımı için bkz: Tablo Güncelleme


Desteklenmiyor

Stored Procedure (Saklı Yordam)

Durum: Desteklenmiyor

-- Bu komutlar MenzeletDB'de çalışmaz:
CREATE PROCEDURE rapor_olustur(tarih DATE) ...;
EXEC rapor_olustur('2024-01-01');
DROP PROCEDURE rapor_olustur;

Neden: MenzeletDB bir sorgu motorudur, prosédüral programlama ortamı değildir. PL/SQL veya T-SQL benzeri bir dil katmanı bulunmaz.

Alternatif: İş mantığı istemci tarafında uygulanabilir. Karmaşık sorgular için CTE kullanılabilir:

WITH aylik_satis AS (
    SELECT date_part('month', tarih) AS ay, SUM(tutar) AS toplam
    FROM siparisler
    GROUP BY date_part('month', tarih)
),
yillik_ozet AS (
    SELECT ay, toplam,
           SUM(toplam) OVER (ORDER BY ay) AS kumulatif
    FROM aylik_satis
)
SELECT * FROM yillik_ozet ORDER BY ay

Trigger (Tetikleyici)

Durum: Desteklenmiyor

-- Bu komutlar MenzeletDB'de çalışmaz:
CREATE TRIGGER stok_guncelle AFTER INSERT ON siparisler ...;
DROP TRIGGER stok_guncelle;

Neden: MenzeletDB olay tabanlı (event-driven) bir mekanizma içermez. Tetikleyiciler geleneksel OLTP veritabanlarının özellikleridir; MenzeletDB analitik (OLAP) odaklıdır.

Alternatif: Uygulama katmanında olay işlemecileri (event handlers) ile benzer işlevsellik sağlanabilir.

Kullanıcı Tanımlı Fonksiyon (UDF)

Durum: Kullanıcı tarafından SQL üzerinden oluşturulamaz

-- Bu komutlar MenzeletDB'de çalışmaz:
CREATE FUNCTION hesapla(x INT) RETURNS INT ...;
DROP FUNCTION hesapla;

Mevcut durum: MenzeletDB, 200+ yerleşik fonksiyonu destekler. Ayrıca sunucu içinde kayıtlı özel fonksiyonlar bulunur (ör. collate()). Ancak kullanıcıların SQL üzerinden yeni fonksiyon tanımlaması desteklenmez.

Tüm kullanılabilir fonksiyonlar için bkz: SQL Fonksiyonları


Karşılaştırma Tablosu

ÖzellikSQL ServerPostgreSQLOracleMySQLMenzeletDB
CREATE/DROP TABLEEvetEvetEvetEvetEvet
ALTER TABLEEvetEvetEvetEvetKısmi (5 işlem)
VIEWEvetEvetEvetEvetEvet
Stored ProcedureEvetEvetEvetEvetHayır
TriggerEvetEvetEvetEvetHayır
Transaction (ACID)EvetEvetEvetEvetKısmi (INSERT)
JOIN (10 tür)EvetEvetEvetKısmiEvet
Window FunctionsEvetEvetEvetEvetEvet
CTEEvetEvetEvetEvetEvet
SubqueryEvetEvetEvetEvetEvet
RBACEvetEvetEvetEvetEvet
DESCRIBE TABLEEvetEvetEvetEvetEvet
UDF (SQL ile)EvetEvetEvetEvetHayır
Columnar StorageHayırHayırHayırHayırEvet
Parquet FormatHayırHayırHayırHayırEvet

Not: MenzeletDB, OLTP (işlemsel) değil OLAP (analitik) odaklıdır. Desteklenmeyen özellikler, projenin sütun tabanlı analitik mimarisinin bilinçli tasarım kararlarıdır.

Diğer veritabanlarından geçiş yaparken detaylı eşleme tablosu için bkz: Göç Rehberi

Kimlik Doğrulama

Bağlantı Durum Makinesi

Her TCP bağlantısı WaitingForAuth durumunda başlar. Veritabanı işlemlerine erişim yalnızca kimlik doğrulama sonrasında mümkündür.

┌─────────────────┐   LOGIN <kullanıcı> <parola>   ┌───────────────────┐
│  WaitingForAuth  │ ────────────────────────────►  │   Authenticated    │
│   (başlangıç)    │  (doğrulama başarılı)          │  { username }      │
└─────────────────┘                                └───────────────────┘
       │                                                    │
  Hatalı parola / EXIT                             SQL / INDEX / EXIT
  → bağlantı kapatılır                           → normal işleme

LOGIN Komutu

LOGIN <kullanıcı_adı> <parola>

Başarılı Giriş

menzelet> LOGIN sa güçlüŞifre123
Giriş başarılı. Hoş geldiniz, sa!

Başarısız Giriş

Hatalı şifre veya geçersiz kullanıcı durumunda bağlantı otomatik olarak kapatılır (güvenlik nedeniyle).

Giriş Zorunluluğu

  • Her yeni bağlantıda LOGIN komutu zorunludur
  • Kimlik doğrulamadan önce SQL veya INDEX komutları reddedilir
  • Giriş başarısız olursa bağlantı güvenle sonlandırılır

Şifreleme

ÖzellikDeğer
AlgoritmaKriptografik hash (tek yönlü)
Salt16-byte rastgele (kullanıcıya özgü)
Yöntemhash(salt + şifre)
KarşılaştırmaSabit süreli (zamanlama saldırısı önlemi)

Güvenlik Garantileri

KorumaYöntem
Şifre saklamaHash + kullanıcıya özgü 16-byte salt
Zamanlama saldırısıSabit süreli karşılaştırma
DoS korumasıMaksimum eşzamanlı bağlantı limiti
Bağlantı limiti aşımıHata mesajı gönderilip bağlantı güvenle kapatılır
Erken komut korumasıKimlik doğrulama öncesi SQL komutları reddedilir

AUDIT Kaydı

Her Authenticated komut sunucu loglarına kaydedilir:

[AUDIT] sa@127.0.0.1:54321 -> CREATE TABLE urunler (id INT, fiyat FLOAT)
[AUDIT] mehmet@192.168.1.50:42100 -> SELECT * FROM siparisler

Kullanıcı ve Rol Yönetimi

Bu işlemler mnz_sys_admin rolüne sahip kullanıcılar (ör. sa) tarafından yapılabilir.

Kullanıcı İşlemleri

Oluşturma (CREATE USER)

CREATE USER mehmet PASSWORD 'güçlüŞifre456'
  • Kullanıcı adı benzersiz olmalıdır
  • Şifre hash + salt ile korunarak saklanır
  • Yeni kullanıcının varsayılan olarak hiçbir yetkisi yoktur

Şifre Güncelleme (ALTER USER PASSWORD)

ALTER USER mehmet PASSWORD 'yeniŞifre789'

Aktiflik Durumu Değiştirme (ALTER USER SET ACTIVE)

-- Pasifleştir (giriş yapamaz)
ALTER USER mehmet SET ACTIVE FALSE

-- Tekrar aktifleştir
ALTER USER mehmet SET ACTIVE TRUE

Silme (DROP USER)

DROP USER mehmet

Listeleme (SHOW USERS)

SHOW USERS

Koruma Kuralları

KuralAçıklama
sa silinemezDROP USER sa → hata
sa pasifleştirilemezALTER USER sa SET ACTIVE FALSE → hata

Rol İşlemleri

Oluşturma (CREATE ROLE)

CREATE ROLE rapor_admin

Silme (DROP ROLE)

DROP ROLE rapor_admin

Listeleme (SHOW ROLES)

SHOW ROLES

Koruma Kuralları

KuralAçıklama
Yerleşik roller silinemezDROP ROLE mnz_sys_admin → hata
mnz_ ön eki rezerveCREATE ROLE mnz_ozel → hata

Yerleşik Roller

RolKapsamYetkiler
mnz_sys_adminSistem geneliTüm yetkiler — her DB’de tam erişim
mnz_db_ownerTek veritabanıDDL + DML (tam erişim)
mnz_db_readerTek veritabanıSadece SELECT
mnz_db_writerTek veritabanıSELECT, INSERT, UPDATE, DELETE

Yetki Atama (GRANT)

-- Yerleşik rol ata
GRANT mnz_db_reader ON DATABASE musteri_db TO mehmet
GRANT mnz_db_writer ON DATABASE analitik_db TO ali

-- Belirli izinler ver
GRANT select, insert ON DATABASE musteri_db TO rapor_admin

Yetki Geri Alma (REVOKE)

REVOKE insert ON DATABASE musteri_db FROM rapor_admin

Yetki Sorgulama (SHOW GRANTS)

SHOW GRANTS FOR mehmet

Permission Listesi

Sistem Seviyesi

PermissionAçıklama
create_databaseVeritabanı oluşturma
drop_databaseVeritabanı silme
create_userKullanıcı oluşturma
alter_userKullanıcı güncelleme
drop_userKullanıcı silme
create_roleRol oluşturma
drop_roleRol silme
assign_permissionYetki atama (GRANT)
revoke_permissionYetki geri alma (REVOKE)
server_adminSunucu konfigürasyonu

Veritabanı Seviyesi

PermissionAçıklama
create_tableTablo oluşturma
drop_tableTablo silme
alter_tableTablo güncelleme (ADD COLUMN, DROP COLUMN, RENAME, SET NOT NULL)
selectVeri okuma
insertVeri ekleme
updateVeri güncelleme
deleteVeri silme
create_indexİndeks oluşturma
drop_indexİndeks silme
create_viewGörünüm (VIEW) oluşturma
drop_viewGörünüm (VIEW) silme

Tam Senaryo Örneği

-- sa olarak giriş yap
LOGIN sa güçlüŞifre123

-- Yeni veritabanı oluştur
CREATE DATABASE proje_db

-- Yeni kullanıcı oluştur
CREATE USER gelistirici PASSWORD 'dev2024!'

-- Okuma + yazma yetkisi ver
GRANT mnz_db_writer ON DATABASE proje_db TO gelistirici

-- Özel rol oluştur
CREATE ROLE rapor_okuyucu

-- Role sadece okuma izni ver
GRANT select ON DATABASE proje_db TO rapor_okuyucu

-- Yeni bir kullanıcıya özel rolü ata
CREATE USER analist PASSWORD 'analiz2024!'
GRANT rapor_okuyucu ON DATABASE proje_db TO analist

-- Yetkileri kontrol et
SHOW GRANTS FOR gelistirici
SHOW GRANTS FOR analist

Konfigürasyon

Sunucu ayarları src/menzelet.toml dosyasından okunur. Dosya yoksa varsayılan değerlerle çalışır.

Tam Konfigürasyon Dosyası

[server]
# Dinlenecek IP adresi
# "127.0.0.1" = Sadece yerel erişim (önerilen)
# "0.0.0.0"   = Tüm ağ arayüzleri (uzak erişim / Docker için)
host = "127.0.0.1"

# TCP port numarası
port = 4600

# Maksimum eşzamanlı bağlantı sayısı (Semaphore limiti)
max_connections = 100

[storage]
# Veritabanı klasörlerinin kök dizini
data_dir = "data"

[collation]
# Varsayılan dil duyarlı sıralama dili
# Desteklenen değerler: tr, en, de, ar, fr, es, ...
default_locale = "tr"

# Collation hassasiyet seviyesi
# primary   = Temel karakter farkları (a ≠ b)
# secondary = Aksanlar (a ≠ á)
# tertiary  = Büyük/küçük harf (a ≠ A)
strength = "tertiary"

[security]
# TLS sertifika dosyası (isteğe bağlı)
# tls_cert_path = "certs/server.pem"
# tls_key_path  = "certs/server-key.pem"

[pool]
# Sunucu başlatıldığında önceden oluşturulacak bağlantı havuzu sayısı
min_idle = 5

# Havuzda tutulabilecek maksimum boşta bağlantı sayısı
max_idle = 20

[metrics]
# Prometheus metrik HTTP endpoint'i aktif mi?
enabled = true

# Metrik sunucusunun dinleyeceği IP adresi
host = "127.0.0.1"

# Metrik HTTP port numarası
port = 9100

[optimizer]
# Sorgu optimizasyonu ayarları

[wal]
# WAL (Write-Ahead Log) ayarları
# format = "ndjson"  # veya "bincode" (kompakt format)

Önemli Ayarlar

Uzak Erişim

Sunucuya başka makinelerden erişmek için:

[server]
host = "0.0.0.0"
port = 4600
./menzelet-cli 192.168.1.100:4600

Docker İçin

Docker container içinde host = "0.0.0.0" gereklidir (dışarıdan erişim için). entrypoint.sh bunu otomatik ayarlar.

Bağlantı Havuzu

AyarVarsayılanAçıklama
pool.min_idle5Başlangıçta ön-ısınma ile oluşturulacak bağlantı sayısı
pool.max_idle20Havuzda tutulabilecek maksimum boşta bağlantı sayısı

WAL Formatı

FormatBoyutHızOkunabilirlik
ndjson (varsayılan)NormalNormalOkunabilir, debug dostu
bincode~3x küçük~5x hızlıBinary, okunabilir değil

Yedekleme ve Geri Yükleme

Veri Dizin Yapısı

MenzeletDB verileri klasör bazlı olarak saklar:

data/                                     ← Kök veri dizini (config: data_dir)
 ├── master/                              ← Sistem DB (silinemez, bootstrap'ta oluşur)
 │    ├── mnz_users.parquet               ← Kullanıcılar (şifreler korunmuş)
 │    ├── mnz_roles.parquet               ← Roller
 │    ├── mnz_user_roles.parquet          ← Kullanıcı-rol eşlemeleri
 │    ├── mnz_role_permissions.parquet    ← Rol-permission eşlemeleri
 │    ├── mnz_tables.parquet              ← Tablo katalog meta verileri
 │    ├── catalog.delta                   ← Katalog değişiklik günlüğü
 │    └── user_mgmt.delta                 ← Kullanıcı/rol değişiklik günlüğü
 │
 ├── musteri_db/                          ← Kullanıcı veritabanı
 │    ├── siparisler.parquet              ← Base Parquet (LZ4)
 │    ├── siparisler.wal                  ← WAL dosyası
 │    ├── siparisler.bloom                ← Bloom filter
 │    ├── siparisler-flush-0001.parquet   ← Flush dosyası #1
 │    ├── siparisler-flush-0002.parquet   ← Flush dosyası #2
 │    └── urunler.parquet
 │
 └── analitik_db/                         ← Başka bir kullanıcı veritabanı
      └── satislar.parquet

Yedekleme

Verilerinizi yedeklemek için data/ dizinini kopyalamanız yeterlidir:

# Linux/macOS
cp -r data/ data_backup_$(date +%Y%m%d)/

# Windows PowerShell
Copy-Item -Recurse data\ "data_backup_$(Get-Date -Format 'yyyyMMdd')\"

Tutarlı Yedekleme

En tutarlı yedek için:

  1. Sunucuyu durdurun (bellekteki tüm veriler diske yazılır)
  2. data/ dizinini kopyalayın
  3. Sunucuyu yeniden başlatın

Sunucu çalışırken yapılan yedeğe WAL dosyaları dahil olduğundan, geri yükleme sonrası WAL replay ile tutarlılık sağlanır.

Geri Yükleme

  1. Sunucuyu durdurun
  2. Mevcut data/ dizinini yedekle (güvenlik için)
  3. data/ dizinini yedeğiyle değiştirin
  4. Sunucuyu yeniden başlatın
# Linux/macOS
systemctl stop menzelet-server
mv data/ data_old/
cp -r data_backup_20240115/ data/
systemctl start menzelet-server

# Windows PowerShell
Stop-Service menzelet-server
Rename-Item data data_old
Copy-Item -Recurse data_backup_20240115\ data\
Start-Service menzelet-server

Tek Veritabanı Yedekleme

Sadece belirli bir veritabanını yedeklemek için:

# musteri_db yedeği
cp -r data/musteri_db/ backup_musteri_db/

# Geri yükleme
cp -r backup_musteri_db/ data/musteri_db/

Not: master veritabanı güvenlik meta verilerini içerir. Tam geri yükleme için master/ klasörü de dahil edilmelidir.

Delta Log Dosyaları

DosyaİçerikKonum
catalog.deltaTablo oluşturma/silme işlemleridata/master/
user_mgmt.deltaKullanıcı/rol yönetimi işlemleridata/master/

Bu dosyalar ekleme-tabanlı (append-only) formattadır. Belirli bir eşiği aştığında kompaksiyon tetiklenir ve tüm değişiklikler ana veri dosyasına yazılır.

İzleme ve Metrikler

Prometheus Metrikleri

MenzeletDB, Prometheus text format uyumlu HTTP endpoint sunar.

Konfigürasyon

[metrics]
enabled = true
host = "127.0.0.1"    # "0.0.0.0" = uzak erişim
port = 9100

Endpoint

GET http://127.0.0.1:9100/metrics

Metrik Kategorileri

Bağlantı Metrikleri

MetrikTipAçıklama
connections_totalCounterToplam TCP bağlantı sayısı
connections_activeGaugeAnlık aktif bağlantı sayısı
connections_rejectedCounterLimit aşımı reddedilen bağlantılar

Kimlik Doğrulama

MetrikTipAçıklama
auth_success_totalCounterBaşarılı giriş sayısı
auth_failure_totalCounterBaşarısız giriş sayısı

Sorgu Metrikleri

MetrikTipAçıklama
queries_totalCounterToplam sorgu sayısı
queries_selectCounterSELECT sorgu sayısı
queries_insertCounterINSERT sorgu sayısı
queries_ddlCounterDDL komut sayısı

İndeks Metrikleri

MetrikTipAçıklama
index_builds_totalCounterİndeks inşa sayısı
index_lookups_totalCounterİndeks arama sayısı

Depolama / Havuz Metrikleri

MetrikTipAçıklama
wal_appends_totalCounterWAL yazma sayısı
flush_totalCounterFlush işlem sayısı
pool_activeGaugeAnlık kullanılan context sayısı
pool_idleGaugeAnlık boşta context sayısı
pool_createdCounterToplam oluşturulan context
pool_reusedCounterHavuzdan yeniden kullanılan context

Metrik Türleri

TipAçıklamaÖrnek
AtomicCounterMonoton artan sayaçconnections_total, queries_total
AtomicGaugeAnlık değer (yükselir/düşer)connections_active, pool_idle

Performans

  • ~1-2 ns maliyet (x86-64 LOCK XADD talimatı)
  • ~200 byte bellek tüketimi (tüm metrikler için)
  • Lock-free: Mutex/RwLock kullanılmaz

Örnek Prometheus Çıktısı

# HELP connections_total Toplam bağlantı sayısı
# TYPE connections_total counter
connections_total 1523

# HELP connections_active Anlık aktif bağlantı
# TYPE connections_active gauge
connections_active 12

# HELP queries_total Toplam sorgu sayısı
# TYPE queries_total counter
queries_total 45678

# HELP pool_active Aktif context
# TYPE pool_active gauge
pool_active 8

# HELP pool_idle Boşta context
# TYPE pool_idle gauge
pool_idle 12

Grafana Entegrasyonu

Prometheus veri kaynağını yapılandırdıktan sonra aşağıdaki sorgularla dashboard oluşturulabilir:

PanelPromQL
Anlık bağlantılarconnections_active
Sorgu hızı (req/s)rate(queries_total[5m])
Havuz doluluk oranıpool_active / (pool_active + pool_idle)
Auth başarısızlık oranırate(auth_failure_total[5m])

Yük Testi Aracı

menzelet_loadgen ile stres testi yapılabilir:

cargo run -p menzelet_loadgen -- \
  --host 127.0.0.1:4600 \
  --scenario mixed \
  --concurrency 50 \
  --iterations 1000

Senaryolar: read, write, mixed, auth, ddl

Göç Rehberi

Bu rehber, diğer veritabanı sistemlerinden MenzeletDB’ye geçiş yaparken dikkat edilmesi gerekenleri içerir.

SQL Server’dan Göç

SQL ServerMenzeletDBNot
CREATE DATABASE xCREATE DATABASE xAynı
USE xUSE xAynı
CREATE TABLE t (id INT IDENTITY)CREATE TABLE t (id INT)IDENTITY yok, uuid() kullanılabilir
ALTER TABLE t ADD col INTALTER TABLE t ADD COLUMN col INTADD/DROP COLUMN, SET NOT NULL, RENAME desteklenir
CREATE VIEW v AS ...CREATE VIEW v AS ...Desteklenir (CREATE VIEW / DROP VIEW / SHOW VIEWS)
CREATE PROCEDURE p ...Desteklenmiyorİstemci tarafında uygula
CREATE TRIGGER tr ...DesteklenmiyorUygulama katmanında event handler
BEGIN TRAN ... COMMITBEGIN ... COMMITINSERT tamponlama desteklenir (DDL transaction icinde engellenir)
GETDATE()NOW()Yerleşik fonksiyon
ISNULL(x, y)COALESCE(x, y)SQL standardı
TOP 10LIMIT 10SQL standardı
NEWID()uuid()Yerleşik fonksiyon
LEN(str)LENGTH(str)SQL standardı
CHARINDEX(a, b)STRPOS(b, a)Parametre sırası farklı
DATEDIFF(day, a, b)date_part('epoch', b) - date_part('epoch', a)Manuel hesaplama
DATEADD(day, 10, d)d + INTERVAL '10 days'Interval aritmetiği
CONVERT(type, val)CAST(val AS type)SQL standardı
@@ROWCOUNTDesteklenmiyor

Veri Tipi Eşlemesi

SQL ServerMenzeletDB
INTINT
BIGINTBIGINT
SMALLINTSMALLINT
TINYINTTINYINT
FLOATFLOAT
REALFLOAT32
VARCHAR(n)VARCHAR (sabit uzunluk yok)
NVARCHAR(n)VARCHAR (UTF-8 varsayılan)
BITBOOL
DATEDATE
DATETIMETIMESTAMP
DATETIMEOFFSETTIMESTAMPTZ
DECIMAL(p,s)DECIMAL (38,10 sabit)
VARBINARYBLOB
UNIQUEIDENTIFIERUUID

PostgreSQL’den Göç

PostgreSQLMenzeletDBNot
CREATE DATABASECREATE DATABASEAynı
CREATE TABLE ... SERIALCREATE TABLE ... INTSERIAL yok, uuid() kullanılabilir
ALTER TABLEALTER TABLEADD/DROP COLUMN, SET NOT NULL, RENAME TO desteklenir
CREATE VIEWCREATE VIEWDesteklenir (CREATE VIEW / DROP VIEW / SHOW VIEWS)
CREATE FUNCTIONDesteklenmiyor200+ yerleşik fonksiyon
CREATE TRIGGERDesteklenmiyorUygulama katmanında
BEGIN ... COMMITBEGIN ... COMMITINSERT tamponlama desteklenir (DDL engellenir)
gen_random_uuid()uuid()Yerleşik fonksiyon
NOW()NOW()Aynı
EXTRACT(...)EXTRACT(...)Aynı
string_agg()string_agg()Aynı
array_agg()array_agg()Aynı

Oracle’dan Göç

OracleMenzeletDBNot
SYS_GUID()uuid()Yerleşik fonksiyon
SYSDATENOW()UTC döndürür
NVL(x, y)COALESCE(x, y)SQL standardı
ROWNUM <= 10LIMIT 10SQL standardı
DECODE(x, a, b, c)CASE WHEN x=a THEN b ELSE c ENDSQL standardı
TO_CHAR(date, fmt)to_char(date, fmt)Benzer
CREATE SEQUENCEDesteklenmiyoruuid() veya istemci-taraflı
CREATE SYNONYMDesteklenmiyor
CREATE MATERIALIZED VIEWDesteklenmiyor

MySQL’den Göç

MySQLMenzeletDBNot
AUTO_INCREMENTDesteklenmiyoruuid() veya istemci-taraflı
IFNULL(x, y)COALESCE(x, y)SQL standardı
UUID()uuid()Aynı işlevsellik
CONCAT(a, b)CONCAT(a, b)Aynı
GROUP_CONCAT(...)string_agg(...)Farklı isim
LIMIT x OFFSET yLIMIT x OFFSET yAynı
NOW()NOW()Aynı
CREATE INDEX idx ON t(col)INDEX BUILD t col btreeFarklı sözdizimi

Genel Göç Stratejisi

  1. Şema taşınması: Kaynak veritabanındaki tablo yapılarını MenzeletDB CREATE TABLE sözdizimine dönüştürün
  2. Veri aktarımı: Kaynak veritabanından CSV/Parquet olarak dışa aktarın, MenzeletDB’ye INSERT ile yükleyin
  3. Sorgu uyarlama: SP ve Trigger’ları uygulama-taraflı mantığa dönüştürün (VIEW desteklenmektedir)
  4. Test: Sorgu sonuçlarını karşılaştırın

Desteklenen Özellikler

ÖzellikMenzeletDB Karşılığı
VIEWCREATE VIEW, DROP VIEW, SHOW VIEWS
TransactionBEGIN / COMMIT / ROLLBACK (INSERT tamponlama, DDL engellenir)
ALTER TABLEADD COLUMN, DROP COLUMN, SET NOT NULL, RENAME TO (ALTER TYPE hariç)

Desteklenmeyen Özellikler İçin Alternatifler

ÖzellikAlternatif
Stored Procedureİstemci/uygulama mantığı
TriggerUygulama katmanında event handler
ALTER TABLE (ALTER TYPE)DROP TABLE + CREATE TABLE ile yeniden oluşturma
AUTO_INCREMENT / SERIALuuid() veya istemci-taraflı sayaç
Sequenceİstemci-taraflı sayaç

Sorun Giderme

Bu sayfa, MenzeletDB kullanırken karşılaşılan yaygın sorunları ve çözümlerini içerir.

Bağlantı Sorunları

Sunucuya Bağlanamıyorum

Belirti: İstemci “bağlantı reddedildi” hatası veriyor.

Olası nedenler ve çözümler:

  1. Sunucu çalışıyor mu?

    • Sunucuyu başlattığınızdan emin olun
    • cargo run -p menzelet_server veya ./menzelet-server
  2. Doğru adres ve port mu?

    • Varsayılan: 127.0.0.1:4600
    • menzelet.toml dosyasındaki [server] bölümünü kontrol edin
  3. Güvenlik duvarı?

    • Port 4600’un açık olduğundan emin olun
    • Windows: Windows Defender Firewall ayarlarını kontrol edin
    • Linux: ufw status veya iptables -L
  4. telnet/nc kullanıyorum, çalışıyor mu?

    • MenzeletDB length-prefix framing protokolü kullanır
    • telnet ve nc uyumlu değildir
    • Her zaman menzelet-cli kullanın

Bağlantı Kopuyor

Belirti: İşlem sırasında bağlantı aniden kapanıyor.

Olası nedenler:

  • Hatalı LOGIN girişimi (güvenlik önlemi olarak bağlantı kapatılır)
  • Sunucu maksimum bağlantı limitine ulaşmış olabilir (max_connections)
  • Ağ zaman aşımı

Kimlik Doğrulama Sorunları

“Kimlik doğrulaması gerekli” Hatası

Neden: LOGIN komutu kullanılmadan SQL çalıştırılmaya çalışıldı.

Çözüm:

menzelet> LOGIN sa şifreniz

Hatalı Şifre

Belirti: LOGIN sonrası bağlantı hemen kapanıyor.

Olası nedenler:

  • Şifre yanlış yazılmış olabilir (büyük/küçük harf duyarlı)
  • Kullanıcı pasifleştirilmiş olabilir (is_active = false)

Çözüm:

  • sa ile giriş yapın ve kullanıcıyı kontrol edin: SHOW USERS

Yetkilendirme Sorunları

“Permission denied” Hatası

Neden: Kullanıcının ilgili işlem için yetkisi yok.

Çözüm:

  1. sa ile bağlanın
  2. Kullanıcının yetkilerini kontrol edin: SHOW GRANTS FOR kullanici_adi
  3. Gerekli yetkileri atayın:
GRANT mnz_db_writer ON DATABASE veritabani_adi TO kullanici_adi

master DB Üzerinde İşlem Yapılamadı

Neden: master sistem veritabanıdır ve bazı işlemler kısıtlıdır.

Bilgi:

  • master silinemez
  • sa kullanıcısı silinemez ve pasifleştirilemez
  • mnz_ ön ekli roller silinemez

Veri Sorunları

INSERT Hatası: “Anahtar zaten mevcut”

Neden: Aynı birincil anahtarla veri eklenmiş.

Çözümler:

  1. Farklı bir anahtar kullanın
  2. Mevcut veriyi güncellemek için: INSERT OR REPLACE INTO ...

SELECT Sonuç Dönmüyor

Olası nedenler:

  • Tablo boş olabilir
  • WHERE koşulu hiçbir satırı karşılamıyor olabilir
  • Yanlış veritabanı seçili olabilir — USE dogru_db ile kontrol edin

Türkçe Karakterler Yanlış Sıralanıyor

Neden: Collation ayarı yapılandırılmamış.

Çözüm:

  1. menzelet.toml dosyasında:
[collation]
default_locale = "tr"
strength = "tertiary"
  1. Sorgularda ORDER BY collate(sutun) kullanın

Sunucu Sorunları

Sunucu Çökmesi Sonrası Veri Kaybı

Bilgi: MenzeletDB WAL (Write-Ahead Log) sayesinde çökme sonrası otomatik kurtarma yapar.

Adımlar:

  1. Sunucuyu yeniden başlatın
  2. WAL dosyaları otomatik replay edilir
  3. Flush edilmemiş veriler belleğe geri yüklenir
  4. Normal çalışmaya devam edilir

Sunucu Başlamıyor

Olası nedenler:

  1. Port kullanılıyor:

    • Başka bir işlem 4600 portunu kullanıyor olabilir
    • Windows: netstat -ano | findstr :4600
    • Linux: lsof -i :4600
  2. data/ dizini bozuk:

    • data/master/ dizinindeki Parquet dosyalarını kontrol edin
    • Yedekten geri yükleyin
  3. Yapılandırma hatası:

    • menzelet.toml dosyasının geçerli TOML formatı olduğunu kontrol edin

Bellek Kullanımı Yüksek

Olası nedenler:

  • Çok fazla tablo için bellek tamponu açık
  • Büyük indeksler bellekte tutuluyor
  • Flush eşiği çok büyük ayarlanmış

Çözüm:

  • COMPACT komutu ile flush dosyalarını birleştirin
  • menzelet.toml içinde flush eşiğini düşürün

Docker Sorunları

Container Başlamıyor

Kontrol:

docker logs menzelet

Olası nedenler:

  • MENZELET_SA_PASSWORD ortam değişkeni belirlenmemiş
  • Port çatışması (4600 kullanılıyor)

Dışarıdan Bağlanamıyorum

Çözüm:

  • Container’ın -p 4600:4600 ile başlatıldığından emin olun
  • host = "0.0.0.0" ayarının yapılandırıldığını kontrol edin

Performans Sorunları

Sorgular Yavaş

Olası nedenler ve çözümler:

  1. İndeks kullanın:

    • Sık aranan sütunlarda indeks oluşturun
    • INDEX BUILD tablo sutun btree
  2. Flush ve compaction:

    • Çok fazla flush dosyası sorgu performansını düşürür
    • COMPACT komutu ile birleştirin
  3. WHERE koşulu optimize edin:

    • Eşitlik kontrolleri için Hash indeks
    • Aralık sorguları için BTree indeks

Yardım ve Destek

Sorunun devam etmesi durumunda:

  1. Sunucu loglarını inceleyin (stdout)
  2. --ping ile sunucu sağlık kontrolü yapın
  3. Prometheus metriklerini kontrol edin (/metrics endpoint)

Komut Referansı

MenzeletDB’nin desteklediği tüm komutların tam referansı.

Bağlantı Komutları

KomutAçıklama
LOGIN <kullanıcı> <şifre>Kimlik doğrulama
EXITBağlantıyı kapat
QUITBağlantıyı kapat (EXIT ile aynı)

Veritabanı Komutları

KomutAçıklama
CREATE DATABASE <isim>Yeni veritabanı oluştur
DROP DATABASE <isim>Veritabanını sil
USE <isim>Aktif veritabanını değiştir
SHOW DATABASESTüm veritabanlarını listele

Tablo Komutları

KomutAçıklama
CREATE TABLE <tablo> (<sütunlar>)Yeni tablo oluştur
ALTER TABLE <tablo> ADD COLUMN <sütun> <tip>Tabloya nullable sütun ekle
ALTER TABLE <tablo> ADD COLUMN <sütun> <tip> NOT NULL DEFAULT <değer>NOT NULL + varsayılan değerli sütun ekle
ALTER TABLE <tablo> DROP COLUMN <sütun>Sütun sil
ALTER TABLE <tablo> ALTER COLUMN <sütun> SET NOT NULLSütunu NOT NULL yap
ALTER TABLE <tablo> RENAME TO <yeni_isim>Tabloyu yeniden adlandır
DROP TABLE <tablo>Tabloyu sil
DESCRIBE TABLE <tablo>Tablo şemasını göster (sütun/tip/nullable)
SHOW TABLESAktif veritabanındaki tabloları listele
COMPACT <tablo>Flush dosyalarını birleştir

VIEW Komutları

KomutAçıklama
CREATE VIEW <isim> AS <SELECT ...>Görünüm oluştur
DROP VIEW <isim>Görünümü sil
SHOW VIEWSAktif veritabanındaki görünümleri listele

Transaction Komutları

KomutAçıklama
BEGIN / BEGIN TRANSACTIONTransaction başlat (yalnızca INSERT buffer’lanır)
COMMITBuffer’daki INSERT’leri çalıştır
ROLLBACKBuffer’ı temizle, değişiklikleri iptal et

CREATE TABLE Sözdizimi

CREATE TABLE tablo_adi (
    sutun1 TIP [NOT NULL],
    sutun2 TIP [NOT NULL],
    ...
)

Desteklenen Veri Tipleri

SQL TipiEşdeğerlerAçıklama
INTINTEGER, INT3232-bit tam sayı
BIGINTINT6464-bit tam sayı
SMALLINTINT1616-bit tam sayı
TINYINTINT88-bit tam sayı
FLOATFLOAT6464-bit ondalıklı sayı
FLOAT3232-bit ondalıklı sayı
VARCHARTEXT, STRINGMetin
BOOLBOOLEANMantıksal değer
DATETarih (YYYY-MM-DD)
TIMESTAMPZaman damgası
TIMESTAMPTZZaman damgası + UTC
DECIMALSabit noktalı ondalık (38,10)
BLOBİkili veri
UUID128-bit benzersiz tanımlayıcı

SQL Komutları

SELECT

SELECT [sütunlar | *] FROM tablo
    [WHERE koşul]
    [ORDER BY sütun [ASC | DESC]]
    [LIMIT sayı]
    [OFFSET sayı]

INSERT

-- Strict mod (aynı anahtar varsa hata)
INSERT INTO tablo VALUES (değer1, değer2, ...)

-- Upsert mod (aynı anahtar varsa güncelle)
INSERT OR REPLACE INTO tablo VALUES (değer1, değer2, ...)

UPDATE

UPDATE tablo SET sütun = değer [, sütun2 = değer2] WHERE koşul

DELETE

DELETE FROM tablo WHERE koşul

JOIN

SELECT t1.sütun, t2.sütun
FROM tablo1 t1
JOIN tablo2 t2 ON t1.anahtar = t2.anahtar
[WHERE koşul]

GROUP BY

SELECT sütun, COUNT(*) FROM tablo
GROUP BY sütun
[HAVING koşul]

Aggregate Fonksiyonlar

FonksiyonAçıklama
COUNT(*)Tüm satırları say (NULL dahil)
COUNT(sütun)NULL olmayan satırları say
SUM(sütun)Toplam (NULL hariç)
AVG(sütun)Ortalama (NULL hariç)
MIN(sütun)Minimum değer
MAX(sütun)Maksimum değer

Scalar Fonksiyonlar

FonksiyonAçıklama
LOWER(metin)Küçük harfe çevir
UPPER(metin)Büyük harfe çevir
LENGTH(metin)Karakter sayısı
SUBSTR(metin, başlangıç, uzunluk)Alt metin çıkar
ROUND(sayı, ondalık)Yuvarla
CAST(değer AS tip)Tip dönüşümü
COALESCE(a, b, ...)İlk NULL olmayan değer
NULLIF(a, b)Eşitse NULL döndür

Tarih/Saat Fonksiyonları

FonksiyonAçıklama
NOW()Geçerli UTC zaman damgası
date_part('birim', tarih)Tarih bileşeni çıkar
EXTRACT(birim FROM tarih)SQL standart tarih bileşeni
tarih + INTERVAL 'süre'Tarihe süre ekle

Window Fonksiyonları

FonksiyonAçıklama
ROW_NUMBER() OVER (...)Satır numarası ata
FIRST_VALUE(sütun) OVER (...)Penceredeki ilk değer
LAST_VALUE(sütun) OVER (...)Penceredeki son değer

Collation (Dil Duyarlı Sıralama)

-- Türkçe alfabetik sıralama
SELECT isim FROM musteriler ORDER BY collate(isim)

-- Azalan sırada
SELECT urun_adi FROM urunler ORDER BY collate(urun_adi) DESC

İndeks Komutları

KomutAçıklama
INDEX LISTTüm indeksleri listele
INDEX LOOKUP <tablo> <sütun> <değer>Eşitlik araması (Hash)
INDEX SCAN <tablo> <sütun> <başlangıç> <bitiş>Aralık araması (BTree)

Kullanıcı Yönetimi Komutları

KomutAçıklama
CREATE USER <isim> PASSWORD '<şifre>'Kullanıcı oluştur
ALTER USER <isim> PASSWORD '<şifre>'Şifre güncelle
ALTER USER <isim> SET ACTIVE TRUEKullanıcıyı aktifleştir
ALTER USER <isim> SET ACTIVE FALSEKullanıcıyı pasifleştir
DROP USER <isim>Kullanıcıyı sil
SHOW USERSKullanıcıları listele

Rol Yönetimi Komutları

KomutAçıklama
CREATE ROLE <isim>Rol oluştur
DROP ROLE <isim>Rol sil
SHOW ROLESRolleri listele

Yetki Komutları

KomutAçıklama
GRANT <rol> ON DATABASE <db> TO <kullanıcı>Rol ata
GRANT <yetki1, yetki2> ON DATABASE <db> TO <rol>Permission ata
REVOKE <yetki> ON DATABASE <db> FROM <kullanıcı>Yetkiyi geri al
SHOW GRANTS FOR <kullanıcı>Yetkileri göster

Yerleşik Roller

RolKapsamAçıklama
mnz_sys_adminSistemTüm yetkiler
mnz_db_ownerVeritabanıDDL + DML tam erişim
mnz_db_readerVeritabanıSadece SELECT
mnz_db_writerVeritabanıSELECT, INSERT, UPDATE, DELETE

Permissionlar

Sistem seviyesi: create_database, drop_database, create_user, alter_user, drop_user, create_role, drop_role, assign_permission, revoke_permission, server_admin

Veritabanı seviyesi: create_table, drop_table, alter_table, select, insert, update, delete, create_index, drop_index, create_view, drop_view

İstemci Bayrakları

BayrakAçıklama
--lang <dil>Arayüz dilini ayarla (tr, en, es)
--pingSunucu sağlık kontrolü
--helpKullanım bilgisi

İstemci Meta-Komutları (Kısayollar)

KısayolAçıklama
\dTabloları listele (SHOW TABLES)
\d <tablo>Tablo şemasını göster (DESCRIBE TABLE <tablo>)
\dtTabloları listele (SHOW TABLES)
\duKullanıcıları listele (SHOW USERS)
\drRolleri listele (SHOW ROLES)
\diİndeksleri listele (INDEX LIST)
\dvGörünümleri listele (SHOW VIEWS)
\timingSorgu zamanlamayı aç/kapat
\xGenişletilmiş görünümü aç/kapat
\qÇıkış
\?Meta-komut yardımını göster