Brak produktów w koszyku.

Optymalizacja bazy danych w programach InsERT: Subiekt GT, Subiekt nexo, Rewizor i Navireo

Aktualizacja: 26 sierpnia 2026

Program działa wolno, konserwacja bazy z Programu serwisowego została wykonana i nic nie dała, sprzęt jest mocny. Gdzie szukać dalej?

To pytanie dostajemy regularnie i ten artykuł jest na nie odpowiedzią. Opisujemy, co realnie spowalnia bazy programów InsERT, jak to zdiagnozować, z zapytaniami, które możesz uruchomić sam, i gdzie przebiega granica tego, co zrobisz u siebie bez niczyjej pomocy. Materiał pochodzi z ponad 200 baz, które przeszły przez nasze ręce, i z naszych zgłoszeń serwisowych z ostatnich kilkunastu miesięcy.

Artykuł dotyczy Subiekta GT, Subiekta nexo, Rewizora GT, Rewizora nexo, Rachmistrza, Gratyfikanta, Gestora, Biura nexo, Navireo i Sello NX oraz każdego innego systemu opartego o Microsoft SQL Server.

Objaw a najbardziej prawdopodobna przyczyna

Listę zebraliśmy z własnych zgłoszeń serwisowych z ostatnich kilkunastu miesięcy.

Objaw Najczęstsza przyczyna
Otwarcie zakładki (np. Zamówienia od klientów) trwa minutę i dłużej Duży wolumen dokumentów i brak indeksu pokrywającego zapytanie listy
Program działał szybko, od kilku dni zwalnia Fragmentacja indeksów lub zwietrzałe statystyki
Wolno dopiero po aktualizacji programu Nieaktualne statystyki po konwersji bazy i przekompilowane plany
Dodanie jednej pozycji do dokumentu trwa 10–60 sekund, zwłaszcza po nocnej konserwacji lub restarcie Zły plan wykonania utrwalony w pamięci podręcznej (param-sniffing)
Wolno u jednego użytkownika, przy tym samym sprzęcie Blokady na obiektach, wpisy w tabeli ins_Blokada, wiszące sesje
Wolno u wszystkich jednocześnie, o określonych porach Zadania w tle, integratory, kopia zapasowa w godzinach pracy
Duże wyliczenia (JPK, zamknięcie roku, amortyzacja) trwają godzinami Zła konfiguracja równoległości przy wielu węzłach NUMA
Raport własny SQL: 2 sekundy w SSMS, 20 minut w programie Brak unikalnego identyfikatora w pierwszej kolumnie zestawienia
Zawiesza się dopiero pod koniec dnia pracy Narastające blokady i niezamknięte sesje
Pulpit zdalny wolniejszy niż praca lokalna przy tym samym SQL Wąskim gardłem nie jest baza, tylko taktowanie rdzenia terminala

Dlaczego konserwacja z Programu serwisowego nie wystarcza

Program serwisowy InsERT robi dwie ważne rzeczy: odbudowuje indeksy i aktualizuje statystyki. To jest sensowne i należy z tego korzystać. Problem polega na tym, że pokrywa część realnych przyczyn spowolnień, nie wszystkie.

Konserwacja nie doda indeksu, którego w bazie nie ma, a konkretne zapytanie go potrzebuje. Nie wyczyści pamięci podręcznej planów wykonania. Nie zmieni konfiguracji instancji SQL Server. Nie pokaże, które zapytanie realnie zjada czas. Nie rozwiąże blokad między użytkownikami, nie naprawi konfiguracji plików bazy i logu transakcyjnego i nie wykryje, że wąskim gardłem jest serwer terminali.

Ścieżka „zrobiłem konserwację, nic to nie dało” jest więc zupełnie normalna. Znaczy tylko tyle, że przyczyna leży poza zakresem tego narzędzia.

Osiem przyczyn spowolnień w bazach InsERT

1. Fragmentacja indeksów

Najbardziej znana przyczyna i jednocześnie najczęściej źle obsługiwana.

Próg 30 procent z ogólnych poradników o SQL Server jest złą regułą decyzyjną dla bazy ERP. Nie dlatego, że jest za wysoki albo za niski w oderwaniu od kontekstu, tylko dlatego, że jedna liczba nie opisuje bazy, w której część tabel jest zapisywana setki razy na minutę, a część nie zmienia się miesiącami. Właściwy próg ustalamy pomiarem dla konkretnej bazy i konkretnej tabeli.

Odbudowa online (REORGANIZE) ma swoją granicę skuteczności. Powyżej pewnego poziomu fragmentacji przestaje spełniać rolę, choć nadal nie blokuje pracy użytkowników i dlatego bywa mylnie uznawana za wystarczającą. Wyżej potrzebna jest odbudowa offline (REBUILD), czyli okno serwisowe. A jeżeli między pełnymi odbudowami pracują integratory, czyli import zamówień, e-commerce, WMS albo KSeF, fragmentacja wraca znacznie szybciej, niż zakłada standardowy harmonogram.

Jest rzecz, której nie da się wyczytać z poradników, a która przesądza o skuteczności harmonogramu: tempo powrotu fragmentacji różni się o rząd wielkości między indeksami tej samej tabeli. U jednego z naszych klientów, z ciągłym strumieniem zamówień z kilku rynków marketplace, prowadzimy dziennik każdej operacji konserwacyjnej. Z ponad 700 tysięcy pomiarów zebranych przez piętnaście miesięcy widać wyraźnie: na tej samej tabeli dokumentów jeden indeks wraca do wysokiej fragmentacji w pół godziny, a inny potrzebuje na to kilku godzin. Decyduje o tym nie wielkość tabeli, tylko to, które kolumny wchodzą w skład indeksu i czy są modyfikowane w miejscu, czy tylko dopisywane na końcu.

Praktyczny wniosek: harmonogram konserwacji ustala się per indeks, na podstawie pomiaru, a nie per baza na podstawie tabeli z internetu. Plan, który odbudowuje wszystko z jedną częstotliwością, dla części obiektów jest za rzadki, a dla reszty to zmarnowana praca i niepotrzebne blokady.

U jednego z klientów zmierzyliśmy fragmentację 21 procent na pojedynczej tabeli, a ręczna odbudowa offline rozwiązała problem tego samego dnia. Ten przypadek nie dowodzi jednak tego, co się na pierwszy rzut oka wydaje: odbudowa indeksu jednocześnie odświeża statystyki i unieważnia plany wykonania dla tego obiektu, więc bez osobnego pomiaru nie da się rozstrzygnąć, która z trzech rzeczy zadziałała. Tani test rozstrzygający: uruchomić najpierw sam UPDATE STATISTICS ... WITH FULLSCAN i sprawdzić, czy problem znika bez odbudowy.

Fragmentacja nie jest jednak odpowiedzią na wszystko. Mieliśmy zgłoszenie, w którym wczytywanie kodów dostaw trwało 6–10 sekund, a fragmentacja na tabelach partii i rozchodów wynosiła poniżej 1 procenta. Odbudowa niczego nie zmieniła, bo przyczyna była inna. Opisujemy ją w punkcie następnym.

2. Zły plan wykonania utrwalony w pamięci podręcznej

SQL Server kompiluje plan zapytania dla parametrów, z jakimi trafiło ono do niego jako pierwsze po restarcie albo po konserwacji, i stosuje ten plan do wszystkich kolejnych wywołań. Jeżeli pierwszy zestaw parametrów był nietypowy, cała firma pracuje przez kolejne dni na planie dobranym do wyjątku. Indeksy są zdrowe, statystyki świeże, a jedna konkretna operacja trwa dziesiątki sekund. Objawem rozstrzygającym jest to, że problem pojawia się po nocnej konserwacji, a nie przed nią.

To najczęstsza przyczyna spowolnień w linii nexo, którą rozpoznajemy w zgłoszeniach. Opisaliśmy ją osobno, razem z przypadkiem, w którym operacja narastała od 6 sekund do 60 i timeoutów: Program zwalnia po nocnej konserwacji: zły plan wykonania w Subiekcie nexo.

3. Brak indeksów pod konkretne zapytania programu

Programy InsERT mają swoje indeksy, ale są one projektowane pod przeciętną bazę. Przy 500 tysiącach dokumentów albo 3 milionach rozrachunków „przeciętna” przestaje obowiązywać. W bazie Subiekta GT jednego z klientów dołożyliśmy pięć indeksów na tabelach dokumentów i ruchu magazynowego, bo bazę dławiła suma bardzo częstych, pojedynczo lekkich zapytań.

Indeks przyspiesza odczyt, ale każdy zapis musi go zaktualizować. Zbyt szerokie indeksy, zwłaszcza z rozbudowaną listą INCLUDE, potrafią spowolnić dodawanie dokumentu oraz pracę integracji korzystających ze Sfery i z widoków SQL. Dokładanie własnych indeksów do bazy InsERT wymaga też utrzymania, bo aktualizacja programu może zakładać konkretną strukturę. Każdy indeks, który dokładamy, jest spisany i weryfikowany po aktualizacjach.

4. Konfiguracja instancji SQL Server

Instalacja klikana bez zmian domyślnych zostawia ustawienia, które dla systemu ERP bywają szkodliwe: brak ograniczenia równoległości, brak limitu pamięci dla silnika, próg zrównoleglania z lat dziewięćdziesiątych i brak wykluczeń antywirusa dla plików bazy. Każde z nich z osobna potrafi kosztować godziny przy dużych wyliczeniach.

Co konkretnie ustawić i na jakie wartości, opisujemy tutaj: Jak ustawić SQL Server pod Subiekta i Rewizora: MAXDOP, pamięć, tempdb.

5. Blokady, zakleszczenia i triggery

Jeżeli spowolnienie dotyczy jednego użytkownika albo narasta w ciągu dnia i znika po restarcie, przyczyną są zwykle blokady, a nie wydajność zapytań. Typowe źródła: niewylogowywanie się z programu i utrzymywanie sesji dłużej niż dobę, wiszące wpisy w tabeli ins_Blokada, procesy w tle trzymające transakcję dłużej, niż powinny.

Osobno własne triggery. Trigger blokuje tabelę i przy większym obciążeniu prowadzi do zakleszczeń, a przy każdej aktualizacji programu trzeba go wyłączać. Jeżeli zadanie da się wykonać nocnym zadaniem wsadowym, wybieramy zadanie wsadowe.

6. Log transakcyjny i pliki bazy

Autogrowth ustawiony procentowo daje coraz większe skoki i zauważalne przycięcia w pracy. Log powinien leżeć na wolumenie o niskim opóźnieniu zapisu, bo to jedyne miejsce, w którym dysk naprawdę decyduje o odczuwalnej wydajności. tempdb wymaga osobnej uwagi. Szczegóły w artykule o konfiguracji instancji.

7. Sprzęt, terminale i architektura

Mocny serwer nie oznacza szybkiego nexo. Programy tej linii w praktyce nie wykorzystują więcej niż dwóch rdzeni do własnej pracy, a start programu obciąża głównie procesor. Serwer z 96 rdzeniami o niskim taktowaniu bazowym uruchomi program wolniej niż zwykły komputer z wysokim zegarem pojedynczego rdzenia.

Serwer terminali to osobny problem od serwera SQL. Zdarza się konfiguracja, w której baza się nudzi, stanowiska lokalne pracują dobrze, a użytkownicy na pulpicie zdalnym mają zawieszenia. Wtedy nie ma czego optymalizować w bazie.

Po restarcie serwera pierwsze 10–20 minut jest wolniejsze, bo bufor bazy nie jest jeszcze wypełniony. To normalne. SQL Server Express ma z kolei limit 10 GB na bazę oraz ograniczenie pamięci i rdzeni, a zbliżanie się do tych limitów jest samodzielną przyczyną spowolnień.

8. Objętość danych i procesy aplikacyjne

Część problemów nie leży w bazie, tylko w tym, ile danych program próbuje załadować. Klasyczny przypadek to zakładka Zamówienia od klientów przy 500 tysiącach pozycji: program ładuje listę, zanim nałoży filtr. Podniesienie Command Timeout i Connection Timeout w rejestrze do 180 sekund jest rozwiązaniem pomostowym. Docelowo trzeba ograniczyć zakres ładowanych danych, dołożyć indeks pokrywający zapytanie listy albo zarchiwizować zrealizowane zamówienia.

Podobnie raport własny SQL, który w SSMS wykonuje się w 2 sekundy, a w programie 20 minut. Częsta przyczyna to brak unikalnego identyfikatora w pierwszej kolumnie zestawienia. Program musi wtedy wykonać dodatkową pracę na każdym wierszu.

Zapytania diagnostyczne, które możesz uruchomić sam

Uruchom je w SQL Server Management Studio na bazie podmiotu. Wszystkie są wyłącznie do odczytu i nie zmieniają niczego w bazie.

Potrzebna jest przy tym podstawowa wiedza o SQL Server: trzeba umieć połączyć się z właściwą instancją, wskazać bazę odpowiedniego podmiotu i odczytać wynik. Jeżeli nigdy tego nie robiłeś, poproś osobę, która opiekuje się u Was serwerem. Same zapytania niczego nie zepsują, ale uruchomione na złej bazie albo złej instancji dadzą mylący obraz i można na ich podstawie wyciągnąć błędny wniosek.

Fragmentacja indeksów

SELECT
    OBJECT_NAME(ips.object_id)         AS tabela,
    i.name                             AS indeks,
    ips.avg_fragmentation_in_percent   AS fragmentacja_proc,
    ips.page_count                     AS strony
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i
  ON i.object_id = ips.object_id AND i.index_id = ips.index_id
WHERE ips.page_count > 1000
  AND ips.avg_fragmentation_in_percent > 5
ORDER BY ips.avg_fragmentation_in_percent DESC;

Interpretacja: filtr ustawiony jest nisko celowo, żeby zobaczyć pełny obraz, a nie tylko skrajne przypadki. Próg, przy którym fragmentacja zaczyna być odczuwalna dla użytkowników, jest inny dla linii GT i inny dla nexo, i zależy od tego, jak często dana tabela jest zapisywana.

Najdroższe zapytania

SELECT TOP 20
    qs.total_worker_time / 1000                      AS cpu_ms_lacznie,
    qs.execution_count                               AS wykonan,
    qs.total_worker_time / qs.execution_count / 1000 AS cpu_ms_srednio,
    qs.total_elapsed_time / qs.execution_count / 1000 AS czas_ms_srednio,
    SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
        ((CASE qs.statement_end_offset WHEN -1
            THEN DATALENGTH(st.text)
            ELSE qs.statement_end_offset END - qs.statement_start_offset)/2)+1) AS zapytanie
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY qs.total_worker_time DESC;

Interpretacja: patrz na cpu_ms_lacznie. Zapytanie wykonywane 200 tysięcy razy po 5 ms kosztuje więcej niż raport uruchamiany raz dziennie przez minutę.

Aktualne blokady

SELECT
    r.session_id          AS sesja,
    r.blocking_session_id AS blokowana_przez,
    r.wait_type           AS typ_oczekiwania,
    r.wait_time / 1000    AS czeka_sek,
    s.login_name          AS uzytkownik,
    s.host_name           AS stanowisko,
    t.text                AS zapytanie
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id <> 0;

Interpretacja: jeżeli w godzinach pracy stale coś tu widać, problemem są blokady, a nie wydajność zapytań.

Konfiguracja instancji

SELECT name, value_in_use
FROM sys.configurations
WHERE name IN (
    'max degree of parallelism',
    'cost threshold for parallelism',
    'max server memory (MB)',
    'min server memory (MB)'
);

Interpretacja: max degree of parallelism = 0 oznacza brak ograniczenia. cost threshold for parallelism = 5 to wartość domyślna, dla ERP zwykle za niska. max server memory (MB) = 2147483647 oznacza brak limitu.

Gdy wynik nic nie mówi

To normalne przy pierwszym uruchomieniu. Zapytanie o najdroższe zapytania pokazuje dane od ostatniego restartu instancji, więc po niedawnym restarcie będzie prawie puste. Zapytanie o blokady pokazuje tylko to, co dzieje się w tej sekundzie, więc trzeba je puścić kilka razy w godzinach szczytu, a nie wieczorem. A jeżeli fragmentacja wygląda dobrze i użytkownicy nadal czekają, przejdź do punktu 2 z listy przyczyn. To najczęstszy przypadek, w którym wszystkie standardowe wskaźniki są zielone.

Gdzie kończy się samodzielna diagnostyka

Wszystko powyżej możesz zrobić sam. Zapytania są bezpieczne, odczytanie wyników nie wymaga zaawansowanej wiedzy o SQL Server, a przy bazie poniżej 2 GB bez integracji zwykle wystarczy poprawnie ustawiony harmonogram konserwacji i wykluczenia antywirusa.

Granica przebiega w miejscu, w którym trzeba mierzyć w czasie realnej pracy. Pojedynczy zrzut z pustej bazy o dwudziestej drugiej niczego nie pokaże. Potrzebne są dwie do trzech godzin obserwacji w szczycie, Query Store włączony wcześniej, a przy problemach sporadycznych sesja Extended Events zostawiona na cały dzień. To jest dzień pracy kogoś, kto robi to nie pierwszy raz, i najczęściej właśnie w tym miejscu ludzie odpuszczają, bo nie mają jak wygospodarować tego czasu obok bieżących obowiązków.

Analiza wydajności bazy danych przez profesjonalistę

Stała cena, praca zdalna, start w 3–5 dni roboczych. Wywiad, pomiar w godzinach realnej pracy użytkowników, przegląd bazy i konfiguracji, a na końcu dokument, w którym jest napisane, co konkretnie powoduje spowolnienie. Nie „baza wymagała optymalizacji”, tylko na przykład: „zapytanie listy zamówień wykonuje pełny skan tabeli X, brakuje indeksu pokrywającego, 47 s przy 500 tys. rekordów”. Jeżeli problem nie jest skomplikowany, w tej samej cenie dostajesz również rozwiązanie.

Jeżeli w trakcie okaże się, że sprawa jest większa, dzwonimy, zanim wyjdziemy poza umówiony zakres. A jeżeli przyczyną jest sprzęt, sieć albo konfiguracja terminala, też to napiszemy, nawet gdy oznacza to, że nie mamy Ci nic do sprzedania.

Zamów analizę wydajności bazy danych

Jak często wykonywać optymalizację

Nie ma jednej dobrej odpowiedzi. Częstotliwość wynika z tempa, w jakim fragmentacja wraca po odbudowie, a to tempo różni się o rząd wielkości w zależności od tego, czy w bazie pracują integratory.

  • Baza bez integratorów, umiarkowany przyrost: zwykle wystarczy okresowy przegląd, wykonywany na podstawie Waszych obserwacji, a nie sztywnego kalendarza.
  • Baza z integracjami (e-commerce, WMS, KSeF, import zamówień): tu standardowy harmonogram najczęściej okazuje się za rzadki. Właściwy interwał ustala się, mierząc, po ilu dniach fragmentacja wraca do poziomu odczuwalnego przez użytkowników.
  • Zawsze po dużej aktualizacji programu: aktualizacja statystyk i weryfikacja planów wykonania.

Harmonogram ustawiony raz i niezmieniany przez trzy lata jest częstą przyczyną powrotu problemu. Dlatego przy bazach z integracjami dobieramy go indywidualnie i korygujemy w czasie, w ramach stałej opieki nad bazą danych.

Czego nie robimy

  • Nie robimy SHRINK bazy jako elementu optymalizacji. Powoduje drastyczną fragmentację indeksów i w dłuższej perspektywie spowalnia system.
  • Nie zmieniamy struktury tabel InsERT. Aktualizacje programu zakładają konkretną strukturę.
  • Nie zakładamy triggerów na tabelach, jeżeli da się tego uniknąć.
  • Nie dokładamy indeksów bez dokumentacji. Każdy dodany indeks musi być spisany i sprawdzany po aktualizacjach.
  • Nie mówimy „baza została zoptymalizowana” bez pomiaru przed i po.

Optymalizacja i diagnostyka baz danych SQL Server dla programów InsERT: Subiekt GT, Subiekt nexo, Rewizor GT, Rewizor nexo, Rachmistrz, Gratyfikant, Gestor, Biuro nexo, Navireo i Sello NX. Najczęstsze zgłoszenia, z jakimi się do nas zwracacie: wolno działa Subiekt, nexo długo dodaje pozycję do dokumentu, Rewizor długo liczy JPK, program zwolnił po aktualizacji, konserwacja bazy nic nie dała.

Zapytaj o KSeF Zobacz wpisy na blogu o
KSeF 2.0