Büyük veri analizi söz konusu olduğunda, klasik row-based (satır tabanlı) veritabanı motorları genellikle yetersiz kalır. Milyonlarca satırı tararken dakikalarca beklemek, raporlama sorgularının yavaşlaması ve sunucu kaynaklarının gereksiz tükenmesi… Bunları yaşıyorsanız MariaDB Columnstore tam size göre. Bu yazıda Columnstore motorunu gerçek dünya senaryolarıyla inceleyeceğiz, kurulumdan performans optimizasyonuna kadar her şeyi ele alacağız.
MariaDB Columnstore Nedir?
MariaDB Columnstore, verileri satır bazında değil sütun bazında depolayan ve analitik sorgular için optimize edilmiş bir depolama motorudur. InfiniDB projesinden türetilmiş olan bu motor, OLAP (Online Analytical Processing) iş yükleri için tasarlanmıştır.
Klasik InnoDB motorundan temel farkı şu: InnoDB bir sorgu çalıştırdığında ilgili satırların tamamını okur. Columnstore ise sadece sorguda kullanılan sütunları okur. Bu, özellikle geniş tablolarda (50+ sütun) muazzam bir I/O tasarrufu sağlar.
Ne zaman Columnstore kullanmalısınız:
- Milyonlarca veya milyarlarca satırlık tablolarınız varsa
- Sorgularınız büyük veri setleri üzerinde aggregation (SUM, AVG, COUNT, GROUP BY) yapıyorsa
- Raporlama ve BI (Business Intelligence) iş yükleri çalıştırıyorsanız
- Veri ambarı mimarisi kuruyorsanız
- Batch insert ağırlıklı yazma operasyonlarınız varsa
Ne zaman Columnstore kullanmamalısınız:
- Tek satır okuma/yazma operasyonları çoksa (OLTP iş yükleri)
- Sık UPDATE/DELETE işlemi yapıyorsanız
- Küçük boyutlu tablolarla çalışıyorsanız
Kurulum ve Yapılandırma
MariaDB Columnstore Kurulumu
Önce MariaDB sunucunuzun kurulu olduğundan emin olun. Columnstore eklentisi MariaDB 10.5 ve üzeri sürümlerde daha stabil çalışır.
# Ubuntu/Debian için MariaDB repo ekleyin
curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash
# MariaDB Columnstore paketini kurun
sudo apt-get install mariadb-plugin-columnstore
# Ya da tam Columnstore kurulumu için
sudo apt-get install mariadb-columnstore
Red Hat/CentOS tabanlı sistemler için:
# MariaDB reposunu ekleyin
sudo rpm --import https://downloads.mariadb.com/MariaDB/RPM-GPG-KEY-MariaDB
# Columnstore motorunu kurun
sudo yum install MariaDB-columnstore-engine
# Servisi başlatın
sudo systemctl start mariadb-columnstore
sudo systemctl enable mariadb-columnstore
Kurulumdan sonra eklentinin yüklü olup olmadığını doğrulayın:
# MariaDB'ye bağlanın
mysql -u root -p
# Eklentileri listeleyin
SHOW PLUGINS;
# Columnstore motorunu kontrol edin
SELECT * FROM information_schema.ENGINES WHERE ENGINE = 'Columnstore';
Temel Yapılandırma
Columnstore’un varsayılan yapılandırması çoğu senaryo için yeterlidir, ancak üretim ortamı için bazı ayarları optimize etmek gerekir. /etc/columnstore/Columnstore.xml dosyasını düzenleyin:
# Columnstore yapılandırma dosyasını düzenleyin
sudo nano /etc/columnstore/Columnstore.xml
# Önemli parametreler:
# <NumBlocksPct>70</NumBlocksPct> --> Bellek havuzunun yüzdesi
# <TotalUmMemory>4G</TotalUmMemory> --> User Module bellek limiti
# <MaxColumnstoreJobsPerQuery>16</MaxColumnstoreJobsPerQuery> --> Paralel iş sayısı
İlk Columnstore Tablonuzu Oluşturun
Gerçekçi bir senaryo üzerinden gidelim. Bir e-ticaret firması için satış analitik tablosu oluşturacağız.
-- Analitik veritabanı oluşturun
CREATE DATABASE IF NOT EXISTS sales_analytics;
USE sales_analytics;
-- Columnstore motoru ile satış olayları tablosu
CREATE TABLE sales_events (
event_id BIGINT NOT NULL,
event_date DATE NOT NULL,
event_timestamp DATETIME NOT NULL,
customer_id INT NOT NULL,
product_id INT NOT NULL,
category_id INT NOT NULL,
region_id SMALLINT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
total_amount DECIMAL(12,2) NOT NULL,
discount_rate DECIMAL(5,2) DEFAULT 0.00,
channel VARCHAR(20) NOT NULL,
campaign_id INT DEFAULT NULL
) ENGINE=Columnstore DEFAULT CHARSET=utf8mb4;
-- Boyut tabloları InnoDB olabilir (lookup için)
CREATE TABLE products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(200) NOT NULL,
category_id INT NOT NULL,
brand VARCHAR(100),
cost_price DECIMAL(10,2)
) ENGINE=InnoDB;
Dikkat: Columnstore tablolarında PRIMARY KEY, UNIQUE INDEX ve FOREIGN KEY desteklenmez. Bu kısıtlamayı aklınızda tutun.
Veri Yükleme Stratejileri
Columnstore’a veri yüklerken performansı maksimize etmek için doğru yöntemi seçmek kritik önem taşır.
Bulk Load ile Hızlı Veri Aktarımı
# CSV dosyasından hızlı veri yükleme
# cpimport aracı Columnstore'a özel ve çok daha hızlı
sudo cpimport sales_analytics sales_events /tmp/sales_data.csv
-s ','
-E '"'
-n 1
# Alternatif olarak LOAD DATA INFILE kullanabilirsiniz
# Ama cpimport genellikle 3-5x daha hızlıdır
Eğer mevcut bir InnoDB tablosundan Columnstore’a geçiş yapıyorsanız:
-- InnoDB'den Columnstore'a veri kopyalama
INSERT INTO sales_analytics.sales_events
SELECT
event_id,
event_date,
event_timestamp,
customer_id,
product_id,
category_id,
region_id,
quantity,
unit_price,
total_amount,
discount_rate,
channel,
campaign_id
FROM legacy_db.sales_raw
WHERE event_date >= '2020-01-01';
-- Büyük tablolar için parçalı yükleme yapın
-- Her seferinde 1 milyonluk batch
INSERT INTO sales_analytics.sales_events
SELECT * FROM legacy_db.sales_raw
WHERE event_date BETWEEN '2023-01-01' AND '2023-03-31';
Analitik Sorgu Örnekleri
İşte Columnstore’un gerçek gücünün ortaya çıktığı yer burası. Aynı sorguları InnoDB’de çalıştırdığınızda dakikalar sürebilir, Columnstore’da saniyeler içinde sonuç alırsınız.
Senaryo 1: Aylık Satış Performans Raporu
-- Aylık bazda satış özeti - 500 milyon satır üzerinde bile hızlı çalışır
SELECT
YEAR(event_date) AS satis_yili,
MONTH(event_date) AS satis_ayi,
COUNT(*) AS islem_sayisi,
COUNT(DISTINCT customer_id) AS benzersiz_musteri,
SUM(quantity) AS toplam_adet,
SUM(total_amount) AS toplam_ciro,
AVG(total_amount) AS ortalama_siparis_degeri,
SUM(total_amount * discount_rate / 100) AS toplam_indirim,
MAX(total_amount) AS en_buyuk_siparis
FROM sales_events
WHERE event_date BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY
YEAR(event_date),
MONTH(event_date)
ORDER BY
satis_yili,
satis_ayi;
Senaryo 2: Ürün Kategori Analizi
-- Kategori bazında performans metrikleri
SELECT
se.category_id,
se.channel,
COUNT(DISTINCT se.customer_id) AS musteri_sayisi,
COUNT(*) AS siparis_adedi,
SUM(se.total_amount) AS kategori_ciro,
SUM(se.total_amount) / COUNT(*) AS ortalama_siparis,
SUM(se.quantity) AS satis_adedi,
AVG(se.discount_rate) AS ort_indirim_orani,
SUM(se.total_amount) * 100.0 /
SUM(SUM(se.total_amount)) OVER() AS ciro_yuzdesi
FROM sales_events se
WHERE
se.event_date >= DATE_SUB(CURDATE(), INTERVAL 90 DAY)
AND se.channel IN ('web', 'mobile', 'store')
GROUP BY
se.category_id,
se.channel
ORDER BY
kategori_ciro DESC
LIMIT 50;
Senaryo 3: Cohort Analizi (Müşteri Segment Takibi)
Bu tür analitik sorgular klasik RDBMS’lerde gerçekten ağır çalışır:
-- Müşterinin ilk alışveriş ayı bazında cohort analizi
WITH first_purchase AS (
SELECT
customer_id,
MIN(event_date) AS ilk_alis_tarihi,
DATE_FORMAT(MIN(event_date), '%Y-%m') AS cohort_ayi
FROM sales_events
GROUP BY customer_id
),
monthly_activity AS (
SELECT
se.customer_id,
fp.cohort_ayi,
DATE_FORMAT(se.event_date, '%Y-%m') AS aktif_ay,
PERIOD_DIFF(
DATE_FORMAT(se.event_date, '%Y%m'),
DATE_FORMAT(fp.ilk_alis_tarihi, '%Y%m')
) AS ay_farki,
SUM(se.total_amount) AS aylik_harcama
FROM sales_events se
JOIN first_purchase fp ON se.customer_id = fp.customer_id
GROUP BY
se.customer_id,
fp.cohort_ayi,
aktif_ay,
ay_farki
)
SELECT
cohort_ayi,
ay_farki,
COUNT(DISTINCT customer_id) AS aktif_musteri,
SUM(aylik_harcama) AS cohort_ciro,
AVG(aylik_harcama) AS kisi_basi_harcama
FROM monthly_activity
GROUP BY
cohort_ayi,
ay_farki
ORDER BY
cohort_ayi,
ay_farki;
Performans Optimizasyonu
Sorgu Planını Anlamak
-- Columnstore'da sorgu planını inceleyin
EXPLAIN SELECT
region_id,
SUM(total_amount) AS toplam
FROM sales_events
WHERE event_date >= '2023-01-01'
GROUP BY region_id;
-- Daha detaylı plan için
EXPLAIN EXTENDED SELECT ...;
-- Columnstore'a özgü istatistikleri kontrol edin
SELECT * FROM information_schema.COLUMNSTORE_TABLES
WHERE table_schema = 'sales_analytics';
Extent Elimination ile Performans
Columnstore, verileri extent adı verilen 8MB’lık bloklara böler ve her extent için min/max değerleri tutar. Sorgularınızda filtreleme kullandığınızda motor gereksiz extent’leri okumaz. Buna extent elimination denir.
Bu özellikten maksimum fayda sağlamak için:
-- Kötü: Tarihi string olarak filtrelemek
SELECT * FROM sales_events
WHERE DATE_FORMAT(event_date, '%Y') = '2023'; -- Extent elimination çalışmaz!
-- İyi: Native date filtresi kullanmak
SELECT * FROM sales_events
WHERE event_date BETWEEN '2023-01-01' AND '2023-12-31'; -- Extent elimination çalışır!
-- Kötü: Sütun üzerinde fonksiyon kullanmak
SELECT * FROM sales_events
WHERE YEAR(event_date) = 2023; -- Tüm extent'ler okunur
-- İyi: Range filtreleme
SELECT * FROM sales_events
WHERE event_date >= '2023-01-01'
AND event_date < '2024-01-01'; -- Sadece ilgili extent'ler okunur
Paralel Sorgu Ayarları
-- Mevcut session için paralellik seviyesini ayarlayın
SET columnstore_use_import_for_batchinsert = ON;
-- İnfiniDB uyumlu paralel sorgu modu
SET infinidb_local_query = 0; -- Distributed mode
SET infinidb_local_query = 1; -- Local mode (tek node)
-- Bellek kullanımını sorgulayın
SELECT
variable_name,
variable_value
FROM information_schema.GLOBAL_STATUS
WHERE variable_name LIKE 'Columnstore%';
Hibrit Mimari: Columnstore + InnoDB Birlikte Kullanım
Gerçek dünya uygulamalarında çoğunlukla her iki motoru birlikte kullanırsınız. OLTP işlemler için InnoDB, raporlama için Columnstore.
-- Örnek: InnoDB OLTP tablosu ile Columnstore analitik tablosunu birleştirme
-- Müşteri detayları InnoDB'de, satış verileri Columnstore'da
CREATE TABLE customers (
customer_id INT PRIMARY KEY AUTO_INCREMENT,
customer_name VARCHAR(200) NOT NULL,
email VARCHAR(150) UNIQUE,
city VARCHAR(100),
segment ENUM('bronze','silver','gold','platinum'),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- Analitik sorgu: Her iki tabloyu birleştir
SELECT
c.segment,
c.city,
COUNT(DISTINCT se.customer_id) AS musteri_sayisi,
SUM(se.total_amount) AS toplam_harcama,
AVG(se.total_amount) AS kisi_basi_harcama,
SUM(se.quantity) AS toplam_adet
FROM sales_events se
JOIN customers c ON se.customer_id = c.customer_id
WHERE
se.event_date >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
AND c.segment IN ('gold', 'platinum')
GROUP BY
c.segment,
c.city
ORDER BY
toplam_harcama DESC;
İzleme ve Bakım
Columnstore tablolarının sağlığını düzenli kontrol etmek gerekir:
# Columnstore tablolarının durumunu kontrol edin
sudo mcsadmin getSystemStatus
# Tablo istatistiklerini yenileyin (sorgu planı iyileştirmesi için)
mysqlcheck --analyze --user=root --password sales_analytics
# Columnstore log dosyalarını inceleyin
sudo tail -f /var/log/mariadb/columnstore/err.log
sudo tail -f /var/log/mariadb/columnstore/debug.log
-- Tablo boyutu ve sıkıştırma bilgisi
SELECT
table_name,
table_rows,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS toplam_mb
FROM information_schema.TABLES
WHERE
table_schema = 'sales_analytics'
AND engine = 'Columnstore'
ORDER BY data_length DESC;
-- Columnstore motorunun genel durumu
SELECT
variable_name,
variable_value
FROM information_schema.GLOBAL_STATUS
WHERE variable_name LIKE '%columnstore%'
ORDER BY variable_name;
Yaygın Hatalar ve Çözümleri
Sahada en sık karşılaştığım sorunlar ve çözümleri:
Hata: “No ColumnStore engine support for type” hatası
- Columnstore bazı veri tiplerini desteklemez: BLOB, TEXT, SET, BIT, GEOMETRY
- Bu alanlar için VARCHAR veya INT dönüşümü yapın
Hata: Sorgular çok yavaş çalışıyor
SET infinidb_local_query = 0komutunu çalıştırıp dağıtık modu aktif edin- WHERE koşullarının extent elimination’dan faydalanıp faydalanmadığını kontrol edin
EXPLAINçıktısında “CS” prefiksi görmelisiniz, görmüyorsanız Columnstore kullanılmıyor demektir
Hata: INSERT performansı düşük
- Tek tek INSERT yerine batch INSERT kullanın
- Mümkünse
cpimportaracını tercih edin columnstore_use_import_for_batchinsert = ONayarını etkinleştirin
Hata: Bellek yetersizliği
/etc/columnstore/Columnstore.xmldosyasındaTotalUmMemorydeğerini artırın- Sunucunuzun RAM’inin en az %60’ını Columnstore’a ayırın
Gerçek Dünya Senaryosu: E-Ticaret Raporlama Sistemi
Bir müşterimizin projesinde yaklaşık 800 milyon satırlık satış verisi mevcuttu. InnoDB ile çalışan eski raporlama sistemi, günlük satış raporunu üretmek için 45-60 dakika harcıyordu. Columnstore’a geçişten sonra:
- Günlük satış raporu: 45 dakikadan 38 saniyeye indi
- Aylık cohort analizi: 2 saatten 4 dakikaya düştü
- Depolama alanı: Sıkıştırma sayesinde yaklaşık %65 azaldı
- Sunucu CPU kullanımı: Raporlama sırasında %95’ten %40’a geriledi
Bu geçiş için kullandığımız temel strateji şuydu: OLTP işlemleri için InnoDB tablolarını koruyup her gece cpimport ile Columnstore tablolarına toplu veri aktarımı yaptık. Bu hibrit yaklaşım hem yazma performansını hem de okuma performansını optimize etti.
Sonuç
MariaDB Columnstore, büyük veri analitikleri için ciddi bir seçenek. Özellikle şunları aklınızda tutun:
- Doğru iş yükü seçimi kritik: OLAP için Columnstore, OLTP için InnoDB
- Extent elimination mekanizmasından faydalanmak için WHERE koşullarınızı akıllıca yazın
- Bulk load için mutlaka
cpimportaracını kullanın - Hibrit mimari çoğu zaman en iyi sonucu verir
- Desteklenmeyen veri tipleri için şema dönüşümü yapın
MariaDB Columnstore’u InnoDB ile karşılaştırırken “hangisi daha iyi?” sorusunu sormak yerine “hangi iş yükü için hangi motor?” sorusunu sormalısınız. İkisini birlikte, doğru senaryolarda kullandığınızda muazzam bir performans kazanımı elde edersiniz. Sorularınız varsa yorum bölümüne yazabilirsiniz, elimden geldiğince yardımcı olmaya çalışırım.