SqlCopy 1.0.38
SqlCopy
Tool .NET 9 CLI pentru replicare selectiva a bazelor de date SQL Server. Cazul principal de utilizare: baze de date remote de 100GB-2TB din care ai nevoie local doar de cateva GB - toate obiectele programatice (proceduri, view-uri, functii, triggere), toate structurile de tabele, dar date doar din tabele de interes.
Caracteristici
- Pur managed - Dapper + Microsoft.Data.SqlClient + sys.* catalog views (fara dependinte native SMO)
- Full async - toate operatiile pe IO sunt asincrone
- Paralelism pe niveluri FK - tabelele independente se transfera simultan, ordinea constrangerilor este garantata
- AOT/trimming friendly - cod managed, fara reflection masiv
- 5 comenzi:
transfer(direct),script(genereaza .sql),list(inventory rapid),inventory(manifest editabil),copy-rows(transfer selectiv de randuri prin YAML) - Filtrare flexibila: wildcard si regex, separat pe tabele vs. obiecte programatice
- Manifest workflow: marcare manuala data/structure/skip per tabel
- Praguri automate: structure-only peste un numar de randuri sau dimensiune in MB
- Skip blob columns: VARBINARY(MAX), NVARCHAR(MAX), XML etc.
- Toleranta la erori: configurabil (
--continue-on-error) - Autentificare: Windows si SQL Auth
- CLI: Spectre.Console cu progress bars
- Logging: Serilog cu fisiere zilnice
Instalare
# Ca dotnet tool global (recomandat)
dotnet tool install -g SqlCopy
# Sau build local
git clone <repository-url>
cd sql-copy
dotnet build
dotnet publish src/SqlCopy -c Release -o ./publish
Cerinte: .NET 9 SDK, acces la SQL Server (sursa si/sau destinatie).
Update / Versiune
# Update la cea mai recenta versiune
dotnet tool update -g SqlCopy
# Verifica versiunea instalata
sqlcopy --version
# Reinstalare fortata (daca update-ul nu prinde o versiune noua)
dotnet tool uninstall -g SqlCopy
dotnet tool install -g SqlCopy
Versiunile sunt publicate pe NuGet si urmaresc tag-urile git (vMAJOR.MINOR.PATCH) prin MinVer.
Quick start
# Transfer simplu (creeaza DB-ul la destinatie daca nu exista)
sqlcopy transfer -s (local) --source-db ProductionDB \
-d localhost --dest-db DevDB --create-db
# Cu paralelism (4 tabele simultan per nivel FK)
sqlcopy transfer -s remote --source-db BigDB \
-d localhost --dest-db LocalDB \
--create-db --parallelism 4
# Doar tabelele de configurare cu date, restul structure-only
sqlcopy transfer -s remote --source-db BigDB \
-d localhost --dest-db DevDB \
--data-tables "dbo.Config,dbo.Users,dbo.Products" \
--create-db
Workflow recomandat (manifest)
# 1. Genereaza un manifest cu toate tabelele si dimensiunile
sqlcopy inventory -s remote --source-db ProductionDB -o manifest.txt
# 2. Editeaza manifest.txt - marcheaza fiecare tabel cu data/structure/skip
# Tabele mici/de configurare -> data
# Tabele mari de istoric -> structure
# Tabele de audit/loguri -> skip
# 3. Transfer cu manifestul
sqlcopy transfer -s remote --source-db ProductionDB \
-d localhost --dest-db DevDB \
--manifest manifest.txt --create-db
copy-rows: transfer selectiv de randuri cu WHERE per tabela
Comanda copy-rows muta randuri filtrate dintr-o lista de tabele intr-o destinatie unde schema exista deja (rulezi mai intai transfer --no-data sau ai DB-ul gata). Caz de utilizare tipic: vrei un Customer cu toate Order-urile, OrderLine-urile si Product-urile referentiate, fara restul bazei.
Configurarea e intr-un fisier YAML cu lista de tabele + WHERE per tabela. Ordinea de insert e calculata automat din FK-uri (Kahn topological sort), deci tabelele parinte intra inainte de copii. Daca preferi sa controlezi tu ordinea, seteaza respectExplicitOrder: true.
Exemplu YAML
source:
server: PRODSERVER
database: ProductionDB
windowsAuth: true
destination:
server: localhost
database: DevDB
windowsAuth: true
variables:
customerId: 42
fromDate: "2024-01-01"
options:
batchSize: 10000 # default 10000
timeout: 3600 # default 3600 sec
continueOnError: true # default true
maxErrors: 5 # default 5
truncateBeforeInsert: false # default false. Daca true: DELETE FROM target WHERE <same predicate> inainte de INSERT
respectExplicitOrder: false # default false (FK-auto); true = ordinea exacta din lista de mai jos
tables:
- name: dbo.Customer
where: "Id = {customerId}"
- name: dbo.Address
where: "Id IN (SELECT AddressId FROM dbo.Customer WHERE Id = {customerId})"
- name: dbo.Order
where: "CustomerId = {customerId} AND CreatedAt >= '{fromDate}'"
- name: dbo.OrderLine
where: "OrderId IN (SELECT Id FROM dbo.Order WHERE CustomerId = {customerId})"
- name: dbo.Product
where: "Id IN (SELECT DISTINCT ol.ProductId FROM dbo.OrderLine ol JOIN dbo.Order o ON ol.OrderId = o.Id WHERE o.CustomerId = {customerId})"
Rulare
# Executa transferul folosind config-ul YAML
sqlcopy copy-rows -c copy-customer.yaml
# Suprascrie o variabila din CLI (utila pentru a rula acelasi YAML pentru entitati diferite)
sqlcopy copy-rows -c copy-customer.yaml --var customerId=99
# Dry-run: doar SELECT COUNT(*) per tabela cu WHERE-ul rezolvat (verifica cati randuri ai pulla)
sqlcopy copy-rows -c copy-customer.yaml --dry-run
Note importante
- Schema trebuie sa existe la destinatie —
copy-rowsnu creeaza tabele/FK/module. Folosestetransfer --no-datao data ca sa pregatesti destinatia. - Variabilele
{name}se substituie text plain inainte de executie. Tu ai grija de quoting in WHERE (numere fara quote, string-uri/date-uri intre'...'). - Ordonarea FK se calculeaza pe sursa, din
sys.foreign_keys. Daca tabelele tale au cicluri sau FK-uri cross-DB, folosesterespectExplicitOrder: truesi ordoneaza manual. KeepIdentitye activ — PK-urile sunt pastrate exact, deci referintele intre tabele raman valide.- Idempotenta: ruland comanda a doua oara vei prinde un PK conflict. Foloseste
truncateBeforeInsert: truepentru re-rulari curate (sterge intai randurile care match-uiesc WHERE-ul, apoi reinsereaza). - Tabelele fara
wherese copiaza in totalitate (SELECT plat).
Documentatie completa
Vezi docs/MANUAL.md pentru:
- Toate optiunile fiecarei comenzi
- Reguli de prioritate intre filtre, manifest, data-tables, structure-only
- Workflow-uri tipice
- Note si limitari (feature-uri SQL Server neacoperite: temporal, partitioning, in-memory OLTP)
- Wildcard si regex patterns
Comenzi pe scurt
| Comanda | Scop |
|---|---|
transfer |
Transfer direct intre doua servere (schema + date paralel) |
script |
Genereaza scripturi SQL organizate pe foldere (DDL only) |
list |
Listeaza obiectele din baza de date (cu top N optional) |
inventory |
Genereaza manifest editabil cu toate tabelele |
copy-rows |
Transfer selectiv de randuri din mai multe tabele dupa un fisier YAML cu WHERE per tabela (ex: o singura entitate cu toate tabelele referentiate) |
Fisier de parametri
Orice comanda poate citi argumente dintr-un fisier cu -@fisier:
sqlcopy transfer -@params.txt
params.txt:
# Comentariile incep cu #
-s remote
--source-db ProductionDB
-d localhost
--dest-db DevDB
--create-db
--parallelism 4
--manifest manifest.txt
Coduri de iesire
| Cod | Descriere |
|---|---|
| 0 | Succes |
| 1 | Eroare (partial sau total) |
Logging
Fisiere log in logs/sqlcopy-YYYYMMDD.log cu detalii despre fiecare operatie, erori cu side (Source/Destination), si decizii de transfer per tabel.
Troubleshooting
Eroare de conexiune
Error: A network-related or instance-specific error occurred
Verifica: SQL Server pornit, firewall pe 1433, numele server-ului, credentialele.
Eroare de permisiuni
Error: The SELECT permission was denied on object
Utilizatorul are nevoie de minim db_datareader pe sursa si db_owner pe destinatie.
Timeout la transfer date
sqlcopy transfer ... --timeout 7200 # 2 ore
Constrangeri FK care esueaza la sfarsit
Daca ai cicluri sau dependente intre DB-uri, foloseste --no-fk pentru a sari complet peste constrangerile FK.
Licenta
MIT License
| Version | Downloads | Last updated |
|---|---|---|
| 1.0.38 | 4 | 05/18/2026 |
| 1.0.37 | 2 | 05/16/2026 |
| 1.0.36 | 2 | 05/16/2026 |
| 1.0.35 | 2 | 05/16/2026 |
| 1.0.34 | 2 | 05/16/2026 |
| 1.0.33 | 2 | 05/16/2026 |
| 1.0.32 | 2 | 05/15/2026 |
| 1.0.31 | 2 | 05/15/2026 |
| 1.0.30 | 2 | 05/15/2026 |
| 1.0.29 | 2 | 05/15/2026 |
| 1.0.28 | 2 | 05/15/2026 |
| 1.0.27 | 2 | 05/15/2026 |
| 1.0.26 | 2 | 05/15/2026 |
| 1.0.25 | 2 | 05/15/2026 |
| 1.0.24 | 2 | 05/15/2026 |
| 1.0.23 | 2 | 05/15/2026 |
| 1.0.22 | 2 | 05/15/2026 |
| 1.0.21 | 2 | 05/15/2026 |
| 1.0.20 | 2 | 05/15/2026 |
| 1.0.19 | 2 | 05/15/2026 |
| 1.0.18 | 2 | 05/15/2026 |
| 1.0.17 | 2 | 05/15/2026 |
| 1.0.16 | 2 | 05/15/2026 |
| 1.0.15 | 2 | 05/15/2026 |
| 1.0.14 | 2 | 05/14/2026 |
| 1.0.13 | 6 | 03/11/2026 |
| 1.0.12 | 4 | 03/11/2026 |
| 1.0.11 | 5 | 03/11/2026 |
| 1.0.10 | 5 | 03/11/2026 |
| 1.0.9 | 5 | 03/11/2026 |
| 1.0.8 | 5 | 03/11/2026 |
| 1.0.7 | 5 | 03/11/2026 |
| 1.0.6 | 5 | 03/11/2026 |
| 1.0.5 | 5 | 03/11/2026 |
| 1.0.4 | 5 | 03/10/2026 |
| 1.0.3 | 5 | 03/10/2026 |
| 1.0.2 | 5 | 03/10/2026 |
| 1.0.1 | 4 | 02/19/2026 |
| 1.0.0 | 5 | 02/19/2026 |