Cum scrieti migrarile pentru baza de date?

Salutare,
Sunt curios cum scrieti migrarile pentru baza de date si cum le rulati. Care e procesul de deploy / ce tool-uri folosit.

Zi ce intelegi prin “migrare” intai. Alt DB? Structura diferita? Change log?

1 Like
  • modificare structura tabele, coloane
  • versioning
  • modificare content in baza de date

Am utilizat Liquibase cu un pipeline separat pentru migrari la baza de date.
Creezi un pull request intr-un repo de migrari cu scriptul de liquibase, se aproba si dupa merge se poate rula script-ul pe fiecare env dintr-un job specific. (se creaza automat un helm chart la care se face update dupa push)
In mod ideal pe prod le ruleaza program manager-ul. Trebuie sa ai si un script de rollback.

Alternativ se utilizeaza per serviciu, dar in acest caz schimbi versiunea la serviciu daca schimbi ceva in baza de date si poate fi o problema.

2 Likes

folosesc go-migrate și țin modificările ( fișiere .up.sql și .down.sql) intr-un director care e parte din codul sursă. Cînd execut programul, la connectarea la baza de date și execut si partea de migrare. Cam ca aici:

func initDB() *sql.DB {

	db, err := sql.Open("postgres", "connection string goes here")
	if err != nil {
		panic(err)
	}

	migrationsPath := os.Getenv("MIGRATIONS_DIR")

	driver, _ := postgres.WithInstance(db, &postgres.Config{})

	m, _ := migrate.NewWithDatabaseInstance(fmt.Sprintf("file://%s", migrationsPath), "postgres", driver)
	err = m.Up()
	if err != nil && err.Error() != "no change" {
		log.Printf("db failed to migrate; reason: %s", err)
	}

	return db
}

Uite un exemplue mai detaliat aici: migrate/TUTORIAL.md at v4.15.2 · golang-migrate/migrate · GitHub

2 Likes

Cu ceva facut de Chuck Norris nu poti da gres:

1 Like

Avem un fisier sql de incremetal cu modificari si trecem acolo tot ce modificam . Si in baza de date avem un tabel unde tinem versiunea. Fiecare mo

cam asa

-- Rev xyz

//cod sql care adauga, modifica

UPDATE DbVersion SET Revision = 'xyz' WHERE Id = 1;

Si cand faci update-ul, se ia de la versiunea xyz in jos. Facem asa de 4 ani si nu am avut probleme

1 Like

Django. Migrările se fac semiautomat (migrările simple se fac prin modificarea modelelor aferente tabelelor și apoi se rulează niște comenzi intuitive, iar migrările mai complicate sunt asistate de funcții de validare mostly, dar se pot face și data migrations). Dacă vrei să adopți Django pe o db deja existentă știe să genereze/sincronizeze baza de date cu codul python. Destul de drăguț.

1 Like

Exact aceeași abordare o am și eu în programul de facturare, am ajuns la versiunea 26 a bazei de date. În 14 ani doar câteva probleme minore, când am uitat să migrez unele chestii sau am făcut-o incorect, mai ales când userul făcea un salt serios între versiuni.

Am văzut azi în log un user care folosește versiunea din 2008, sunt curios ce se va întâmpla când se va hotărî să aducă programul la zi :slight_smile:

Noi faceam cu scripturi sql tinute in repository si rulate pe fiecare baza de date a clientilor. Nu era un proces eficient si dura mult, greu de integrat in cd, asa ca am investigat un mod mai bun si am dat de Fluent Migrator. https://fluentmigrator.github.io

Migrarile sunt tinute acum ca si clase individuale per versiune, pot include ori setup in format fluent ori sql raw.

// Fluent:
Create.Table("Log")
                .WithColumn("Id").AsInt64().PrimaryKey().Identity()
                .WithColumn("Text").AsString();
// Raw Sql
Execute.Sql("Select * from Users");

De asemenea, am facut un console app care il rulam ca parte din CD pipeline care migreaza fiecare baza de date bazat pe versiunea curenta a bazei de date.

Mentionez ca folosim acest tool de aprox 6 luni si nu am avut probleme.

Daca ai timp sa citesti un blog post cuprinzator despre migrari: Migrations Done Well: Typical Migration Approaches - The Pragmatic Engineer

Cele mai pretentioase din experienta mea sunt migrarile cu zero downtime. Poti sa ai tot felul de tool-uri, dar e foarte important sa ai pe cineva care intelege in detaliu cum functioneaza serverul de DB pe care il folosesti, ce fel de presiune, lock-uri se pun pe tabele/date in timpul migrarii. La aplicatii mari, o migrare poate fi cel mai complicat lucru pe care il faci.

2 Likes

Cu mentiunea ca folosesc 2 seturi de migrations:

  • full migrations
  • changes
1 Like

Am si eu fix la fel. Si le-am pus in main sa ruleze cand porneste app. Nu stiu daca neaparat e o idee buna dar na…

1 Like

Eu folosesc Flyway. Merge pe principiul cu scripturi versionate care nu mai pot fi modificate, orice modificare ulterioara in DB este un script nou. Versiunile aplicate se tin intr-o tabela si se aplica versiunile noi, care inca nu sunt acolo. Se poate rula cand porneste aplicatia sau din CLI.
Am mai folosit Liquibase, functioneaza pe acelasi principiu.

Tot așa, face Django și la noi. Le generează automat.

Mai facem și chestii manuale (adică cod Python cu ORM Django, nu SQL), cum ar fi migrări de date (de ex. populare fielduri noi).

Și rularea se face in linie de comandă: python manage.py migrate. Și poți merge inclusiv înapoi cu migrările.

Pentru că avem o aplicație la care lucram de vreo 10 ani, se aduna migrări și mai făceam un squash la migrări din când în când. Dar aici trebuie sa ai grija (daca ai o aplicație cu mai multe instanțe instalate) că nu va mai merge upgrade de la orice versiune la orice versiune.

Pentru că dura cam un minut ca sa aplice toate migrările la instalare, in procesul de build al aplicației ne generam acum automat un initdb.sql care e rulat la instalare in doar câteva secunde. Astfel nu ne-am mai bătut capul nici cu squash de câțiva ani.

Acum:

  • Instalare inițială: initdb.sql
  • Upgrade: migrări
1 Like

noi folosim de >10 ani aceasta metoda si merge bine:la update se distribuie si structura bazei de date la zi si se ruleza o rutina care compara metadata distribuita cu a clientului si genereaza cod pt adaugare tabele noi,campuri noi, pk,fk.cod proceduri stocate+triggers se ruleaza cu CREATE OR ALTER.pe o baza de date cu 100 de tabele,100 sp+triggers dureaza 4-5 secunde
chestii secundare de sters campuri,tabele,etc,se executa cu 2 rutine: una inainte si una dupa migrare,aici f rar se adauga cod

1 Like

Eu am folosit Liquibase si Flyway, vorbind de Java, functioneaza bine, sunt super usor de integrat/configurat. Liquibase stie si rollback la versiuni anterioare, Flyway dupa cunostintele mele actuale nu, dar nu-mi bag mana in foc ca nu am studiat indeaproape chestia asta, recunosc. CI-ul preia executia practic, nu facem nimic manual.

“Migrarile propriu-zise” sunt ori intr-un repo separat sau in repoul de service daca serviceul e responsabil de propria baza de date (microservice sau microservice-oriented architecture).

Ca si limbaj, am folosit XML, YAML si SQL plain pentru a declara migrarile. Urasc XML, dar era proiect vechi si asa era structura. YAML si SQL au fiecare avantajele si dezavantajele lor, e o chestie personala.

1 Like

Eu n-am curaj sa rulez in productie nimic automat legat de DB. Nici nu merge “alter table” pe majoritatea tabelelor, ca face lock si la cat de mari sunt ar pune aplicatia jos.

2 Likes

Inseamna ca ai ajuns in momentul ala in care chiar trebuie sa folosesti altfel datele. Fie partitionezi tabelele, fie migrezi o parte catre alte sisteme de stocare. Dar teama de automatizare in punctul asta nu e chiar the way to go.

E outage fear. :slight_smile:
Buna parte din resurse le canalizam spre redundanta, protectii, fallback-uri si orice ne lasa sa dormim noaptea mai linistiti. Am cam mutat datele de care n-avem nevoie on the spot fie in alte DB fie in elasticsearch.

PS: la alter table nu conteaza ca tabela e partitionata.
PPS: mai e si riscul de a strica replicarea, alta sabie deasupra capului

dbadmin e meserie grea