Jun 18, 2026, 9:47 AM
This commit is contained in:
@@ -94,3 +94,790 @@ Spotkanie kontrolne (follow-up) prawdopodobnie zostanie zaplanowane na przyszły
|
||||
- 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 👍
|
||||
|
||||
Reference in New Issue
Block a user