Ana Sayfa • Hakkında • Hızlı Başlangıç • Tutorial • Benchmark • Locale • SQL Rehberi • Changes • Wiki • English
Bu kılavuz, geleneksel ilişkisel veritabanı (RDBMS / SQL) deneyimi olan geliştiricilerin AmberDB’ye hızla adapte olabilmesi için hazırlanmıştır. Kuramsal ve felsefi detaylar yerine, “SQL’de şu şekilde yapılan işlem AmberDB’de şu şekilde yapılır” yaklaşımıyla doğrudan çalışan kod örneklerine odaklanır.
AmberDB ile kod geliştirmeye başlamadan önce bilmeniz gereken 4 pratik kural:
MySQL veya PostgreSQL gibi bir servis başlatmanız veya ağ bağlantısı kurmanız gerekmez. AmberDB, uygulamanızın içine bir Perl nesnesi olarak dahil edilir ve doğrudan yerel diskte çalışır.
use AmberDB;
my $adb = AmberDB->new(
cfg => { user => 'admin', language => 'tr' },
path => { dbase_dir => './dbstore' }
);
@record): SQL’deki tablo satırı, AmberDB’de ($id, $alan1, $alan2, ...) şeklinde bir Perl dizisidir.$record[0]) kaydın benzersiz kimliğidir. Yeni kayıtlarda buraya 0 veya undef verilir; insert_id çağrısı otomatik artan ID’yi üretir.name, price, status sütun adları yerine tablodaki pozisyonel blok indisleri (1, 2, 3…) kullanılır. Alanlarda düz skalar değerlerin yanı sıra iç içe ARRAY veya HASH referansları da doğrudan saklanabilir.[!NOTE] AmberDB’nin derin mimari altyapısı, disk dosya formatları ve benchmark sonuçları için AmberDB Hakkında, Kapsamlı Tutorial ve Benchmark Raporu sayfalarına başvurabilirsiniz.
INSERT INTO products (name, price, brand, category_id)
VALUES ('Sony WH-1000XM5', 149.99, 'Sony', 5);
# [0] ID (0: otomatik artan), [1] Ad, [2] Fiyat, [3] Marka, [4] Kategori ID
my $id = $adb->insert_id("products", 0, "Sony WH-1000XM5", 149.99, "Sony", 5);
insert_id ilk parametrede tablo adını, ikinci parametrede ID’yi (yeni kayıtlarda 0) ve ardından alanları alır. Otomatik atanan yeni ID numarasını skalar olarak döner. Tüm tanımlı indeksler eşzamanlı güncellenir.INSERT INTO products (name, price, brand) VALUES
('Ürün 1', 10.00, 'A'),
('Ürün 2', 20.00, 'B'),
('Ürün 3', 30.00, 'C');
my @records = (
[ 0, "Ürün 1", 10.00, "A" ],
[ 0, "Ürün 2", 20.00, "B" ],
[ 0, "Ürün 3", 30.00, "C" ],
);
my $status = $adb->insert_list("products", @records);
# $status->{1} = ilk eklenen ID, $status->{total} vb.
insert_list, dizi referanslarını toplu oturumda yazar. Tek tek eklemek yerine I/O ve kilit açma/kapama maliyetini minimuma indirir.SELECT * FROM products WHERE id = 101;
my @product = $adb->read_id("products", 101);
if (@product) {
print "ID: $product[0], Ad: $product[1], Fiyat: $product[2]\n";
}
read_id, birincil anahtara doğrudan erişerek kaydı dizi olarak döner. Kayıt yoksa boş liste döner. Sorgu planlama veya derleme yükü yoktur, $O(1)$ doğrudan anahtar erişimidir.UPDATE products
SET price = 129.99
WHERE id = 101;
my @p = $adb->read_id("products", 101);
$p[2] = 129.99; # 2. bloktaki fiyatı güncelle
$adb->update_id("products", @p);
@p dizisini update_id‘ye göndermek standart ve güvenli yoldur. @p[0] zaten kayıt ID’sini içerdiğinden tablo ve dizi parametreleri yeterlidir.-- Genellikle transaction veya geçici tablo ile yürütülür
UPDATE products SET price = price * 1.10 WHERE id IN (101, 102);
my @updates = (
[ 101, "Sony WH-1000XM5", 139.99, "Sony", 5 ],
[ 102, "Apple AirPods Max", 549.99, "Apple", 5 ],
);
my $status = $adb->update_list("products", @updates);
update_list metoduna göndererek tek seferde ve kilit verimliliğiyle tüm indeksleri güncelleyebilirsiniz.DELETE FROM products WHERE id = 101;
$adb->delete_id("products", 101);
delete_id, kaydı tablodan ve tüm ilişkili indekslerden (.inx, .fld, .src, .fac) anında kaldırır. Eğer tablonun şemasında keep_deleted => 1 etkinse kayıt yok edilmez; .del soft-delete çöp kutusuna taşınarak kurtarılabilir kılınır.DELETE FROM products WHERE id IN (101, 102, 103);
my $status = $adb->delete_list("products", 101, 102, 103);
delete_id çağırmaktan çok daha hızlıdır.SELECT COUNT(*) FROM products;
my $total = $adb->table_count("products");
SELECT * FROM products WHERE category_id = 5;
# 4. blok: category_id
my ($total, @products) = $adb->field_fetch("products", 4, 5);
print "Toplam $total adet kategori-5 ürünü bulundu.\n";
match_block => [4] tanımlanmışsa, motor .fld tersine indeksinden doğrudan 5 anahtarını arar ve eşleşen kayıtları getirir.SELECT * FROM products WHERE id IN (10, 25, 42);
my @products = $adb->read_list("products", [ 10, 25, 42 ]);
read_list metodu verilen ID listesini sırasıyla doğrudan diskten çeker ve kayıt referanslarını döner.-- LIKE ile (İndekssiz veya yavaş):
SELECT * FROM products WHERE name LIKE '%kulaklık%' OR description LIKE '%kulaklık%';
-- veya Full-Text Search ile:
SELECT * FROM products WHERE MATCH(name, description) AGAINST('kulaklık');
my ($total, @results) = $adb->search_table("products", "kulaklık");
foreach my $item (@results) {
print "Bulunan ID: $item->[0], Ad: $item->[1]\n";
}
search_table hem şemasız basit modda hem de .src tam metin indeksi tanımlı tablolarda çalışır. İç içe dizilerin derinliklerindeki kelimeleri de bulur. Harici arama motoru gerektirmeden AmberDB::Locale altyapısıyla Türkçe aksan ve büyük/küçük harf duyarsızlığını (İ/ı, ç/c) doğal olarak çözer.SELECT * FROM products
WHERE category_id = 5 AND brand = 'Sony';
my $res = $adb->field_filter("products", {
filter => {
4 => 5, # Blok 4 (category_id) = 5
3 => "Sony", # Blok 3 (brand) = "Sony"
}
});
my @matched_ids = @{ $res->{ids} };
my @records = $adb->read_list("products", \@matched_ids); # veya
my @records = $adb->read_list("products", $res->{ids});
field_filter, birden fazla alanın eşleşme indekslerini binary küme kesişimi (set intersection) ile birleştirir.SELECT * FROM products
ORDER BY id DESC
LIMIT 20 OFFSET 40;
# Parametreler: tablo, \%secenekler (offset, limit, sort)
my ($total, @page) = $adb->read_all("products", { offset => 40, limit => 20, sort => { reverse => 1 } });
print "Toplam $total kayıttan 40-60 arası gösteriliyor:\n";
read_all metodu veritabanının kayıt ID dizisi üzerinde doğrudan ikili arama ve dilimleme yapar. SQLite ve MySQL’in yüksek offset değerlerinde yaşadığı derin sayfalama yavaşlığını yaşamaz.SELECT * FROM products
WHERE category_id = 5
ORDER BY price ASC;
# field_fetch içinde dinamik sıralama:
# tabloid, blok_indis, blok_değeri, \%secenekler
my ($total, @sorted) = $adb->field_fetch(
"products", 4, 5,
{ offset => 0, limit => 20, sort => { blk => 2, reverse => 0 } } # Blok 2 (fiyat) artan
);
sort_block => [2] tanımlanmışsa, motor .inx indeksini kullanarak ekstra bellek sıralaması yapmadan veriyi doğrudan sıralı getirir.SELECT * FROM members
ORDER BY name COLLATE utf8mb4_turkish_ci;
# Nesne başlatılırken belirtilen dil motoru otomatik çalışır:
# cfg => { language => 'tr' }
my ($total, @members) = $adb->read_all("members", { offset => 0, limit => 50, sort => { blk => 1 } });
AmberDB::Locale motorunu çalıştırır. Türkçe Ç, Ğ, I, İ, Ö, Ş, Ü harfleri ASCII karmaşasına uğramadan evrensel standartta doğru sırada dizilir.Geleneksel ilişkisel SQL ile AmberDB arasındaki en büyük zihniyet ve performans farkı ilişkisel verilerin modellenmesindedir.
SQL’de bir siparişin kalemlerini ve müşteri ilişkisini tutmak için en az 3 ayrı tablo ve bunları bağlayan yabancı anahtarlar (Foreign Keys) gereklidir:
-- 1. Siparişleri ve Kalemleri Bulmak için SQL JOIN:
SELECT o.id AS order_id, o.customer_name, oi.product_id, oi.quantity, p.name AS product_name
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE oi.product_id = 101;
Maliyet: 3 ayrı B-Tree indeks taraması, çoklu disk I/O, geçici tablo belleği ve CPU sorgu planlama yükü.
AmberDB’de sipariş kaydı, kalemlerini kendi içinde doğal bir Perl iç içe dizi referansı (ARRAY ref) olarak barındırır:
# 1. Sipariş Kaydının Yapısı (@order):
my @order = (
0, # [0] Sipariş ID (Örn: 5001)
"Ahmet Yılmaz", # [1] Müşteri Adı
"2026-09-06", # [2] Tarih
[ # [3] Kalemler (İç içe ARRAY): [ [ ÜrünID, Adet, Fiyat ], ... ]
[ 101, 2, 149.99 ],
[ 105, 1, 49.90 ],
],
{ status => "kargoda" } # [4] Ek Bilgiler (HASH ref)
);
# Siparişi kaydet:
my $order_id = $adb->insert_id("orders", @order);
Şema dosyasında (orders.table) Blok 3 eşleştirme listesine eklenir:
{
match_block => [ 3 ], # Blok 3 içindeki tüm alt dizi elemanlarını otomatik indeksle
}
my @orders = $adb->field_fetch("orders", 3, 101);
foreach my $ord (@orders) {
print "Sipariş ID: $ord->[0], Müşteri: $ord->[1]\n";
}
<tablo>.fld (burada orders.fld) dosyasında toplanır. Kayıt eklenirken iç içe dizideki 101 ve 105 ID’leri otomatik olarak 3:101 ve 3:105 anahtarlarıyla orders.fld tersine indeksine yazılır. field_fetch("orders", 3, 101) çağrıldığında motor, orders.fld dosyasından "3:101" anahtarına tek bir doğrudan hash aramasıyla bu ürünü içeren tüm sipariş ID’lerini ($O(1)$) anında döner.order_items tablosu gerekmez; veri bütünlüğü bozulmaz.E-ticaret ve arama sayfalarında kullanıcıların sol tarafta gördüğü “Sony (12), Apple (8), Samsung (5)” gibi kategori filtre sayaçları SQL’de GROUP BY ile hesaplanır.
SELECT brand, COUNT(*) AS count
FROM products
WHERE category_id = 5
GROUP BY brand;
field_fltkeys Facet Motoru):
# 1. Facet Sayaçlarını Alma (Sadece { Değer => Adet } haritası döner, kayıt getirmez):
# Tablo şemasında facet_block => [ 3 ] tanımlandığında:
my $facets = $adb->field_fltkeys("products", {
target_block => 3, # Sayımı çıkarılacak hedef özellik bloku (Marka)
filter => { 4 => 5 }, # Filtrelenen blok: Blok 4 (Kategori ID) = 5
});
# $facets döner: { "Sony" => 12, "Apple" => 8, "Samsung" => 5 }
# 2. Seçilen Facet Değerine Göre Kayıtları Çekme (read_list):
# Kullanıcı "Sony" filtresine tıkladığında kayıtları getirmek için:
my $res = $adb->field_filter("products", {
filter => { 4 => 5, 3 => "Sony" }
});
my @records = $adb->read_list("products", $res->{ids});
# (Veya tekil blok için doğrudan: my @prods = $adb->field_fetch("products", 3, "Sony");)
field_fltkeys doğrudan kayıtları değil, yalnızca belirtilen filtre altındaki alan dağılım sayaçlarını döner. SQL büyük tablolarda GROUP BY yaparken geçici tablolar oluşturup yüksek CPU harcarken; AmberDB’nin Facet motoru .fac ikili indekslerini kullanarak sayaçları mikro-saniye seviyesinde üretir. Kayıtların kendisi ise filtrelenen ID’ler üzerinden read_list ile diskten tek seferde çekilir.AmberDB, çökmelere karşı korumalı geri alma günlüğü (undo-log) ve Strict 2PL (Two-Phase Locking) transaction desteğine sahiptir.
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- Hata varsa:
-- ROLLBACK;
-- Başarılıysa:
COMMIT;
# 1. İşlemi Başlat
$adb->transact_start();
my @sender = $adb->read_id("accounts", 1);
my @receiver = $adb->read_id("accounts", 2);
if ($sender[1] >= 100) { # Bakiye kontrolü
$sender[1] -= 100;
$receiver[1] += 100;
$adb->update_id("accounts", @sender);
$adb->update_id("accounts", @receiver);
} else {
# Hata bildir (transact_end'in otomatik rollback yapmasını sağlar)
$adb->transact_error("accounts", "Yetersiz bakiye");
}
# 2. İşlemi Tamamla (Hata varsa otomatik ROLLBACK, yoksa COMMIT)
my $txn = $adb->transact_end();
if ($txn->{status} eq "commit") {
print "Transfer başarılı!\n";
} else {
print "İşlem iptal edildi ve değişiklikler geri alındı!\n";
}
$adb->transact_start() ve $adb->transact_end() arasında yapılan tüm insert, modify, delete işlemleri loglanır. Hata olduğunda motor diski işlem öncesi durumuna kusursuz şekilde geri döndürür. Beklenmeyen elektrik kesintilerinde transact_recover() yarım kalan işlemleri otomatik temizler.ALTER TABLE) zorunludur:
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
price DECIMAL(10,2) NOT NULL,
brand VARCHAR(100),
category_id INT,
INDEX idx_cat (category_id),
FULLTEXT idx_search (name)
);
$adb->insert_id("products", ...) çağrısıyla tablo oluşturulabilir.products.table veya table_attr): Büyük ölçekli ve indeksli tablolar için blokların üstleneceği roller tek bir Hash yapısında tanımlanır:
$adb->table_attr("products", {
match_block => [ 4 ], # Kategori ID eşleşmesi (.fld)
search_block => [ 1 ], # Ürün adı tam metin araması (.src)
sort_block => [ 2 ], # Fiyat sıralaması (.inx)
facet_block => [ 3, 4 ], # Marka ve kategori filtre sayaçları (.fac)
slug_block => [ 1 ], # Başlıktan otomatik SEO URL üretimi (.slg)
keep_deleted => 1, # Silinenleri .del dosyasında sakla (Soft-delete)
log_owner => 1, # Hangi kullanıcı ne zaman değiştirdi kaydet (.aut)
});
.fld, .src, .fac, .inx) otomatik inşa edeceğini belirler.SQL veritabanı kullanan projelerde geliştiricilerin harici kütüphaneler, trigger’lar, ayrı önbellek sunucuları veya Cron betikleriyle çözdüğü birçok operasyon AmberDB’de çekirdek motora dahildir:
| Özellik | Geleneksel SQL Dünyasında Çözüm | AmberDB’deki Yerleşik Çözüm |
|---|---|---|
| Otomatik SEO URL Slug | Uygulama kodu, harici slugify kütüphaneleri, çakışma kontrolü için veritabanı sorguları. | slug_block => [1] tanımlandığında motor başlık değiştiğinde /urun/sony-wh-1000xm5 URL’ini otomatik üretir ve çakışmaları çözer (get_slug). |
| Kullanıcı İşlem Denetimi (Audit Log) | Ekstra audit tablosu, trigger’lar veya ORM middleware kodları. | log_owner => 1 tanımlandığında her ekleme/güncelleme .aut dosyasına işlenir. $adb->auth_view("tablo", $id) ile HTML raporu alınır. |
| Yüksek Hızlı Bellek İçi Önbellek ve Geçici Veri (RAM-Disk) | Disk I/O darboğazını aşmak veya geçici oturum/sepetleri tutmak için harici bir önbellek sunucusu (Redis veya Memcached) kurup yönetmek, ağ gecikmesi (TCP) ve senkronizasyon kodlarıyla uğraşmak. |
Ayrı bir sunucu veya servis kurmadan; süreç içi L1 bellek nesne önbelleği (set_cache, get_cache) ve işletim sistemi paylaşımlı belleği (RAM-Disk) üzerinde doğrudan çalışan yerel tablo motoru (use_ramdisk, ramdisk_*). Sıfır ağ gecikmesi, sıfır harici servis bağımlılığı. |
| Güvenli Silme (Soft-Delete) | Tabloya is_deleted sütunu eklemek ve yazılan her SELECT sorgusuna WHERE is_deleted = 0 eklemeyi unutmamak. |
keep_deleted => 1 ile silinen kayıtlar ana tablodan kaldırılıp .del arşivine taşınır. Veri sızıntısı riski olmadan güvenle saklanır. |
Günlük kod yazarken başvurabileceğiniz hızlı dönüşüm tablosu:
| SQL İşlemi | AmberDB Metodu | AmberDB Örnek Kullanımı |
|---|---|---|
INSERT INTO t VALUES (...) |
insert_id |
$id = $adb->insert_id("t", 0, @alanlar); |
INSERT INTO t VALUES (...), (...) |
insert_list |
$adb->insert_list("t", @records); |
SELECT * FROM t WHERE id = ? |
read_id |
my @rec = $adb->read_id("t", $id); |
SELECT * FROM t WHERE id IN (...) |
read_list |
my @recs = $adb->read_list("t", $res->{ids}); |
SELECT * FROM t LIMIT 20 OFFSET 0 |
read_all |
my ($tot, @recs) = $adb->read_all("t", { offset => 0, limit => 20 }); |
UPDATE t SET ... WHERE id = ? |
update_id |
$adb->update_id("t", @guncel_kayit); |
DELETE FROM t WHERE id = ? |
delete_id |
$adb->delete_id("t", $id); |
DELETE FROM t WHERE id IN (...) |
delete_list |
$adb->delete_list("t", @id_list); |
SELECT COUNT(*) FROM t |
table_count |
my $count = $adb->table_count("t"); |
SELECT * FROM t WHERE col = val |
field_fetch |
my @recs = $adb->field_fetch("t", $blk, $val); |
SELECT * FROM t WHERE col LIKE '%s%' |
search_table |
my @recs = $adb->search_table("t", "kelime"); |
SELECT * FROM t WHERE a=? AND b=? |
field_filter |
$adb->field_filter("t", { filter => { 1 => $a, 2 => $b } }); |
SELECT col, COUNT(*) GROUP BY col |
field_fltkeys |
$adb->field_fltkeys("t", { target_block => $blk, filter => { $fld => $val } }); |
START TRANSACTION / COMMIT |
transact_* |
$adb->transact_start(); ... $adb->transact_end(); |
CREATE TABLE / CREATE INDEX |
table_attr |
$adb->table_attr("t", { match_block => [ 1, 2 ] }); |
SQL dünyasındaki kavramların AmberDB mimarisindeki teknik karşılıkları:
| SQL / RDBMS Kavramı | AmberDB Karşılığı | Açıklama ve Mimari Anlamı |
|---|---|---|
| Database Server / Instance | AmberDB Nesnesi ($adb) |
Harici bir daemon veya TCP portu yoktur; uygulama prosesinin içinde gömülü (embedded) bir nesne olarak yaşar. |
| Table (Tablo) | Tablo (.db) |
Verilerin saklandığı Berkeley DB (DB_File) anahtar-değer dosyası. |
| Row / Record (Satır / Kayıt) | Dizi Kaydı (@record) |
Sabit kolonlu C-struct benzeri satırlar yerine doğal bir Perl listesidir. Skalar, ARRAY veya HASH referansı taşıyabilir. |
| Column / Field (Sütun / Kolon) | Blok / Alan İndisi ($record[$i]) |
Kolon adları yerine pozisyonel indisler (1, 2, 3…) kullanılır. |
| Primary Key (PK, AUTO_INCREMENT) | 0. İndis ($record[0]) |
Her kaydın ilk elemanıdır. Motor tarafından sıralı veya benzersiz sayısal ID atanır. |
| Foreign Key & JOINs | İç İçe Dizi (ARRAY ref) & match_block |
Normalize edilmiş çoklu tablolar yerine döküman içine gömülü listeler tutulur; .fld tersine indeksleriyle sıfır JOIN maliyetiyle sorgulanır. |
Index (CREATE INDEX) |
Şema İndeks Blokları | Tablo şemasında tanımlanan tersine indeksler: Eşleştirme (.fld), Metin arama (.src), Filtre/Facet (.fac), Sıralama (.inx). |
| Query Planner / Optimizer | Doğrudan İndeks Anahtarı Erişimi | SQL sözdizimi ayrıştırma, AST ağacı oluşturma ve maliyet hesaplama yükü yoktur; binary RID blokları doğrudan diskten okunur. |
| Collation / Charset | AmberDB::Locale |
Harici işletim sistemi veya veritabanı ayarına ihtiyaç duymaksızın Türkçeye ve 10+ dile tam uyumlu yerel alfabe motoru. |
| Audit Table & Triggers | log_owner & .aut Dosyası |
Kaydı kimin ne zaman eklediğini veya güncellediğini takip eden yerleşik denetim izi mekanizması. |
Soft Delete (is_deleted) |
keep_deleted & .del Dosyası |
Silinen kayıtların ana tablodan çıkarılıp kurtarılabilir ayrı bir dosyaya taşındığı yerleşik çöp kutusu. |
| Harici Önbellek / Oturum Sunucusu (Redis / Memcached Alternatifi) | set_cache / get_cache & RAM-Disk (use_ramdisk) |
Harici bir daemon/sunucu kurmaksızın; uygulama düzeyinde L1 süreç içi nesne önbelleği ve kritik/geçici tablolar için işletim sistemi paylaşımlı belleğinde (RAM-Disk) dosya tabanlı, TTL destekli yerel hızlandırma. |