--- 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 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: ```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 👍