16 KiB
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
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:
ADD new_column- kopiowanie danych batchami:
UPDATE TOP (99000) - (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 ScanParallelismSortTable UpdateIndex 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 update’y
🎯 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:
- ✅ indeks na kluczu (ID) + INCLUDE
- ✅ batchowanie po ORDER BY ID
- ✅ mniejszy TOP
- ✅ 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
- transakcja per obiekt
- logging pre + post
- poprawa indeksów migracji (z poprzedniego wątku)
✅ SHOULD HAVE
- retry logic
- eliminacja literówek
- unique constraint na queue
✅ NICE TO HAVE
- FK retry loop
- 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 👍