Tüm Tabloların Kayıt Sayısını Tek Sorguda Görmek
Bir veritabanını yönetirken en sık karşılaştığın durumlardan biri şudur: “Hangi tabloda ne kadar veri var?” sorusu. Özellikle production ortamında onlarca, hatta yüzlerce tablo barındıran bir veritabanında her tabloyu tek tek sorgulamak hem zaman kaybı hem de ciddi bir eziyet. İşte bu noktada MariaDB ve MySQL’in sunduğu sistem tabloları ve dinamik SQL yetenekleri devreye giriyor. Bu yazıda, tüm tablolardaki kayıt sayısını tek sorguda nasıl görebileceğini, farklı yöntemlerin artı ve eksilerini, ve gerçek dünya senaryolarında bunları nasıl kullanacağını detaylıca ele alacağım.
Neden Bu Sorguya İhtiyaç Duyarsın?
Günlük operasyonlarda bu bilgiye ihtiyaç duyduğun onlarca senaryo var. Mesela bir e-ticaret sitesinin veritabanını devraldın. Önceki ekipten sağlıklı bir dokümantasyon gelmiyor. İlk iş olarak “Bu veritabanında ne var, nasıl bir veri yoğunluğu söz konusu?” diye bakmak istersin. Ya da otomatik temizlik scriptleri yazıyorsun ve bir tablonun belirli bir kayıt sayısının altına düşüp düşmediğini kontrol etmen gerekiyor. Bunlara ek olarak, yedekleme stratejisi belirlerken hangi tabloların daha kritik ve daha büyük olduğunu bilmek isteyebilirsin. Tüm bu ihtiyaçlar için “tüm tablolarda kayıt sayısı” sorgusu birebir.
Yöntem 1: information_schema Üzerinden Hızlı Tahmin
MariaDB ve MySQL, information_schema adlı bir sistem veritabanı barındırır. Bu veritabanındaki TABLES view’u, her tablo hakkında metadata bilgisi tutar. Bunlardan biri de TABLE_ROWS kolonudur.
SELECT
TABLE_NAME AS 'Tablo Adı',
TABLE_ROWS AS 'Kayıt Sayısı (Tahmini)',
ENGINE AS 'Motor',
DATA_LENGTH / 1024 / 1024 AS 'Veri Boyutu (MB)'
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'veritabani_adin'
AND TABLE_TYPE = 'BASE TABLE'
ORDER BY
TABLE_ROWS DESC;
Bu sorguyu çalıştırdığında saniyeler içinde tüm tabloların listesini alırsın. Ancak burada kritik bir uyarı var: InnoDB motorunu kullanan tablolarda TABLE_ROWS değeri gerçek sayıyı değil, yaklaşık bir tahmini gösterir. Bu tahmin, özellikle büyük tablolarda %20-40 sapma gösterebilir. MyISAM tablolarda ise bu değer kesindir çünkü MyISAM kayıt sayısını ayrıca saklar.
Bu yöntemi şu durumlarda kullan:
- Genel bir fikir edinmek istiyorsan
- Hız öncelikliyse
- Kesin sayı kritik değilse
- Büyük tablolarda bile hızlı sonuç istiyorsan
Yöntem 2: COUNT(*) ile Kesin Sonuç – Dinamik SQL
Eğer kesin kayıt sayısına ihtiyacın varsa, her tablo için COUNT(*) çalıştırman gerekir. Bunu elle yapmak yerine, dinamik SQL üreten bir sorgu yazabiliriz.
Önce hangi tabloların var olduğunu görelim:
SELECT
GROUP_CONCAT(
'SELECT ''', TABLE_NAME, ''' AS tablo_adi, COUNT(*) AS kayit_sayisi FROM `',
TABLE_NAME, '`'
SEPARATOR ' UNION ALL '
) AS dinamik_sorgu
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'veritabani_adin'
AND TABLE_TYPE = 'BASE TABLE';
Bu sorgu sana çalıştırabileceğin dinamik bir SQL çıktısı verir. Ama bu yaklaşımı production’da doğrudan kullanmak biraz zahmetli. Daha pratik olan stored procedure yöntemi.
Yöntem 3: Stored Procedure ile Otomatik COUNT(*)
Production ortamlarında en çok tercih ettiğim yöntem budur. Bir kez yazarsın, sonrasında tek komutla çağırırsın:
DELIMITER $$
CREATE PROCEDURE tum_tablolarin_kayit_sayisi(IN db_adi VARCHAR(255))
BEGIN
DECLARE bitti INT DEFAULT 0;
DECLARE tablo_adi VARCHAR(255);
DECLARE sorgu TEXT;
DECLARE tablo_cursor CURSOR FOR
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = db_adi
AND TABLE_TYPE = 'BASE TABLE'
ORDER BY TABLE_NAME;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bitti = 1;
CREATE TEMPORARY TABLE IF NOT EXISTS kayit_sayilari (
tablo_adi VARCHAR(255),
kayit_sayisi BIGINT
);
TRUNCATE TABLE kayit_sayilari;
OPEN tablo_cursor;
tablo_dongusu: LOOP
FETCH tablo_cursor INTO tablo_adi;
IF bitti = 1 THEN
LEAVE tablo_dongusu;
END IF;
SET sorgu = CONCAT(
'INSERT INTO kayit_sayilari SELECT ''',
tablo_adi,
''', COUNT(*) FROM `',
db_adi, '`.`',
tablo_adi, '`'
);
PREPARE stmt FROM sorgu;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE tablo_cursor;
SELECT * FROM kayit_sayilari ORDER BY kayit_sayisi DESC;
DROP TEMPORARY TABLE kayit_sayilari;
END$$
DELIMITER ;
Oluşturduktan sonra şu şekilde çağırırsın:
CALL tum_tablolarin_kayit_sayisi('veritabani_adin');
Bu procedure her tablo için gerçek COUNT(*) yapar, sonuçları geçici bir tabloda toplar ve sana sıralı olarak sunar. Dezavantajı: Büyük tablolarda uzun sürebilir. Milyonlarca kayıt içeren tablolar varsa bu procedure dakikalarca çalışabilir. Production saatlerinde çalıştırmaktan kaçın.
Yöntem 4: Bash Script ile Dışarıdan Toplama
Sistem yöneticisi bakış açısıyla en esnek yöntemlerden biri de bu işi MySQL dışında, bir Bash scriptiyle yapmak. Özellikle sonuçları bir log dosyasına yazmak veya monitoring sistemine göndermek istiyorsan bu yaklaşım çok işe yarıyor:
#!/bin/bash
DB_HOST="localhost"
DB_USER="monitor_user"
DB_PASS="guclu_parola"
DB_NAME="veritabani_adin"
LOG_FILE="/var/log/db_kayit_sayilari.log"
TARIH=$(date '+%Y-%m-%d %H:%M:%S')
echo "=== $TARIH ===" >> "$LOG_FILE"
# Tablo listesini al
TABLOLAR=$(mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" -N -e
"SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA='$DB_NAME' AND TABLE_TYPE='BASE TABLE'
ORDER BY TABLE_NAME;" 2>/dev/null)
if [ $? -ne 0 ]; then
echo "HATA: Veritabanina baglanılamadı!" >> "$LOG_FILE"
exit 1
fi
# Her tablo için COUNT(*) çalıştır
for TABLO in $TABLOLAR; do
SAYI=$(mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" -N -e
"SELECT COUNT(*) FROM `$DB_NAME`.`$TABLO`;" 2>/dev/null)
printf "%-40s %sn" "$TABLO" "$SAYI" >> "$LOG_FILE"
echo " $TABLO: $SAYI kayıt"
done
echo "" >> "$LOG_FILE"
echo "Tamamlandı. Sonuçlar $LOG_FILE dosyasına yazıldı."
Bu scripti crontab’a ekleyerek günlük raporlar üretebilirsin:
# Her gece 02:00'de çalıştır
0 2 * * * /opt/scripts/tablo_kayit_sayisi.sh >> /var/log/cron_db_rapor.log 2>&1
Yöntem 5: information_schema ve ANALYZE TABLE Kombinasyonu
InnoDB tablolarında information_schema‘daki tahminleri güncellemek için önce ANALYZE TABLE çalıştırabilirsin. Bu işlem istatistikleri yeniler ve TABLE_ROWS değerini gerçeğe daha yakın hale getirir:
-- Önce istatistikleri güncelle
SELECT
CONCAT('ANALYZE TABLE `', TABLE_NAME, '`;') AS komut
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'veritabani_adin'
AND TABLE_TYPE = 'BASE TABLE';
Bu sorgunun çıktısını kopyalayıp çalıştırabilir, ardından Yöntem 1’deki sorguyu tekrar kullanabilirsin. Büyük veritabanlarında ANALYZE TABLE işlemi tablo kilitlemesine neden olabileceğinden, bu işlemi de düşük trafik saatlerinde yapmanı öneririm.
Gerçek Dünya Senaryosu 1: Veri Büyüme Takibi
Bir müşteri için yönettiğim e-ticaret veritabanında “orders” tablosu beklenenden çok daha hızlı büyüyordu. Sorunu tespit etmek için şu sorguyu kullandım:
SELECT
TABLE_NAME AS 'Tablo',
TABLE_ROWS AS 'Tahmini Kayıt',
ROUND(DATA_LENGTH / 1024 / 1024, 2) AS 'Veri (MB)',
ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS 'Index (MB)',
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS 'Toplam (MB)',
CREATE_TIME AS 'Oluşturulma',
UPDATE_TIME AS 'Son Güncelleme'
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'eticaret_db'
AND TABLE_TYPE = 'BASE TABLE'
ORDER BY
(DATA_LENGTH + INDEX_LENGTH) DESC
LIMIT 20;
Bu sorgu sayesinde hem kayıt sayısını hem de disk kullanımını tek sorguda gördüm. “order_logs” tablosunun beklenmedik şekilde şiştiğini fark ettim. Uygulama tarafında bir hata, her sipariş güncellemesinde gereksiz log kaydı yaratıyordu.
Gerçek Dünya Senaryosu 2: Migrate Sonrası Doğrulama
Bir veritabanı migrasyonu yaptıktan sonra kaynak ve hedef taraftaki kayıt sayılarının eşleşip eşleşmediğini kontrol etmek zorundasın. Bunun için şu yaklaşımı kullanıyorum:
-- Kaynak sunucuda çalıştır, sonuçları kaydet
SELECT
TABLE_NAME,
TABLE_ROWS
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'kaynak_db'
AND TABLE_TYPE = 'BASE TABLE'
ORDER BY
TABLE_NAME
INTO OUTFILE '/tmp/kaynak_sayilar.csv'
FIELDS TERMINATED BY ','
LINES TERMINATED BY 'n';
Ardından hedef sunucuda aynı sorguyu çalıştırıp iki dosyayı karşılaştırabilirsin:
# Bash ile iki dosyayı karşılaştır
diff /tmp/kaynak_sayilar.csv /tmp/hedef_sayilar.csv
# Veya daha okunaklı bir karşılaştırma için
join -t',' -1 1 -2 1
<(sort /tmp/kaynak_sayilar.csv)
<(sort /tmp/hedef_sayilar.csv) |
awk -F',' '{
fark = $2 - $3;
if (fark != 0) print $1 ": Kaynak=" $2 " Hedef=" $3 " Fark=" fark
}'
Bu script sana sadece farklılık olan tabloları listeler. Migrasyon sonrası doğrulama sürecini çok hızlandırır.
Performans ve Dikkat Edilmesi Gerekenler
information_schema sorgularının kendisi çok hızlı olmakla birlikte, bazı durumlarda dikkat etmeni gereken noktalar var:
- InnoDB istatistik hassasiyeti: InnoDB,
TABLE_ROWSdeğerini her zaman canlı tutmaz. Çok sık write işlemi olan tablolarda bu değer gerçekten sapabilir. - COUNT() maliyeti: Özellikle partitioned olmayan büyük InnoDB tablolarında
COUNT()full table scan yapabilir. Yüz milyonluk bir tabloda bu sorgu dakikalar alabilir. - Bağlantı havuzu: Bash scriptinde her tablo için ayrı bağlantı açmak yerine, mümkünse tek bağlantıda işlemleri bitir.
- Yetki gereksinimleri:
information_schema.TABLESsorgulayabilmek için kullanıcının o veritabanındaki tablolara en azındanSELECTyetkisi olmalı.SHOW DATABASESveSHOW TABLESyetkileri de işe yarar. - Replikasyon ortamları: Eğer replica sunucularda bu sorguları çalıştırıyorsan, replika lag nedeniyle master ile tutarsız sonuçlar görebilirsin.
Monitoring Entegrasyonu
Üretim ortamlarında bu bilgileri Zabbix, Prometheus veya Grafana ile entegre etmek çok değerli. Bir tablo aniden sıfıra düşüyorsa veya beklenmedik şekilde patlıyorsa alarm almak isteyebilirsin. Bunun için basit bir monitoring scripti:
#!/bin/bash
# Kritik tablolar icin kayit sayisi kontrolu
# /opt/scripts/kritik_tablo_kontrol.sh
DB_USER="monitor"
DB_PASS="monitor_parola"
DB_NAME="uygulama_db"
ALERT_EMAIL="[email protected]"
# Kontrol edilecek tablolar ve minimum kayıt sayıları
declare -A MIN_KAYIT
MIN_KAYIT["users"]=100
MIN_KAYIT["products"]=50
MIN_KAYIT["categories"]=10
HATA_VAR=0
for TABLO in "${!MIN_KAYIT[@]}"; do
SAYI=$(mysql -u "$DB_USER" -p"$DB_PASS" -N -e
"SELECT COUNT(*) FROM `$DB_NAME`.`$TABLO`;" 2>/dev/null)
MIN=${MIN_KAYIT[$TABLO]}
if [ "$SAYI" -lt "$MIN" ]; then
echo "UYARI: $TABLO tablosu sadece $SAYI kayıt iceriyor! (Min: $MIN)"
HATA_VAR=1
fi
done
if [ "$HATA_VAR" -eq 1 ]; then
echo "Kritik tablo kayit sayisi sorunu tespit edildi!" |
mail -s "[ALARM] Veritabani Kayıt Sayisi Uyarisi" "$ALERT_EMAIL"
fi
Sık Yapılan Hatalar
Yıllar içinde gördüğüm en yaygın hataları sıralayayım:
- information_schema’ya kör güvenmek: InnoDB tablolarda
TABLE_ROWSher zaman yanlış olabilir. Kritik kararları bu veriye dayandırmadan önceCOUNT(*)ile doğrula. - Production saatlerinde COUNT() çalıştırmak: Büyük tablolarda
COUNT()ciddi I/O yükü yaratır. Mümkünse gece saatlerinde çalıştır ya da replica üzerinde kullan. - View’ları dahil etmek:
TABLE_TYPE = 'BASE TABLE'filtresi olmazsa view’lar da listeye girer ve count sorguları hata verebilir. Bu filtreyi her zaman ekle. - Geçici tabloları saymaya çalışmak:
information_schema‘da geçici tablolar görünmez, bu normal bir durum. - Karakter seti sorunları: Tablo adlarında Türkçe karakter veya boşluk varsa backtick kullanmayı unutma.
Farklı Veritabanı Motorlarının Etkisi
Sorgularını yazarken hangi storage engine kullandığını bilmek önemli. Kısaca özetleyeyim:
- InnoDB: En yaygın kullanılan motor.
TABLE_ROWStahminidir, kesin değildir.COUNT(*)tam tarama yapabilir. - MyISAM:
TABLE_ROWSkesin ve anlıktır çünkü MyISAM bu sayıyı tablonun header bilgisinde saklar.COUNT(*)çok hızlıdır. - MEMORY: MyISAM gibi kesin sayıyı tutar, hızlıdır ama sunucu yeniden başlayınca veriler gider.
- ARCHIVE: Sadece INSERT ve SELECT destekler.
COUNT(*)yavaş olabilir.
Veritabanındaki motorları kontrol etmek için:
SELECT
TABLE_NAME,
ENGINE,
TABLE_ROWS
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'veritabani_adin'
AND TABLE_TYPE = 'BASE TABLE'
ORDER BY
ENGINE, TABLE_NAME;
Bu sorgu sana hangi tablonun hangi motorla çalıştığını gösterir ve TABLE_ROWS değerine ne kadar güvenebileceğini anlamana yardımcı olur.
Sonuç
Tüm tablolardaki kayıt sayısını sorgulamak kulağa basit bir iş gibi gelir ama doğru yöntemi seçmek önemlidir. Hızlı bir tahmini görmek için information_schema.TABLES sorgusunu kullan. Kesin sayıya ihtiyacın varsa ve veritabanı küçükse stored procedure veya bash script yöntemini tercih et. Production ortamlarında büyük tablolar varsa bu işleri replica sunuculara yönlendir ve düşük trafik saatlerinde çalıştır.
Bu sorguları monitoring ve otomasyon süreçlerine entegre ettiğinde veritabanının durumunu çok daha proaktif takip edebilirsin. Beklenmedik veri kayıplarını veya anormal büyümeleri erkenden fark etmek, bir sysadmin olarak seni pek çok gece krizinden kurtarır. Metodları kendi ortamına göre uyarla, gerektiğinde index istatistiklerini tazele ve her zaman önce replica ortamında test et.
