Files
DBAdmin/journals/2026-06-18.md
T
2026-06-18 07:47:40 +00:00

16 KiB
Raw Blame History

title, date, tags, Status, type
title date tags Status type
Daily Note - 2026-06-18 2026-06-18 09:26:51
Active DailyNote

Oracle database backup server (euniappbakprl01) Oracle databases product.bisnode.cz public.bisnode.cz

https://dnbenterprise.atlassian.net/wiki/spaces/AllmantITKredit/pages/1855684994/CZ+disaster+recovery+plan

dev servers devel1.bisnode.cz - free to restart devel2.bisnode.cz


🧾 Kluczowe wnioski

1. Przegląd architektury kopii zapasowych Oceniane są dwa główne podejścia:

  • Kopia zapasowa wypychana (push) z hosta Oracle do systemu backupu VM
  • Kopia zapasowa pobierana (pull) przez system backupu VM bezpośrednio z bazy danych/serwera Decyzja nie została ostatecznie podjęta → wymaga testów i porównania.

2. Potrzeba walidacji w środowisku testowym Wymagane jest środowisko testowe (Oracle + backup + przywracanie) w celu walidacji:

  • wykonalności
  • scenariuszy przywracania Dostępne zasoby:
  • Istniejące serwery deweloperskie (jeden można bez problemu restartować w ciągu dnia)
  • Dodatkowy serwer testowy Linux dostępny do izolowanych testów

3. Obecna strategia kopii zapasowych jest nieefektywna Obecnie skonfigurowane są codzienne pełne kopie zapasowe (full backups). Zidentyfikowane problemy:

  • duża rotacja wolumenu danych
  • wpływ na wydajność maszyny wirtualnej i bazy danych
  • nieefektywne wykorzystanie przestrzeni dyskowej Ogólna zgoda zespołu: to podejście należy zmienić.

4. Proponowana zmiana strategii kopii zapasowych Przejście na:

  • Cotygodniowe pełne kopie zapasowe
  • Codzienne przyrostowe/różnicowe kopie zapasowe
  • Częste kopie zapasowe logów (co kilka godzin) Omówione korzyści:
  • mniejsze zużycie przestrzeni dyskowej
  • poprawa wydajności
  • możliwość przywrócenia bazy do określonego momentu w czasie (point-in-time recovery)

5. Zarządzanie zmianą i kwestie komunikacyjne Zmiana musi przejść przez standardowy proces zarządzania zmianami (~5 dni roboczych). Wymagana komunikacja:

  • Dostawca Oracle (Digitech)
  • Wewnętrzni interesariusze Jeśli wymagana będzie przerwa w działaniu (downtime):
  • Konieczne powiadomienie klienta z co najmniej 2-tygodniowym wyprzedzeniem (ze względu na SLA). Obecnie nie jest jasne, czy wymagany będzie restart bazy danych → należy to zweryfikować.

6. Planowanie kolejnych kroków Spotkanie kontrolne (follow-up) prawdopodobnie zostanie zaplanowane na przyszły tydzień.

Zadania do wykonania (z przypisanymi osobami)

🔧 Techniczne / Wdrożeniowe

  • Ocena podejść do kopii zapasowych (push vs pull z VM) — Właściciel: Paweł Domański (wsparcie: Łukasz)
  • Konfiguracja środowiska testowego (walidacja Oracle + backup + przywracanie) — Właściciel: Paweł Domański (wsparcie: Michal Pavlina ws. dostępności serwerów dev)
  • Użycie serwerów deweloperskich do testów — Właściciel: Michal Pavlina (uwaga: jeden z serwerów potwierdzony jako bezpieczny do restartów w ciągu dnia)
  • Sprawdzenie, czy zmiana strategii kopii zapasowych wymaga restartu bazy danych — Właściciel: Paweł Domański

📦 Zmiana strategii kopii zapasowych

  • Zaprojektowanie nowego harmonogramu kopii zapasowych (cotygodniowy full + przyrostowe + logi) — Właściciel: Paweł Domański
  • Zaplanowanie i ustalenie harmonogramu zmiany na produkcji (standardowy proces zmiany) — Właściciel: Paweł Domański

📢 Komunikacja

  • Koordynacja komunikacji z interesariuszami — Właściciel: Jan Dvořák + Michal Pavlina
  • Powiadomienie dostawcy Oracle (Digitech) o zmianie — Właściciel: Jan Dvořák (potwierdził odpowiedzialność)
  • Ocena potrzeby powiadomienia klienta (jeśli wymagany jest downtime) — Właściciel: Zespół (zależy od wyników weryfikacji konieczności restartu bazy)

📅 Koordynacja

  • Zaplanowanie spotkania kontrolnego na przyszły tydzień — Właściciel: Leszek Wroński

Szybkie podsumowanie (bardzo zwięzłe)

  • Obecnie: Codzienne pełne kopie zapasowe → nieefektywne → podlegają zmianie.
  • Cel: Cotygodniowe pełne + przyrostowe + kopie logów.
  • Wymagane testy i ostateczna decyzja między architekturami (push vs pull).
  • Zmiana wymaga przejścia formalnego procesu i zakomunikowania interesariuszom.
  • Otwarte ryzyko: weryfikacja czy wdrożenie wymusi restart lub downtime.

Okej — zrobię Ci pełny, spójny raport DBA z całej analizy: skryptu + warningów + planu wykonania + realnych rekomendacji.

To będzie coś, co możesz praktycznie potraktować jako: dokument techniczny
materiał do review / knowledge sharing
podstawę do decyzji produkcyjnej


📘 RAPORT: Optymalizacja migracji kolumny (SQL Server)

🔍 1. Cel skryptu

Skrypt służy do:

👉 masowej zmiany typu kolumn (np. VARCHAR(9))
👉 w wielu tabelach
👉 z podziałem na strategię:

przypadek metoda
małe tabele (≤20M) ALTER COLUMN
duże tabele (>20M) migracja “shadow column”

🧱 2. Mechanizm dla dużych tabel

Dla dużych tabel stosowany jest wzorzec:

  1. ADD new_column
  2. kopiowanie danych batchami:
    UPDATE TOP (99000)
    
  3. (później) drop + rename

👉 to jest poprawny enterprise pattern


📊 3. Diagnoza planu wykonania

Na podstawie XML i operatorów:

Fakty

  • tabela: REPORT_XML_STACK
  • liczba wierszy: ~52 841 100
  • typ: HEAP (brak clustered index)
  • batch: TOP (99000)
  • używane:
    • Table Scan
    • Parallelism
    • Sort
    • Table Update
    • Index Update

KLUCZOWY PROBLEM

1. FULL / LARGE TABLE SCAN

PhysicalOp="Table Scan"

➡️ SQL Server czyta dużą część 52M wierszy dla każdego batcha

👉 to jest główne wąskie gardło


2. Słaby indeks filtrowany

Masz:

ON (DUNS_NBR_NEW1)
WHERE DUNS_NBR_NEW1 IS NULL

Problem:

  • wszystkie wartości = NULL
  • brak selektywności
  • brak sensownego porządku

👉 indeks istnieje, ale nie prowadzi planu


3. Batch TOP (99000) bez ORDER

UPDATE TOP (99000)

➡️ brak deterministycznego wyboru wierszy

👉 skutki:

  • sort
  • niespójne batchowanie
  • trudniejsza optymalizacja

⚠️ 4. Warning: CONVERT()

Type conversion may affect cardinality estimate

Wniosek:

👉 prawdziwy, ale drugorzędny

bo:

  • CAST jest tylko w SET
  • nie w predicate

👉 NIE jest główny problem


⚙️ 4. Dodatkowe obserwacje

Parallelism

  • Gather Streams
  • wiele wątków
  • dodatkowy overhead

Sort przed update

  • koszt ~13 CPU w planie
  • wynika z braku uporządkowania danych

Heap

  • brak uporządkowania fizycznego
  • więcej IO
  • trudniejsze updatey

🎯 4. ROOT CAUSE

Największy problem to:

SQL Server nie ma dobrej ścieżki dostępu do „następnych 99000 rekordów do update”

czyli:

  • słaby indeks
  • brak ORDER
  • heap
  • TOP

🚀 5. STRATEGIA OPTYMALIZACJI

🥇 PRIORYTET 1 — popraw indeks

Zamiast:

ON (DUNS_NBR_NEW1)

zrób indeks na kluczu tabeli:

CREATE NONCLUSTERED INDEX IX_REPORT_XML_STACK_MIGRATION
ON dbo.REPORT_XML_STACK (ID)                -- <- KLUCZ!
INCLUDE (DUNS_NBR)
WHERE DUNS_NBR_NEW1 IS NULL
  AND DUNS_NBR IS NOT NULL;

Efekt:

fast seek
brak full scan
mniej IO
brak sort


🥇 PRIORYTET 2 — zmień UPDATE

Zamiast:

UPDATE TOP (99000)

użyj:

wersja CTE

;WITH batch AS
(
    SELECT TOP (20000)
           ID,
           DUNS_NBR
    FROM dbo.REPORT_XML_STACK
    WHERE DUNS_NBR_NEW1 IS NULL
      AND DUNS_NBR IS NOT NULL
    ORDER BY ID
)
UPDATE T
SET T.DUNS_NBR_NEW1 = CAST(B.DUNS_NBR AS VARCHAR(9))
FROM dbo.REPORT_XML_STACK T
JOIN batch B ON B.ID = T.ID
OPTION (RECOMPILE);

🥇 PRIORYTET 3 — zmniejsz batch

Z:

TOP (99000)

👉 testuj:

  • 10k
  • 20k
  • 50k

Korzyści:

mniejszy log
mniej blokad
bardziej stabilny runtime


🥇 PRIORYTET 4 — dodaj RECOMPILE

OPTION (RECOMPILE)

👉 bo dataset się zmienia (NULL → NOT NULL)


🥈 PRIORYTET 5 — kontrola parallelism

Test:

OPTION (RECOMPILE, MAXDOP 1)

👉 często:

  • mniej overhead
  • bardziej przewidywalne batchy

🥈 PRIORYTET 6 — lock strategy

obecnie:

TABLOCK

alternatywa (bardziej OLTP-friendly):

WITH (UPDLOCK, READPAST)

🥈 PRIORYTET 7 — statystyki

UPDATE STATISTICS dbo.REPORT_XML_STACK IX_REPORT_XML_STACK_MIGRATION;

👉 ważne dla planu


🧠 6. FINALNY WZORZEC (PROD READY)

SET NOCOUNT ON;
SET XACT_ABORT ON;

DECLARE @Rows int = 1;

WHILE @Rows > 0
BEGIN
    ;WITH batch AS
    (
        SELECT TOP (20000)
               T.ID,
               T.DUNS_NBR
        FROM dbo.REPORT_XML_STACK AS T
             WITH (INDEX(IX_REPORT_XML_STACK_MIGRATION), UPDLOCK, READPAST)
        WHERE T.DUNS_NBR_NEW1 IS NULL
          AND T.DUNS_NBR IS NOT NULL
        ORDER BY T.ID
    )
    UPDATE T
       SET T.DUNS_NBR_NEW1 = CAST(B.DUNS_NBR AS VARCHAR(9))
    FROM dbo.REPORT_XML_STACK AS T
    JOIN batch AS B
      ON B.ID = T.ID
    OPTION (RECOMPILE, MAXDOP 1);

    SET @Rows = @@ROWCOUNT;

    PRINT CONCAT('Updated rows: ', @Rows);
END

📉 7. Oczekiwany efekt po optymalizacji

obszar efekt
IO ↓ znacząco
CPU ↓ (mniej sort/scan)
log
czas batcha
stabilność
blokady ↓ (jeśli bez TABLOCK)

8. TL;DR

👉 największy problem:

batch TOP + heap + słaby indeks → table scan

👉 najważniejsze fixy:

  1. indeks na kluczu (ID) + INCLUDE
  2. batchowanie po ORDER BY ID
  3. mniejszy TOP
  4. RECOMPILE

👉 warning o CAST:

istnieje, ale nie jest głównym problemem

Super — to jest bardzo dobry drugi kawałek Twojego frameworka 🔥
I teraz możemy zrobić pełną analizę architektury (Step 8), bo to jest kluczowy moment: odtwarzanie constraints, indeksów i obiektów po migracji.


📘 TL;DR (co robi Step 8)

👉 Ten fragment:

  • zbiera skrypty odtwarzające (constraints, indexy, statystyki, view-indexy)
  • wrzuca je do kolejki (Step8Queue)
  • sortuje wg kolejności zależności
  • wykonuje je sekwencyjnie przez cursor

👉 to jest poprawny pattern typu rebuild pipeline


🧠 Co działa BARDZO dobrze

1. Kolejka wykonania (Step8Queue)

To jest bardzo dobry design:

CREATE TABLE Step8Queue (...)

👉 masz:

  • centralny queue
  • kontrolę kolejności
  • możliwość debugowania
  • możliwość DRY RUN

💡 to jest bardziej kontrolowalne niż dynamiczne wykonania ad-hoc


2. Priorytety (ExecutionOrder)

CASE ObjectType
    WHEN 'PK/UNIQUE' THEN 1
    WHEN 'DEFAULT'   THEN 3
    WHEN 'FOREIGN_KEY' THEN 5
    WHEN 'INDEX' THEN 7

👉 bardzo ważne — bo:

obiekt zależność
PK musi być pierwszy
FK potrzebują PK
INDEX na końcu

to jest poprawna kolejność odbudowy


3. DryRun mode

IF @DryRun = 1

👉 super ważne przy takich operacjach


4. TRY/CATCH + logowanie

BEGIN TRY
EXEC ...
END TRY
BEGIN CATCH
EXEC dbo.usp_LogError

👉 dobrze, bo:

  • nie wywala całego procesu
  • masz audit

⚠️ Problemy i miejsca do poprawy (ważne)

Teraz sedno — co bym poprawił jako DBA produkcyjny:


1. Cursor = wąskie gardło (ale… tu jest OK)

Masz:

CURSOR FAST_FORWARD

👉 normalnie powiedziałbym: "cursor zły"

ALE w tym przypadku:

  • tworzysz obiekty (DDL)
  • kolejność jest ważna
  • trzeba sekwencyjnie

👉 cursor jest tu UZASADNIONY


2. Brak jawnej transakcji per obiekt

Masz:

SET XACT_ABORT ON;

ALE nie masz:

BEGIN TRAN
COMMIT

Problem

Jeśli obiekt:

  • padnie w połowie (np. index CREATE)
  • i nie rollbacknie się poprawnie

👉 możesz mieć niespójny stan


Fix

Dodać per-obiekt:

BEGIN TRY
    BEGIN TRAN

    EXEC sp_executesql @stmt1

    COMMIT
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK

3. PRINT zamiast realnego logowania

Masz:

PRINT @OBJT1 + '---' + @stmt1

👉 PRINT:

  • znika przy dłuższych operacjach
  • tnie się
  • nie jest audytowalny

Fix

Zostaw PRINT, ale dodaj:

INSERT INTO MyprintLog (...)
VALUES (...)

PRZED wykonaniem, nie tylko po


4. Brak retry logic

DDL potrafi failować przez:

  • blocking
  • deadlock
  • metadane

👉 obecnie:

  • jeden fail = log + jedziemy dalej

Fix (mini retry)

DECLARE @retry INT = 0;

WHILE @retry < 3
BEGIN
    BEGIN TRY
        EXEC sp_executesql @stmt1
        BREAK
    END TRY
    BEGIN CATCH
        SET @retry = @retry + 1
        WAITFOR DELAY '00:00:02'
    END CATCH
END

5. Literówka w ObjectType

Masz:

'Foregin_sweep_Key'

👉 może powodować:

  • brak dopasowania
  • złe sortowanie

6. ORDER BY w INSERT (niezdeterminowane)

INSERT INTO Step8Queue
SELECT ...
ORDER BY ...

👉 SQL Server ignoruje ORDER BY w INSERT bez TOP


Fix

Sortuj tylko przy SELECT w cursorze (już robisz )


7. Brak walidacji duplikatów

Nie masz:

PRIMARY KEY na Step8Queue

👉 możesz mieć:

  • duplikaty create scriptów
  • ponowne wykonanie DDL

Fix

Dodaj:

ALTER TABLE Step8Queue
ADD CONSTRAINT PK_Step8Queue UNIQUE(ObjectType, ObjectName, ParentTable);

8. Brak kontroli zależności między tabelami

Sortowanie:

ORDER BY ExecutionOrder, ObjectType

ALE:

👉 dwa FK między tabelami mogą się „gryźć”


advanced fix (opcjonalne)

Topologiczne sortowanie zależności FK
(albo retry loop — prostsze)


9. Możliwy błąd: VARCHAR(MAX) dla CreateScript

Może powodować:

  • duże użycie tempdb / memory

👉 OK przy małej liczbie obiektów
👉 przy tysiącach → problem


🔥 Najważniejszy problem architektoniczny

Step 8 zakłada, że wszystko się odtworzy „bez oporu”

w praktyce:

  • FK mogą failować
  • PK mogą failować
  • index może failować

👉 i Twój flow:

FAIL → log → NEXT

czyli:

możesz skończyć ze środowiskiem:

  • bez FK
  • bez indeksów
  • częściowo odtworzonym

Lepszy pattern (produkcyjny)

podejście 2-fazowe

FAZA 1 CREATE (niekrytyczne błędy OK)

  • PK, INDEX, DEFAULT, CHECK

FAZA 2 FK (retry loop)

WHILE EXISTS (FK do odtworzenia)
BEGIN
   spróbuj odtworzyć
   jeśli fail  zostaw
END

👉 aż nic się nie da już zrobić


📊 FINALNA OCENA

obszar ocena
architektura
bezpieczeństwo
odporność na błędy
wydajność
produkcyjność

🚀 Co bym zrobił jako DBA (konkrety)

MUST HAVE

  1. transakcja per obiekt
  2. logging pre + post
  3. poprawa indeksów migracji (z poprzedniego wątku)

SHOULD HAVE

  1. retry logic
  2. eliminacja literówek
  3. unique constraint na queue

NICE TO HAVE

  1. FK retry loop
  2. dependency-aware ordering

🧠 Finalny wniosek

👉 Step 8 jest:

dobrze zaprojektowany
zgodny z enterprise patternem
ale wymaga hardeningu pod produkcję


👍 Jeśli chcesz

Mogę Ci:

przepisać cały Step 8 w wersji production-grade (hardcore DBA)
dodać retry engine + dependency resolver
zrobić wersję z checkpointami (resume after fail)
dodać metryki: ile % zrobione

Powiedz tylko — zrobimy z tego narzędzie, którego będziesz używać latami 👍