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).
|
- Wymagane testy i ostateczna decyzja między architekturami (push vs pull).
|
||||||
- Zmiana wymaga przejścia formalnego procesu i zakomunikowania interesariuszom.
|
- Zmiana wymaga przejścia formalnego procesu i zakomunikowania interesariuszom.
|
||||||
- Otwarte ryzyko: weryfikacja czy wdrożenie wymusi restart lub downtime.
|
- 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