Mikro ERP SQL Server Performans Optimizasyonu: Yavaşlığın 7 Kaynağı ve Çözüm Rehberi

Mikro ERP veritabanınız yavaş mı çalışıyor? STOK_HAREKETLERI ve CARI_HESAP_HAREKETLERI tablolarında index stratejisi, TempDB optimizasyonu, Wait Stats analizi, Execution Plan okuma ve otomatik bakım planı ile SQL Server performansını 5-10x artırın.

Mikro ERP’de en sık duyduğumuz şikayet: “Program çok yavaş.” Fatura kaydı 10 saniye sürüyor, stok raporu 2 dakikada açılıyor, cari ekstre sorgusu timeout veriyor.

Sorun genellikle Mikro yazılımının kendisinde değil, SQL Server yapılandırmasında ve veritabanı bakımsızlığında. Bu rehber, Mikro ERP veritabanınızdaki yavaşlığın gerçek kaynaklarını tespit etmenizi ve adım adım çözmenizi sağlayacak.

Başlamadan Önce: Teşhis → Tedavi

Performans optimizasyonunda en büyük hata körlemesine index eklemek veya donanım yükseltmektir. Doğru yaklaşım:

1. Ölç    → Yavaşlığın kaynağını tespit et (Wait Stats)
2. Analiz → Sorunlu sorguları bul (Execution Plan)
3. Uygula → Hedefe yönelik çözüm (Index, TempDB, Ayar)
4. Doğrula → İyileşmeyi ölç, yeni darboğaz var mı kontrol et

⚠️ Uyarı: Bu rehberdeki tüm SQL komutlarını önce test ortamında deneyin. Canlı veritabanında değişiklik yapmadan önce mutlaka tam yedek alın.


1. SQL Server Sürümü: Express Tuzağı

Mikro ERP kurulumlarının büyük çoğunluğu SQL Server Express ile gelir. Express sürümünün kritik sınırlamaları:

ÖzellikExpressStandardDeveloper
Maksimum RAM1,4 GB128 GBSınırsız
Maksimum CPU4 çekirdek24 çekirdekSınırsız
Veritabanı Boyutu10 GB524 PBSınırsız
Paralel SorguYokVarVar
FiyatÜcretsizLisanslıÜcretsiz (üretim dışı)

Veritabanı Boyutunuzu Kontrol Edin

-- Mikro ERP veritabanı boyutunu kontrol et
SELECT
    DB_NAME(database_id)          AS Veritabani,
    type_desc                     AS Dosya_Tipi,
    name                          AS Dosya_Adi,
    size * 8 / 1024               AS Boyut_MB,
    CAST(size * 8.0 / 1024 / 1024 AS DECIMAL(10,2)) AS Boyut_GB
FROM sys.master_files
WHERE DB_NAME(database_id) NOT IN ('master', 'model', 'msdb', 'tempdb')
ORDER BY size DESC;

Eğer veritabanınız 7-8 GB’ı aşıyorsa, Express sürümünde ciddi yavaşlık yaşamaya başlarsınız. 10 GB sınırına yaklaştığınızda ise veritabanı büyüyemez ve hata verir.

Ne Yapmalı?

  • Veritabanı < 5 GB: Express yeterli, diğer optimizasyonlara geçin
  • Veritabanı 5-10 GB: Acil Standard’a geçiş planlayın
  • Test/Geliştirme: Developer Edition tamamen ücretsiz ve sınırsız (üretimde kullanılamaz)

2. Kritik Tabloları Tanıyın: Yavaşlık Nerede?

Mikro ERP’de tüm tablolar eşit yoğunlukta değildir. Yavaşlığın %80’i genellikle şu 4 tabloda yaşanır:

TabloPrefixOrtalama KayıtTipik Sorun
CARI_HESAP_HAREKETLERIcha_500K – 5MEkstre, yaşlandırma raporları
STOK_HAREKETLERIsth_500K – 10MStok bakiye, maliyet raporları
SIPARISLERsip_100K – 1MAçık sipariş, teslimat raporları
STOKLARsto_10K – 100KFiyat listesi, stok arama

Tablo Boyutlarınızı Ölçün

-- En buyuk 15 tabloyu listele (satir sayisi + boyut)
SELECT TOP 15
    s.name + '.' + t.name                            AS Tablo,
    p.rows                                           AS Satir_Sayisi,
    CAST(SUM(a.total_pages) * 8.0 / 1024 AS DECIMAL(10,2)) AS Boyut_MB,
    CAST(SUM(a.used_pages) * 8.0 / 1024  AS DECIMAL(10,2)) AS Kullanilan_MB
FROM sys.tables t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.indexes i ON t.object_id = i.object_id
INNER JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
WHERE t.is_ms_shipped = 0
GROUP BY s.name, t.name, p.rows
ORDER BY SUM(a.total_pages) DESC;

Sonuçta CARI_HESAP_HAREKETLERI ve STOK_HAREKETLERI tablolarının boyutuna dikkat edin. 1 GB’ı aşan tablolarda index stratejisi kritik hale gelir.


3. Wait Stats ile Yavaşlığın Kaynağını Bulun

SQL Server neden yavaş? Cevabı Wait Statistics verir. Her sorgu çalıştığında SQL Server bir kaynağı bekler — disk, bellek, kilit veya CPU. Wait Stats bu bekleme sürelerini kaydeder.

Mevcut Wait Stats’ı Sorgulayın

-- En cok beklemeye neden olan ilk 10 wait type
SELECT TOP 10
    wait_type                        AS Bekleme_Tipi,
    wait_time_ms / 1000              AS Toplam_Bekleme_Saniye,
    signal_wait_time_ms / 1000       AS CPU_Bekleme_Saniye,
    (wait_time_ms - signal_wait_time_ms) / 1000 AS Kaynak_Bekleme_Saniye,
    waiting_tasks_count              AS Bekleme_Sayisi
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
    -- Arka plan ve bos bekleme tiplerini filtrele
    'SLEEP_TASK', 'BROKER_TO_FLUSH', 'SQLTRACE_BUFFER_FLUSH',
    'CLR_AUTO_EVENT', 'CLR_MANUAL_EVENT', 'LAZYWRITER_SLEEP',
    'CHECKPOINT_QUEUE', 'WAITFOR', 'XE_TIMER_EVENT',
    'REQUEST_FOR_DEADLOCK_SEARCH', 'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
    'DIRTY_PAGE_POLL', 'XE_DISPATCHER_WAIT', 'BROKER_EVENTHANDLER',
    'FT_IFTS_SCHEDULER_IDLE_WAIT', 'LOGMGR_QUEUE',
    'ONDEMAND_TASK_QUEUE', 'SP_SERVER_DIAGNOSTICS_SLEEP',
    'BROKER_RECEIVE_WAITFOR', 'PREEMPTIVE_OS_AUTHENTICATIONOPS'
)
  AND wait_time_ms > 0
ORDER BY wait_time_ms DESC;

Sonuçları Nasıl Yorumlayacaksınız?

Wait TypeAnlamÇözüm
PAGEIOLATCH_SH / EXVeriler diskten okunuyor, bellekte bulunamıyor🔴 RAM yetersiz veya index eksik — en yaygın Mikro ERP sorunu
CXPACKETParalel sorgu thread’leri birbirini bekliyorIndex eksik veya istatistikler güncel değil
LCK_M_S / LCK_M_XKilitlenme — bir işlem diğerini bekliyorFatura kaydı sırasında rapor çekilmesi, uzun transaction’lar
SOS_SCHEDULER_YIELDCPU yetersiz, sorgular sıra bekliyorCPU dar boğaz veya çok karmaşık sorgular
WRITELOGTransaction log yazma beklemesiLog dosyası yavaş diskte

Mikro ERP’de en sık görülen: PAGEIOLATCH — veriler bellekte tutulacak kadar RAM yok, her sorguda diskten okunuyor. Bu durumda index eklemek veya RAM artırmak en etkili çözümdür.


4. Eksik Index’leri Tespit Edin ve Akıllıca Ekleyin

SQL Server, çalıştırdığı her sorgunun “keşke şu index olsaydı daha hızlı olurdu” dediği yerleri kaydeder. Bu altın bilgiyi kullanarak doğru index’leri bulabilirsiniz.

Eksik Index Önerileri

-- SQL Server'in onerdigi eksik index'ler (en etkili ilk 15)
SELECT TOP 15
    OBJECT_NAME(d.object_id)     AS Tablo,
    d.equality_columns           AS Esitlik_Kolonlari,
    d.inequality_columns         AS Aralik_Kolonlari,
    d.included_columns           AS Dahil_Kolonlar,
    CAST(s.avg_user_impact AS INT) AS Tahmini_Etki_Yuzde,
    s.user_seeks                 AS Kullanilacak_Sayisi,
    CAST(s.avg_total_user_cost AS DECIMAL(10,2)) AS Ortalama_Maliyet
FROM sys.dm_db_missing_index_details d
INNER JOIN sys.dm_db_missing_index_groups g ON d.index_handle = g.index_handle
INNER JOIN sys.dm_db_missing_index_group_stats s ON g.index_group_handle = s.group_handle
WHERE d.database_id = DB_ID()
ORDER BY s.avg_user_impact * s.user_seeks DESC;

Mikro ERP İçin Önerilen Temel Index’ler

Aşağıdaki index’ler çoğu Mikro ERP kurulumunda fark yaratır. Bunlar hareket tablolarındaki en sık kullanılan filtreleme ve sıralama alanlarını kapsar:

-- =============================================
-- CARI_HESAP_HAREKETLERI: Tarih + Kod Filtresi
-- Fayda: Cari ekstre, yaslandirma, tahsilat raporlari
-- =============================================
IF NOT EXISTS (
    SELECT 1 FROM sys.indexes
    WHERE name = 'IX_CHA_Kod_Tarih'
      AND object_id = OBJECT_ID('dbo.CARI_HESAP_HAREKETLERI')
)
CREATE NONCLUSTERED INDEX IX_CHA_Kod_Tarih
ON dbo.CARI_HESAP_HAREKETLERI (cha_kod, cha_tarihi)
INCLUDE (cha_tip, cha_meblag, cha_evrak_tip, cha_cinsi, cha_iptal)
WITH (ONLINE = ON, FILLFACTOR = 90);
-- ONLINE=ON: Index olusturulurken tablo kilitlenmez
-- FILLFACTOR=90: Sayfalarda %10 bos alan birak (INSERT performansi icin)

-- =============================================
-- STOK_HAREKETLERI: Stok Kodu + Tarih Filtresi
-- Fayda: Stok bakiye, maliyet, hareket raporlari
-- =============================================
IF NOT EXISTS (
    SELECT 1 FROM sys.indexes
    WHERE name = 'IX_STH_StokKod_Tarih'
      AND object_id = OBJECT_ID('dbo.STOK_HAREKETLERI')
)
CREATE NONCLUSTERED INDEX IX_STH_StokKod_Tarih
ON dbo.STOK_HAREKETLERI (sth_stok_kod, sth_tarih)
INCLUDE (sth_tip, sth_miktar, sth_tutar, sth_cins, sth_giris_depo_no, sth_cikis_depo_no)
WITH (ONLINE = ON, FILLFACTOR = 90);

-- =============================================
-- STOK_HAREKETLERI: Cari Kodu Filtresi
-- Fayda: Cariye gore satis/alis raporlari
-- =============================================
IF NOT EXISTS (
    SELECT 1 FROM sys.indexes
    WHERE name = 'IX_STH_CariKod_Tarih'
      AND object_id = OBJECT_ID('dbo.STOK_HAREKETLERI')
)
CREATE NONCLUSTERED INDEX IX_STH_CariKod_Tarih
ON dbo.STOK_HAREKETLERI (sth_cari_kodu, sth_tarih)
INCLUDE (sth_stok_kod, sth_tip, sth_miktar, sth_tutar)
WITH (ONLINE = ON, FILLFACTOR = 90);

-- =============================================
-- SIPARISLER: Musteri Kodu + Tarih Filtresi
-- Fayda: Acik siparis, teslimat raporlari
-- =============================================
IF NOT EXISTS (
    SELECT 1 FROM sys.indexes
    WHERE name = 'IX_SIP_MusteriKod_Tarih'
      AND object_id = OBJECT_ID('dbo.SIPARISLER')
)
CREATE NONCLUSTERED INDEX IX_SIP_MusteriKod_Tarih
ON dbo.SIPARISLER (sip_musteri_kod, sip_tarih)
INCLUDE (sip_stok_kod, sip_miktar, sip_teslim_miktar, sip_tip, sip_cins)
WITH (ONLINE = ON, FILLFACTOR = 90);

⚡ Önemli: Index Ekleme Kuralları

  1. Körlemesine eklemeyin. Önce eksik index sorgusunu çalıştırın, SQL Server’ın önerisini görün
  2. INCLUDE kolonlarını ayarlayın. Raporda gösterdiğiniz alanları INCLUDE’a ekleyin — Key Lookup’ı önler
  3. Test edin. Canlı ortamda index oluşturmadan önce test ortamında deneyin
  4. Gece çalıştırın. Büyük tablolarda index oluşturma uzun sürebilir (ONLINE=ON kullanın)
  5. Fazla index = yavaş yazma. Her INSERT ve UPDATE işleminde tüm index’ler güncellenir. Tablo başına 5-7 index idealdir

5. TempDB Optimizasyonu

TempDB, SQL Server’ın geçici işlem alanıdır. Sıralama, gruplama, JOIN, cursor ve geçici tablolar burayı kullanır. Mikro ERP’deki raporların çoğu karmaşık JOIN ve GROUP BY işlemleri yaptığı için TempDB performansı kritiktir.

TempDB Durumunu Kontrol Edin

-- TempDB dosya durumu ve boyutlari
SELECT
    name                         AS Dosya_Adi,
    physical_name                AS Dosya_Yolu,
    size * 8 / 1024              AS Boyut_MB,
    growth                       AS Buyume_Ayari,
    CASE is_percent_growth
        WHEN 1 THEN CAST(growth AS VARCHAR) + '%'
        ELSE CAST(growth * 8 / 1024 AS VARCHAR) + ' MB'
    END                          AS Buyume_Miktari
FROM tempdb.sys.database_files;

TempDB Optimizasyon Kuralları

Kural 1: Dosya Sayısı = CPU Çekirdek Sayısı (max 8)

-- Sunucunuzdaki CPU cekirdek sayisini kontrol edin
SELECT cpu_count AS Toplam_CPU, hyperthread_ratio AS HT_Orani
FROM sys.dm_os_sys_info;

Örneğin 4 çekirdekli bir sunucuda TempDB’de 4 data file olmalıdır. Tüm dosyalar aynı boyutta olmalı:

-- TempDB'ye yeni dosya ekleme (ornek: 4 cekirdek icin 4 dosya, her biri 512 MB)
-- NOT: Bu komutu calistirmadan once mevcut dosya sayinizi kontrol edin
ALTER DATABASE tempdb
ADD FILE (
    NAME = 'tempdev2',
    FILENAME = 'D:\SQLData\tempdev2.ndf',  -- Hizli bir SSD yolu verin
    SIZE = 512MB,
    FILEGROWTH = 256MB
);
-- Diger dosyalar icin tekrarlayin (tempdev3, tempdev4)

Kural 2: TempDB’yi Ayrı Diske Taşıyın

TempDB kesinlikle ana veritabanı ile aynı diskte olmamalıdır. Mümkünse SSD/NVMe üzerine taşıyın.

Kural 3: Otomatik Küçültme (Shrink) Kullanmayın

tempdb için asla DBCC SHRINKFILE çalıştırmayın. SQL Server yeniden başladığında TempDB zaten başlangıç boyutuna döner.


6. En Yavaş Sorguları Bulun

Hangi sorgular en çok kaynak tüketiyor? SQL Server bunu sizin için kaydeder:

Top 10 Kaynak Tüketen Sorgu

-- En cok CPU + IO tuketen 10 sorgu
SELECT TOP 10
    SUBSTRING(qt.text, (qs.statement_start_offset / 2) + 1,
        (CASE qs.statement_end_offset
            WHEN -1 THEN DATALENGTH(qt.text)
            ELSE qs.statement_end_offset
        END - qs.statement_start_offset) / 2 + 1) AS Sorgu_Metni,
    qs.execution_count                             AS Calisma_Sayisi,
    qs.total_elapsed_time / 1000                   AS Toplam_Sure_ms,
    qs.total_elapsed_time / qs.execution_count / 1000 AS Ortalama_Sure_ms,
    qs.total_logical_reads                         AS Toplam_Okuma,
    qs.total_logical_reads / qs.execution_count    AS Ortalama_Okuma,
    qs.total_worker_time / 1000                    AS Toplam_CPU_ms
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
WHERE qt.dbid = DB_ID()
ORDER BY qs.total_elapsed_time DESC;

Execution Plan Okuma Rehberi

Yavaş bir sorguyu bulduktan sonra çalıştırma planını görüntüleyin:

-- Sorgunun execution plan'ini goruntule
SET STATISTICS IO ON;
SET STATISTICS TIME ON;

-- Yavaş sorgunuzu buraya yapistirin
-- Ornek: Cari ekstre raporu
SELECT cha_kod, cha_tarihi, cha_tip, cha_meblag
FROM CARI_HESAP_HAREKETLERI WITH (NOLOCK)
WHERE cha_kod = '120.001'
  AND cha_tarihi >= '2026-01-01'
  AND cha_iptal = 0
ORDER BY cha_tarihi;

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

SSMS’de çalıştırma planını görsel olarak görmek için: Ctrl + M (Include Actual Execution Plan) tuşlayın, sorguyu çalıştırın, alt paneldeki “Execution Plan” sekmesine bakın.

Execution Plan’da Neye Bakmalı?

Operasyonİyi mi?Anlam
Index Seek✅ İyiIndex üzerinden doğrudan erişim — hızlı
Index Scan⚠️ Kötü olabilirTüm index taranıyor — çok kayıt okuyor
Table Scan🔴 KötüTüm tablo satır satır taranıyor — index yok
Key Lookup⚠️ Kötü olabilirIndex buldu ama ek kolonlar için tabloya geri dönüyor — INCLUDE eksik
Sort⚠️ DikkatBellek yetmezse TempDB’ye taşar — yavaşlatır
Hash Match⚠️ DikkatBüyük tablolarda JOIN — bellek yoğun

Hedef: Table ScanIndex Seek dönüşümü. Bir tablo taramasını index aramasına çevirmek sorguyu 10-100x hızlandırabilir.


7. Otomatik Bakım Planı Oluşturun

Veritabanı bakımı yapılmazsa zamanla yavaşlar. Index’ler parçalanır, istatistikler eskir, log dosyası şişer. Aşağıdaki bakım işlemlerini haftalık çalıştırın:

Index Bakımı (Reorganize / Rebuild)

-- Index parcalanma oranlarini kontrol et
SELECT
    OBJECT_NAME(ips.object_id)   AS Tablo,
    i.name                       AS Index_Adi,
    ips.avg_fragmentation_in_percent AS Parcalanma_Yuzde,
    ips.page_count               AS Sayfa_Sayisi,
    CASE
        WHEN ips.avg_fragmentation_in_percent < 10 THEN 'Islem gereksiz'
        WHEN ips.avg_fragmentation_in_percent < 30 THEN 'REORGANIZE onerisi'
        ELSE 'REBUILD onerisi'
    END                          AS Oneri
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
INNER JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 5
  AND ips.page_count > 1000  -- Kucuk tablolari atla
ORDER BY ips.avg_fragmentation_in_percent DESC;

Parçalanma Kuralları

Parçalanma %İşlemKomut
< %10Bir şey yapma
%10 – %30ReorganizeALTER INDEX [IndexAdi] ON [Tablo] REORGANIZE;
> %30RebuildALTER INDEX [IndexAdi] ON [Tablo] REBUILD WITH (ONLINE = ON);

Tüm Index’leri Otomatik Bakım (Script)

-- Tum tablolardaki parcalanmis index'leri otomatik bakim yap
DECLARE @TabloDB NVARCHAR(256), @IndexDB NVARCHAR(256), @SqlDB NVARCHAR(MAX);
DECLARE @Frag FLOAT;

DECLARE IndexBakim CURSOR FOR
SELECT
    QUOTENAME(OBJECT_SCHEMA_NAME(ips.object_id)) + '.' + QUOTENAME(OBJECT_NAME(ips.object_id)),
    QUOTENAME(i.name),
    ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
INNER JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 10
  AND ips.page_count > 1000
  AND i.name IS NOT NULL;

OPEN IndexBakim;
FETCH NEXT FROM IndexBakim INTO @TabloDB, @IndexDB, @Frag;

WHILE @@FETCH_STATUS = 0
BEGIN
    IF @Frag < 30
        SET @SqlDB = N'ALTER INDEX ' + @IndexDB + N' ON ' + @TabloDB + N' REORGANIZE;';
    ELSE
        SET @SqlDB = N'ALTER INDEX ' + @IndexDB + N' ON ' + @TabloDB + N' REBUILD WITH (ONLINE = ON);';

    PRINT @SqlDB;
    EXEC sp_executesql @SqlDB;

    FETCH NEXT FROM IndexBakim INTO @TabloDB, @IndexDB, @Frag;
END

CLOSE IndexBakim;
DEALLOCATE IndexBakim;

PRINT 'Index bakim tamamlandi.';

İstatistikleri Güncelle

-- Tum tablolarin istatistiklerini guncelle
-- Haftada 1 calistirin, tercihen gece
EXEC sp_updatestats;

-- Veya sadece kritik tablolar icin:
UPDATE STATISTICS dbo.CARI_HESAP_HAREKETLERI WITH FULLSCAN;
UPDATE STATISTICS dbo.STOK_HAREKETLERI WITH FULLSCAN;
UPDATE STATISTICS dbo.SIPARISLER WITH FULLSCAN;

FULLSCAN tablonun %100’ünü okuyarak en doğru istatistiği üretir. Tablo çok büyükse SAMPLE 50 PERCENT kullanabilirsiniz.


Bonus: Mikro ERP’ye Özgü Hızlı Kazanımlar

WITH (NOLOCK) Kullanımı

Raporlama sorgularınızda WITH (NOLOCK) kullanmak kilit bekleme süresini ortadan kaldırır. Mikro ERP’nin kendi raporları zaten bu tekniği kullanır:

-- Raporlama icin: Kilitsiz okuma
SELECT cha_kod, SUM(cha_meblag) AS Toplam
FROM CARI_HESAP_HAREKETLERI WITH (NOLOCK)
WHERE cha_tarihi >= '2026-01-01'
  AND cha_iptal = 0
GROUP BY cha_kod;

⚠️ WITH (NOLOCK) uncommitted (henüz onaylanmamış) verileri de okuyabilir. Rapor sorgularında kabul edilebilir ama veri güncelleyen sorgularda asla kullanmayın.

Kullanılmayan Index’leri Tespit Edin

Çok fazla index yazma performansını düşürür. Hiç kullanılmayan index’leri tespit edin:

-- Son SQL Server restart'indan bu yana hic kullanilmamis index'ler
SELECT
    OBJECT_NAME(i.object_id) AS Tablo,
    i.name                   AS Index_Adi,
    i.type_desc              AS Index_Tipi,
    dm.user_seeks            AS Seek_Sayisi,
    dm.user_scans            AS Scan_Sayisi,
    dm.user_lookups          AS Lookup_Sayisi,
    dm.user_updates          AS Guncelleme_Sayisi
FROM sys.indexes i
LEFT JOIN sys.dm_db_index_usage_stats dm ON i.object_id = dm.object_id
    AND i.index_id = dm.index_id
    AND dm.database_id = DB_ID()
WHERE OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1
  AND i.type_desc = 'NONCLUSTERED'
  AND ISNULL(dm.user_seeks, 0) + ISNULL(dm.user_scans, 0) + ISNULL(dm.user_lookups, 0) = 0
  AND dm.user_updates > 100  -- Sadece guncellenen ama hic okunmayan
ORDER BY dm.user_updates DESC;

SQL Server Bellek Ayarı

SQL Server varsayılan olarak sunucudaki tüm RAM’i almaya çalışır. Mikro ERP sunucusunda başka uygulamalar da çalışıyorsa (Mikro istemci, Windows servisleri) SQL Server’a maksimum bellek limiti verin:

-- SQL Server'a maksimum bellek siniri ver
-- Toplam RAM: 16 GB ise → SQL Server'a 12 GB ver, 4 GB isletim sistemine birak
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;

EXEC sp_configure 'max server memory (MB)', 12288;  -- 12 GB = 12 * 1024
RECONFIGURE;

-- Ayari dogrula
EXEC sp_configure 'max server memory (MB)';

Genel kural: Toplam RAM’in %75-80’ini SQL Server’a verin. Kalan %20-25 işletim sistemi ve diğer servisler içindir.


Kontrol Listesi: Hemen Yapılacaklar

#İşlemKomut/AdımÖncelik
1SQL Server sürümünü kontrol etSELECT @@VERSION🔴
2Veritabanı boyutunu kontrol etYukarıdaki sorguyu çalıştır🔴
3Wait Stats’ı okuYukarıdaki sorguyu çalıştır🔴
4Eksik index önerilerini alsys.dm_db_missing_index_details🔴
5Kritik tablolara index ekle4 temel index’i oluştur🟡
6TempDB dosya sayısını kontrol etCPU çekirdeğe eşitle🟡
7Index parçalanmasını kontrol etBakım scriptini çalıştır🟡
8İstatistikleri güncellesp_updatestats🟡
9Max Memory ayarlasp_configure🟢
10Haftalık bakım planı kurSQL Agent Job oluştur🟢

Sonuç

Mikro ERP yavaşlığının çözümü çoğunlukla yazılım değişikliği değil, veritabanı yapılandırması ve düzenli bakımtır. Bu rehberdeki adımları sırayla uygularsanız:

  • Wait Stats ile gerçek darboğazı tespit edersiniz (tahmin değil, veri)
  • Index stratejisi ile CARI_HESAP_HAREKETLERI ve STOK_HAREKETLERI sorgularını 5-10x hızlandırırsınız
  • TempDB optimizasyonu ile raporlardaki sıralama ve gruplama işlemlerini rahatlatırsınız
  • Otomatik bakım ile performansın zamanla düşmesini engellersiniz

İlgili yazılar:

📚 İlgili Yazılar