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

884 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Daily Note - 2026-06-18
date: 2026-06-18 09:26:51
tags: []
Status: Active
type: 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:
```sql
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
```xml
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:
```sql
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
```sql
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:
```sql
ON (DUNS_NBR_NEW1)
```
zrób indeks **na kluczu tabeli**:
```sql
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:
```sql
UPDATE TOP (99000)
```
użyj:
### ✅ wersja CTE
```sql
;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:
```sql
TOP (99000)
```
👉 testuj:
* 10k
* 20k
* 50k
### Korzyści:
✅ mniejszy log
✅ mniej blokad
✅ bardziej stabilny runtime
***
## 🥇 PRIORYTET 4 — dodaj RECOMPILE
```sql
OPTION (RECOMPILE)
```
👉 bo dataset się zmienia (NULL → NOT NULL)
***
## 🥈 PRIORYTET 5 — kontrola parallelism
Test:
```sql
OPTION (RECOMPILE, MAXDOP 1)
```
👉 często:
* mniej overhead
* bardziej przewidywalne batchy
***
## 🥈 PRIORYTET 6 — lock strategy
### obecnie:
```sql
TABLOCK
```
### alternatywa (bardziej OLTP-friendly):
```sql
WITH (UPDLOCK, READPAST)
```
***
## 🥈 PRIORYTET 7 — statystyki
```sql
UPDATE STATISTICS dbo.REPORT_XML_STACK IX_REPORT_XML_STACK_MIGRATION;
```
👉 ważne dla planu
***
# 🧠 6. FINALNY WZORZEC (PROD READY)
```sql
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:
```sql
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)
```sql
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
```sql
IF @DryRun = 1
```
👉 super ważne przy takich operacjach
***
## ✅ 4. TRY/CATCH + logowanie
```sql
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:
```sql
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:
```sql
SET XACT_ABORT ON;
```
ALE nie masz:
```sql
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:
```sql
BEGIN TRY
BEGIN TRAN
EXEC sp_executesql @stmt1
COMMIT
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK
```
***
# ❌ 3. PRINT zamiast realnego logowania
Masz:
```sql
PRINT @OBJT1 + '---' + @stmt1
```
👉 PRINT:
* znika przy dłuższych operacjach
* tnie się
* nie jest audytowalny
***
## ✅ Fix
Zostaw PRINT, ale dodaj:
```sql
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)
```sql
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:
```sql
'Foregin_sweep_Key'
```
👉 może powodować:
* brak dopasowania
* złe sortowanie
***
# ❌ 6. ORDER BY w INSERT (niezdeterminowane)
```sql
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:
```sql
PRIMARY KEY na Step8Queue
```
👉 możesz mieć:
* duplikaty create scriptów
* ponowne wykonanie DDL
***
## ✅ Fix
Dodaj:
```sql
ALTER TABLE Step8Queue
ADD CONSTRAINT PK_Step8Queue UNIQUE(ObjectType, ObjectName, ParentTable);
```
***
# ❌ 8. Brak kontroli zależności między tabelami
Sortowanie:
```sql
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)
```sql
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
4. retry logic
5. eliminacja literówek
6. unique constraint na queue
***
## ✅ NICE TO HAVE
7. FK retry loop
8. 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 👍