MySQL ve MariaDB’de Otomatik Tablo Analizi: ANALYZE, OPTIMIZE ve CHECK TABLE Komutlarının Etkin Kullanımı

Veritabanı yönetiminde en çok göz ardı edilen konulardan biri tablo sağlığının düzenli olarak kontrol edilmesi ve optimize edilmesidir. Bir MySQL veya MariaDB sunucusu kurulur, tablolar oluşturulur, veriler akar ve sistem bir süre güzel çalışır. Ama zamanla sorgular yavaşlamaya başlar, disk kullanımı beklenmedik şekilde şişer ve “neden bu kadar yavaşladı?” sorusu kaçınılmaz olarak gelir. İşte tam bu noktada ANALYZE TABLE, OPTIMIZE TABLE ve CHECK TABLE komutları devreye giriyor. Bu üç komutu doğru anlayıp doğru zamanlarda kullanmak, veritabanı performansınızı ciddi ölçüde iyileştirebilir.

Temel Kavramlar: Neden Bu Komutlara İhtiyaç Duyarız?

MySQL ve MariaDB, sorgu optimizasyonu için istatistiklere dayanır. Query optimizer, bir sorguyu çalıştırmadan önce hangi indeksin kullanılacağına, hangi join sırasının daha verimli olacağına karar vermek için bu istatistikleri kullanır. Ancak tablolara çok sayıda INSERT, UPDATE ve DELETE işlemi yapıldığında bu istatistikler güncelliğini yitirebilir. Optimizer yanlış kararlar almaya başlar ve performans düşer.

Bunun yanı sıra, özellikle MyISAM tablolarında silme ve güncelleme işlemleri tablo içinde “boşluklar” bırakır. Bu boşluklar disk alanını israf eder ve okuma performansını olumsuz etkiler. InnoDB’de de benzer sorunlar farklı biçimlerde ortaya çıkabilir.

InnoDB ve MyISAM farkı bu komutların davranışını doğrudan etkiler. MyISAM tablolar için bu komutlar genellikle tam anlamıyla fiziksel operasyonlar yaparken, InnoDB için bazen sadece istatistik güncelleme veya metadata işlemleriyle sınırlı kalabilir. Bunu aklınızda tutarak devam edelim.

CHECK TABLE: Tablonuzun Sağlığını Kontrol Etmek

CHECK TABLE komutu, bir tablonun bütünlüğünü ve tutarlılığını kontrol eder. Özellikle beklenmedik bir sistem çökmesinin ardından ya da şüpheli davranışlar gördüğünüzde ilk başvuracağınız komuttur.

Temel Kullanım

mysql -u root -p
-- Tek tablo kontrolü
CHECK TABLE kullanici_log;

-- Birden fazla tablo aynı anda
CHECK TABLE siparisler, urunler, musteriler;

-- Hızlı kontrol (sadece yanlış kapatılmış tabloları kontrol eder)
CHECK TABLE siparisler FAST;

-- Değişen satırları kontrol et
CHECK TABLE siparisler CHANGED;

-- Tam ve kapsamlı kontrol
CHECK TABLE siparisler EXTENDED;

Komutun çıktısı genellikle şu sütunları içerir:

  • Table: Kontrol edilen tablo adı
  • Op: Yapılan operasyon türü (check)
  • Msg_type: Mesaj tipi (status, error, info, warning)
  • Msg_text: Detay mesajı (OK, corrupt, vb.)

Gerçek Dünya Senaryosu: Çökme Sonrası Kontrol

Diyelim ki sunucunuz elektrik kesintisi nedeniyle düzgün kapatılmadı ve MySQL yeniden başladığında bazı tablolarda sorun olduğundan şüpheleniyorsunuz. Bu durumda tüm tabloları hızlıca kontrol etmek için şu yaklaşımı kullanabilirsiniz:

#!/bin/bash
# Tüm veritabanlarındaki tabloları kontrol eden script
DB_USER="root"
DB_PASS="sifreniz"
LOG_FILE="/var/log/mysql_check_$(date +%Y%m%d).log"

mysql -u$DB_USER -p$DB_PASS -e "
SELECT CONCAT('CHECK TABLE ', table_schema, '.', table_name, ';')
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'performance_schema', 'sys', 'mysql')
AND table_type = 'BASE TABLE'
" --skip-column-names 2>/dev/null | mysql -u$DB_USER -p$DB_PASS 2>&1 | tee $LOG_FILE

# Sorunlu tabloları filtrele
echo "=== SORUNLU TABLOLAR ==="
grep -v "OK" $LOG_FILE | grep -v "^Table"

Bu script çalıştığında, “OK” olmayan tüm sonuçları size raporlar. Böylece yüzlerce tablo arasında sorunluları tek tek aramak zorunda kalmazsınız.

ANALYZE TABLE: İstatistikleri Güncellemek

ANALYZE TABLE, tablo istatistiklerini günceller. Query optimizer’ın doğru kararlar alması için bu istatistiklerin güncel olması şarttır. Bir tabloda milyonlarca satır varsa ve sorgunuz bir indeksi hiç kullanmıyorsa, sorun büyük ihtimalle eski istatistiklerdir.

Nasıl Çalışır?

InnoDB için ANALYZE TABLE bir metadata lock alır ama tablo okumalarını engellemez (MySQL 5.6+ ve MariaDB 10.0+ için). Bu nedenle üretim ortamında nispeten güvenle çalıştırılabilir. MyISAM içinse tablo kilitlenir.

-- Tek tablo analizi
ANALYZE TABLE siparisler;

-- Birden fazla tablo
ANALYZE TABLE siparisler, siparis_detay, urunler;

-- MariaDB'de PERSISTENT seçeneği ile
ANALYZE TABLE siparisler PERSISTENT FOR ALL;

Performans Sorununu Tespit Etme

Şöyle bir senaryo düşünün: E-ticaret sitenizdeki sipariş listeleme sayfası son iki haftada giderek yavaşladı. Tablo büyüdü çünkü kampanya döneminde çok sipariş geldi. Şimdi her gün binlerce yeni sipariş ekleniyor ve silen de var.

-- Önce mevcut sorgu planına bakalım
EXPLAIN SELECT * FROM siparisler
WHERE musteri_id = 12345
AND durum = 'beklemede'
ORDER BY olusturma_tarihi DESC
LIMIT 20;

Eğer EXPLAIN çıktısında type sütununda ALL görüyorsanız (full table scan), indeks kullanılmıyor demektir. ANALYZE TABLE siparisler çalıştırdıktan sonra aynı EXPLAIN’i tekrar çalıştırın. Büyük ihtimalle optimizer artık doğru indeksi seçecektir.

-- Analiz et
ANALYZE TABLE siparisler;

-- Tekrar kontrol et
EXPLAIN SELECT * FROM siparisler
WHERE musteri_id = 12345
AND durum = 'beklemede'
ORDER BY olusturma_tarihi DESC
LIMIT 20;

Otomatik Analiz için Cron Job

Üretim ortamında ANALYZE TABLE’ı düzenli aralıklarla çalıştırmak iyi bir pratiktir. Ancak yoğun saatlerde değil, düşük trafikli dönemlerde yapılmalıdır.

#!/bin/bash
# /etc/cron.d/mysql-analyze içine ekleyin
# Haftalık çalışır, Pazar gece 02:00'de

DB_USER="analiz_user"
DB_PASS="guclu_sifre"
DB_HOST="localhost"

# Belirli veritabanlarını analiz et
for DB in eticaret crm muhasebe; do
    echo "Analiz ediliyor: $DB - $(date)"
    mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB -e "
    SELECT CONCAT('ANALYZE TABLE ', table_name, ';')
    FROM information_schema.tables
    WHERE table_schema = '$DB'
    AND table_type = 'BASE TABLE'
    " --skip-column-names | mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB
done

echo "Analiz tamamlandi: $(date)"

Cron’a eklemek için:

echo "0 2 * * 0 root /usr/local/bin/mysql_analyze.sh >> /var/log/mysql_analyze.log 2>&1" > /etc/cron.d/mysql-analyze
chmod 644 /etc/cron.d/mysql-analyze

OPTIMIZE TABLE: Tablo Birleştirme ve Boyut Küçültme

OPTIMIZE TABLE en kapsamlı ve en dikkatli kullanılması gereken komuttur. Bu komut şunları yapar:

  • MyISAM için: Silinen satırların bıraktığı boşlukları temizler, veri ve indeks dosyalarını birleştirir, istatistikleri günceller.
  • InnoDB için: Aslında ALTER TABLE ... ENGINE=InnoDB işlemi yapar. Bu tablonun yeniden oluşturulması anlamına gelir. Büyük tablolarda ciddi zaman alabilir ve disk alanı gerektirir.
  • MariaDB’de: InnoDB tablolar için daha akıllı bir yaklaşım vardır; bazı durumlarda sadece istatistik güncelleme yapılır.

Ne Zaman Kullanmalısınız?

  • Tablonuzdan çok büyük miktarda veri sildikten sonra
  • Tablo boyutu olması gerekenden çok daha büyükse
  • Sorgular tablonun boyutuyla orantısız yavaş çalışıyorsa
-- Tablo boyutunu kontrol et
SELECT
    table_name,
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS boyut_mb,
    ROUND((data_free / 1024 / 1024), 2) AS bos_alan_mb,
    ROUND((data_free / (data_length + index_length)) * 100, 2) AS bos_yuzde
FROM information_schema.tables
WHERE table_schema = 'eticaret'
AND table_type = 'BASE TABLE'
ORDER BY data_free DESC;

Bu sorgu size hangi tablolarda ne kadar boş (fragmented) alan olduğunu gösterir. bos_yuzde değeri 20’nin üzerindeyse o tablo optimize adayıdır.

Gerçek Dünya Senaryosu: Log Tablosu Temizliği

Şirketinizin uygulama log tablosunda 3 yıllık veri birikmiş. 50 milyon satırı eski log kayıtlarını sildünüz ama tablo hala 40 GB boyutunda ve disk alanı sıkıntı çıkarıyor. İşte bu durum klasik bir OPTIMIZE TABLE senaryosudur.

#!/bin/bash
# Optimize öncesi boyutu kaydet
mysql -u root -p"sifre" eticaret -e "
SELECT table_name,
       ROUND((data_length + index_length)/1024/1024, 2) as MB,
       ROUND(data_free/1024/1024, 2) as Bos_MB
FROM information_schema.tables
WHERE table_schema='eticaret' AND table_name='uygulama_log';
"

echo "Optimizasyon basliyor: $(date)"

# Optimize et (büyük tablolarda saatler sürebilir!)
mysql -u root -p"sifre" eticaret -e "OPTIMIZE TABLE uygulama_log;"

echo "Optimizasyon tamamlandi: $(date)"

# Sonraki boyutu göster
mysql -u root -p"sifre" eticaret -e "
SELECT table_name,
       ROUND((data_length + index_length)/1024/1024, 2) as MB,
       ROUND(data_free/1024/1024, 2) as Bos_MB
FROM information_schema.tables
WHERE table_schema='eticaret' AND table_name='uygulama_log';
"

Önemli uyarı: InnoDB tablolarda OPTIMIZE TABLE çalışırken tablo kilitlenir (MySQL 5.6 öncesinde) veya yeniden oluşturulur. Büyük tablolarda bunu üretim saatlerinde yapmak ciddi sorun yaratır. pt-online-schema-change gibi araçları kullanmayı düşünebilirsiniz.

Percona Toolkit ile Daha Güvenli Optimizasyon

Büyük tablolar için pt-online-schema-change çok daha güvenli bir alternatiftir:

# Percona Toolkit kurulumu (RHEL/CentOS)
yum install percona-toolkit

# Online optimize (tabloyu kilitlemeden)
pt-online-schema-change 
    --alter "ENGINE=InnoDB" 
    --host=localhost 
    --user=root 
    --password=sifre 
    --database=eticaret 
    --table=uygulama_log 
    --execute 
    --print

mysqlcheck: Hepsini Tek Komutla Yönetmek

Komut satırından tek seferde birden fazla işlem yapmak istiyorsanız mysqlcheck aracı hayat kurtarır. Bu araç CHECK, ANALYZE, OPTIMIZE ve REPAIR işlemlerini kolayca yapmanızı sağlar.

# Tüm veritabanlarını kontrol et
mysqlcheck -u root -p --all-databases

# Belirli bir veritabanını analiz et
mysqlcheck -u root -p --analyze eticaret

# Tüm veritabanlarını optimize et
mysqlcheck -u root -p --optimize --all-databases

# Hem kontrol hem onar
mysqlcheck -u root -p --auto-repair --all-databases

# Belirli tabloyu kontrol ve analiz
mysqlcheck -u root -p --check --analyze eticaret siparisler

Yaygın kullanılan parametreler:

  • –all-databases: Tüm veritabanlarını işler
  • –analyze: ANALYZE TABLE çalıştırır
  • –optimize: OPTIMIZE TABLE çalıştırır
  • –check: CHECK TABLE çalıştırır
  • –auto-repair: Sorunlu tabloları otomatik onarır
  • –extended: Kapsamlı kontrol yapar
  • –fast: Sadece düzgün kapatılmamış tabloları kontrol eder

MariaDB’ye Özgü İyileştirmeler

MariaDB, bu komutlar konusunda MySQL’e göre bazı avantajlar sunar. Özellikle ANALYZE TABLE ... PERSISTENT özelliği çok güçlüdür.

-- Sadece belirli indeksler için istatistik güncelle
ANALYZE TABLE siparisler PERSISTENT FOR COLUMNS (musteri_id, durum) INDEXES (idx_musteri, idx_durum);

-- Tüm kolonlar ve indeksler için kalıcı istatistik
ANALYZE TABLE siparisler PERSISTENT FOR ALL;

Bu persistent istatistikler mysql.table_stats ve mysql.index_stats tablolarında saklanır. Böylece sunucu yeniden başlatıldığında istatistikler kaybolmaz.

-- Saklanan istatistikleri görüntüle
SELECT * FROM mysql.index_stats WHERE table_name = 'siparisler';
SELECT * FROM mysql.table_stats WHERE table_name = 'siparisler';

Kapsamlı Bakım Scripti

Tüm bu komutları bir araya getiren, üretim ortamına uygun bir bakım scripti hazırlayalım:

#!/bin/bash
# mysql_maintenance.sh - Kapsamlı MySQL/MariaDB bakım scripti

DB_USER="maintenance_user"
DB_PASS="guclu_sifre_burada"
DB_HOST="127.0.0.1"
LOG_DIR="/var/log/mysql-maintenance"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$LOG_DIR/maintenance_$DATE.log"

mkdir -p $LOG_DIR

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# Bakıma muaf tutulacak veritabanları
EXCLUDE_DBS="information_schema performance_schema sys mysql"

log "=== MySQL Bakim Basliyor ==="

# Tüm kullanıcı veritabanlarını bul
DATABASES=$(mysql -u$DB_USER -p$DB_PASS -h$DB_HOST -Bse "
    SELECT schema_name FROM information_schema.schemata
    WHERE schema_name NOT IN ('information_schema','performance_schema','sys','mysql')
" 2>/dev/null)

for DB in $DATABASES; do
    log "Veritabani isleniyor: $DB"

    # 1. Bozuk tabloları kontrol et ve raporla
    log "  >> CHECK TABLE yapiliyor..."
    CHECK_RESULT=$(mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB -e "
        SELECT GROUP_CONCAT(table_name) FROM information_schema.tables
        WHERE table_schema='$DB' AND table_type='BASE TABLE'
    " --skip-column-names 2>/dev/null)

    mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB -e "
        SELECT CONCAT('CHECK TABLE `', table_name, '`;')
        FROM information_schema.tables
        WHERE table_schema='$DB' AND table_type='BASE TABLE'
    " --skip-column-names 2>/dev/null | 
    mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB 2>&1 | 
    grep -v "^Table|status.*OK" | tee -a $LOG_FILE

    # 2. İstatistikleri güncelle
    log "  >> ANALYZE TABLE yapiliyor..."
    mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB -e "
        SELECT CONCAT('ANALYZE TABLE `', table_name, '`;')
        FROM information_schema.tables
        WHERE table_schema='$DB' AND table_type='BASE TABLE'
    " --skip-column-names 2>/dev/null | 
    mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB >> $LOG_FILE 2>&1

    # 3. Yüzde 30'dan fazla boş alan olan tabloları optimize et
    log "  >> Optimize gerektiren tablolar kontrol ediliyor..."
    OPTIMIZE_TABLES=$(mysql -u$DB_USER -p$DB_PASS -h$DB_HOST -Bse "
        SELECT table_name FROM information_schema.tables
        WHERE table_schema='$DB'
        AND table_type='BASE TABLE'
        AND data_free > 0
        AND (data_free / (data_length + index_length + 1)) > 0.30
    " 2>/dev/null)

    for TABLE in $OPTIMIZE_TABLES; do
        log "  >> OPTIMIZE TABLE: $TABLE"
        mysql -u$DB_USER -p$DB_PASS -h$DB_HOST $DB -e "OPTIMIZE TABLE `$TABLE`;" >> $LOG_FILE 2>&1
    done
done

log "=== MySQL Bakim Tamamlandi ==="

# Log dosyasını sıkıştır
gzip $LOG_FILE

# 30 günden eski logları temizle
find $LOG_DIR -name "*.gz" -mtime +30 -delete

echo "Bakim tamamlandi. Log: ${LOG_FILE}.gz"

Bu scripti cron’a eklemek için:

chmod +x /usr/local/bin/mysql_maintenance.sh
echo "0 3 * * 0 root /usr/local/bin/mysql_maintenance.sh" >> /etc/cron.d/mysql-maintenance

Performans Etki Analizi

Bu komutları çalıştırmadan önce sistemin anlık durumunu izlemek için şu sorguyu kullanabilirsiniz:

-- Çalışan işlemleri görüntüle
SHOW FULL PROCESSLIST;

-- InnoDB durum bilgisi
SHOW ENGINE INNODB STATUSG

-- Tablo lock durumunu kontrol et
SHOW OPEN TABLES WHERE In_use > 0;

Eğer SHOW FULL PROCESSLIST çıktısında uzun süren sorgular varsa, OPTIMIZE TABLE çalıştırmayı bekleyin. Bu komutlar metadata lock alır ve diğer sorgular sırada beklemek zorunda kalır.

İzleme ve Uyarı Sistemi

Tablolarınızın durumunu proaktif olarak izlemek için basit bir monitoring scripti:

#!/bin/bash
# Yüksek fragmentasyon uyarısı
THRESHOLD=40  # Yüzde 40 üzeri uyarı ver

RESULT=$(mysql -u monitor_user -p"sifre" -e "
SELECT CONCAT(table_schema, '.', table_name) as tablo,
       ROUND((data_free/(data_length+index_length+1))*100,1) as bos_yuzde,
       ROUND((data_length+index_length)/1024/1024,1) as boyut_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema','performance_schema','sys','mysql')
AND data_free > 0
AND (data_free/(data_length+index_length+1)) > ($THRESHOLD/100)
ORDER BY bos_yuzde DESC
" --skip-column-names 2>/dev/null)

if [ ! -z "$RESULT" ]; then
    echo "UYARI: Yuksek fragmentasyonlu tablolar tespit edildi!"
    echo "$RESULT"
    # Buraya mail veya Slack bildirimi ekleyebilirsiniz
    # echo "$RESULT" | mail -s "MySQL Fragmentasyon Uyarisi" [email protected]
fi

Sonuç

ANALYZE TABLE, OPTIMIZE TABLE ve CHECK TABLE komutları veritabanı bakım rutininizin vazgeçilmez parçaları olmalıdır. Ancak bunları körü körüne ya da sık sık çalıştırmak yerine bilinçli kullanmak önemlidir.

Pratik önerileri özetleyelim:

  • CHECK TABLE: Sistem çökmelerinin ardından ve şüpheli durumlarda hemen kullanın. Haftalık rutin kontroller için uygundur.
  • ANALYZE TABLE: Büyük veri değişikliklerinden (toplu insert, delete, update) sonra mutlaka çalıştırın. Haftada bir rutin olarak yapın.
  • OPTIMIZE TABLE: Sadece gerçekten gerektiğinde, yani yüksek fragmentasyon tespit ettiğinizde ve düşük trafikli saatlerde çalıştırın. Her gün çalıştırmanıza gerek yok.
  • InnoDB tablolarda OPTIMIZE TABLE yerine mümkünse pt-online-schema-change kullanın; bu sayede tablo kilitleme süresini minimuma indirirsiniz.
  • Tüm bu işlemleri otomatize edin ama çıktıları mutlaka loglayın ve anomalileri izleyin.

Veritabanı bakımı “bir kez yap unut” değil, süreklilik gerektiren bir süreçtir. Bu komutları doğru sıklıkta ve doğru şekilde kullandığınızda, sorgu performansınızın iyileştiğini ve disk kullanımınızın düzeldiğini kısa sürede göreceksiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir