sql >> Database >  >> RDS >> Database

Een index maken in Django zonder downtime

Het beheren van databasemigraties is een grote uitdaging in elk softwareproject. Gelukkig wordt Django vanaf versie 1.7 geleverd met een ingebouwd migratieraamwerk. Het raamwerk is zeer krachtig en nuttig bij het beheren van wijzigingen in databases. Maar de flexibiliteit die het raamwerk bood, vereiste enkele compromissen. Om de beperkingen van Django-migraties te begrijpen, ga je een bekend probleem aanpakken:een index maken in Django zonder downtime.

In deze tutorial leer je:

  • Hoe en wanneer Django nieuwe migraties genereert
  • Hoe de commando's te inspecteren die Django genereert om migraties uit te voeren
  • Hoe u migraties veilig kunt aanpassen aan uw behoeften

Deze zelfstudie op gemiddeld niveau is bedoeld voor lezers die al bekend zijn met Django-migraties. Voor een inleiding tot dat onderwerp, bekijk Django Migrations:A Primer.

Gratis bonus: Klik hier om gratis toegang te krijgen tot aanvullende Django-tutorials en bronnen die u kunt gebruiken om uw Python-webontwikkelingsvaardigheden te verdiepen.


Het probleem met het maken van een index in Django-migraties

Een veelvoorkomende wijziging die meestal nodig is wanneer de gegevens die door uw toepassing zijn opgeslagen, groeien, is het toevoegen van een index. Indexen worden gebruikt om zoekopdrachten te versnellen en uw app snel en responsief te maken.

In de meeste databases vereist het toevoegen van een index een exclusief slot op de tabel. Een exclusieve vergrendeling voorkomt bewerkingen voor gegevenswijziging (DML), zoals UPDATE , INSERT , en DELETE , terwijl de index wordt gemaakt.

Vergrendelingen worden impliciet verkregen door de database bij het uitvoeren van bepaalde bewerkingen. Wanneer een gebruiker zich bijvoorbeeld aanmeldt bij uw app, werkt Django de last_login bij veld in de auth_user tafel. Om de update uit te voeren, moet de database eerst een slot op de rij krijgen. Als de rij momenteel wordt vergrendeld door een andere verbinding, krijgt u mogelijk een database-uitzondering.

Het vergrendelen van een tabel kan een probleem vormen wanneer het nodig is om het systeem beschikbaar te houden tijdens migraties. Hoe groter de tabel, hoe langer het kan duren om de index te maken. Hoe langer het duurt om de index te maken, hoe langer het systeem niet beschikbaar is of niet reageert op gebruikers.

Sommige databaseleveranciers bieden een manier om een ​​index te maken zonder de tabel te vergrendelen. Als u bijvoorbeeld een index in PostgreSQL wilt maken zonder een tabel te vergrendelen, kunt u de CONCURRENTLY gebruiken zoekwoord:

CREATE INDEX CONCURRENTLY ix ON table (column);

In Oracle is er een ONLINE optie om DML-bewerkingen op de tafel toe te staan ​​terwijl de index wordt gemaakt:

CREATE INDEX ix ON table (column) ONLINE;

Bij het genereren van migraties zal Django deze speciale trefwoorden niet gebruiken. Als u de migratie uitvoert zoals deze is, krijgt de database een exclusieve vergrendeling op de tafel en worden DML-bewerkingen voorkomen terwijl de index wordt gemaakt.

Het gelijktijdig maken van een index heeft enkele kanttekeningen. Het is belangrijk om van tevoren de specifieke problemen van uw database-backend te begrijpen. Een voorbehoud in PostgreSQL is bijvoorbeeld dat het gelijktijdig maken van een index langer duurt omdat het een extra tabelscan vereist.

In deze zelfstudie gebruik je Django-migraties om een ​​index op een grote tabel te maken, zonder downtime te veroorzaken.

Opmerking: Om deze tutorial te volgen, is het raadzaam een ​​PostgreSQL-backend, Django 2.x en Python 3 te gebruiken.

Het is ook mogelijk om samen met andere database-backends te volgen. Op plaatsen waar SQL-functies worden gebruikt die uniek zijn voor PostgreSQL, wijzigt u de SQL zodat deze overeenkomt met uw database-backend.



Instellen

Je gaat een verzonnen Sale gebruiken model in een app genaamd app . In een echte situatie, modellen zoals Sale zijn de hoofdtabellen in de database, en ze zullen meestal erg groot zijn en veel gegevens bevatten:

# models.py

from django.db import models

class Sale(models.Model):
    sold_at = models.DateTimeField(
        auto_now_add=True,
    )
    charged_amount = models.PositiveIntegerField()

Om de tabel te maken, genereert u de eerste migratie en past u deze toe:

$ python manage.py makemigrations
Migrations for 'app':
  app/migrations/0001_initial.py
    - Create model Sale

$ python manage migrate
Operations to perform:
  Apply all migrations: app
Running migrations:
  Applying app.0001_initial... OK

Na een tijdje wordt de verkooptafel erg groot en beginnen gebruikers te klagen over traagheid. Tijdens het controleren van de database merkte je dat veel zoekopdrachten de sold_at . gebruiken kolom. Om dingen te versnellen, besluit je dat je een index op de kolom nodig hebt.

Een index toevoegen op sold_at , brengt u de volgende wijziging aan in het model:

# models.py

from django.db import models

class Sale(models.Model):
    sold_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
    )
    charged_amount = models.PositiveIntegerField()

Als u deze migratie uitvoert zoals het is, zal Django de index op de tafel maken en deze wordt vergrendeld totdat de index is voltooid. Het kan even duren om een ​​index op een zeer grote tafel te maken en u wilt downtime voorkomen.

Op een lokale ontwikkelomgeving met een kleine dataset en zeer weinig verbindingen, kan deze migratie onmiddellijk aanvoelen. Bij grote datasets met veel gelijktijdige verbindingen kan het verkrijgen van een vergrendeling en het maken van de index echter even duren.

In de volgende stappen ga je migraties aanpassen die door Django zijn gemaakt om de index te maken zonder downtime te veroorzaken.



Nepmigratie

De eerste benadering is om de index handmatig te maken. Je gaat de migratie genereren, maar je gaat Django deze niet daadwerkelijk laten toepassen. In plaats daarvan voert u de SQL handmatig in de database uit en laat u Django denken dat de migratie is voltooid.

Genereer eerst de migratie:

$ python manage.py makemigrations --name add_index_fake
Migrations for 'app':
  app/migrations/0002_add_index_fake.py
    - Alter field sold_at on sale

Gebruik de sqlmigrate commando om de SQL te bekijken die Django zal gebruiken om deze migratie uit te voeren:

$ python manage.py sqlmigrate app 0002
BEGIN;
--
-- Alter field sold_at on sale
--
CREATE INDEX "app_sale_sold_at_b9438ae4" ON "app_sale" ("sold_at");
COMMIT;

U wilt de index maken zonder de tabel te vergrendelen, dus u moet de opdracht wijzigen. Voeg de CONCURRENTLY . toe trefwoord en voer het uit in de database:

app=# CREATE INDEX CONCURRENTLY "app_sale_sold_at_b9438ae4"
ON "app_sale" ("sold_at");

CREATE INDEX

Merk op dat je de opdracht hebt uitgevoerd zonder de BEGIN en COMMIT onderdelen. Als u deze trefwoorden weglaat, worden de opdrachten uitgevoerd zonder een databasetransactie. We zullen later in het artikel databasetransacties bespreken.

Nadat u de opdracht heeft uitgevoerd en u probeert migraties toe te passen, krijgt u de volgende foutmelding:

$ python manage.py migrate

Operations to perform:
  Apply all migrations: app
Running migrations:
  Applying app.0002_add_index_fake...Traceback (most recent call last):
  File "venv/lib/python3.7/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)

psycopg2.ProgrammingError: relation "app_sale_sold_at_b9438ae4" already exists

Django klaagt dat de index al bestaat en dus niet verder kan met de migratie. Je hebt zojuist de index rechtstreeks in de database gemaakt, dus nu moet je Django laten denken dat de migratie al is toegepast.

Een migratie nep maken

Django biedt een ingebouwde manier om migraties als uitgevoerd te markeren, zonder ze daadwerkelijk uit te voeren. Om deze optie te gebruiken, stelt u de --fake . in vlag bij het toepassen van de migratie:

$ python manage.py migrate --fake
Operations to perform:
  Apply all migrations: app
Running migrations:
  Applying app.0002_add_index_fake... FAKED

Django maakte deze keer geen fout. Django paste eigenlijk geen migratie toe. Het heeft het zojuist gemarkeerd als uitgevoerd (of FAKED ).

Hier zijn enkele zaken waarmee u rekening moet houden bij het faken van migraties:

  • De handmatige opdracht moet gelijk zijn aan de SQL die door Django wordt gegenereerd: U moet ervoor zorgen dat de opdracht die u uitvoert gelijk is aan de SQL die door Django wordt gegenereerd. Gebruik sqlmigrate om het SQL-commando te produceren. Als de opdrachten niet overeenkomen, kan het zijn dat u inconsistenties krijgt tussen de database en de status van het model.

  • Andere niet-toegepaste migraties worden ook vervalst: Als u meerdere niet-toegepaste migraties heeft, worden deze allemaal vervalst. Voordat u migraties toepast, is het belangrijk om ervoor te zorgen dat alleen de migraties die u wilt faken, niet worden toegepast. Anders krijg je misschien inconsistenties. Een andere optie is om de exacte migratie op te geven die u wilt faken.

  • Directe toegang tot de database is vereist: U moet de SQL-opdracht in de database uitvoeren. Dit is niet altijd een optie. Ook is het direct uitvoeren van commando's in een productiedatabase gevaarlijk en moet waar mogelijk worden vermeden.

  • Geautomatiseerde implementatieprocessen hebben mogelijk aanpassingen nodig: Als u het implementatieproces hebt geautomatiseerd (met behulp van CI, CD of andere automatiseringstools), moet u het proces mogelijk wijzigen in nepmigraties. Dit is niet altijd wenselijk.

Opruimen

Voordat u doorgaat naar de volgende sectie, moet u de database direct na de eerste migratie terugbrengen naar de staat. Om dat te doen, migreert u terug naar de oorspronkelijke migratie:

$ python manage.py migrate 0001
Operations to perform:
  Target specific migration: 0001_initial, from app
Running migrations:
  Rendering model states... DONE
  Unapplying app.0002_add_index_fake... OK

Django heeft de wijzigingen die bij de tweede migratie zijn aangebracht ongedaan gemaakt, dus het is nu veilig om het bestand ook te verwijderen:

$ rm app/migrations/0002_add_index_fake.py

Inspecteer de migraties om er zeker van te zijn dat je alles goed hebt gedaan:

$ python manage.py showmigrations app
app
 [X] 0001_initial

De eerste migratie is toegepast en er zijn geen niet-toegepaste migraties.



Ruwe SQL uitvoeren bij migraties

In de vorige sectie heb je SQL rechtstreeks in de database uitgevoerd en de migratie vervalst. Dit klaart de klus, maar er is een betere oplossing.

Django biedt een manier om onbewerkte SQL bij migraties uit te voeren met behulp van RunSQL . Laten we proberen het te gebruiken in plaats van het commando rechtstreeks in de database uit te voeren.

Genereer eerst een nieuwe lege migratie:

$ python manage.py makemigrations app --empty --name add_index_runsql
Migrations for 'app':
  app/migrations/0002_add_index_runsql.py

Bewerk vervolgens het migratiebestand en voeg een RunSQL . toe bediening:

# migrations/0002_add_index_runsql.py

from django.db import migrations, models

class Migration(migrations.Migration):
    atomic = False

    dependencies = [
        ('app', '0001_initial'),
    ]

    operations = [
        migrations.RunSQL(
            'CREATE INDEX "app_sale_sold_at_b9438ae4" '
            'ON "app_sale" ("sold_at");',
        ),
    ]

Wanneer u de migratie uitvoert, krijgt u de volgende uitvoer:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: app
Running migrations:
  Applying app.0002_add_index_runsql... OK

Dit ziet er goed uit, maar er is een probleem. Laten we opnieuw proberen migraties te genereren:

$ python manage.py makemigrations --name leftover_migration
Migrations for 'app':
  app/migrations/0003_leftover_migration.py
    - Alter field sold_at on sale

Django genereerde dezelfde migratie opnieuw. Waarom deed het dat?

Opruimen

Voordat we die vraag kunnen beantwoorden, moet u de wijzigingen die u in de database hebt aangebracht, opschonen en ongedaan maken. Begin met het verwijderen van de laatste migratie. Het is niet toegepast, dus het is veilig om te verwijderen:

$ rm app/migrations/0003_leftover_migration.py

Maak vervolgens een lijst van de migraties voor de app app:

$ python manage.py showmigrations app
app
 [X] 0001_initial
 [X] 0002_add_index_runsql

De derde migratie is weg, maar de tweede is toegepast. U wilt direct na de eerste migratie terugkeren naar de staat. Probeer terug te migreren naar de oorspronkelijke migratie zoals u deed in de vorige sectie:

$ python manage.py migrate app 0001
Operations to perform:
  Target specific migration: 0001_initial, from app
Running migrations:
  Rendering model states... DONE
  Unapplying app.0002_add_index_runsql...Traceback (most recent call last):

NotImplementedError: You cannot reverse this operation

Django kan de migratie niet ongedaan maken.



Omgekeerde migratiebewerking

Om een ​​migratie ongedaan te maken, voert Django voor elke bewerking een tegengestelde actie uit. In dit geval is het verwijderen van een index het omgekeerde van het toevoegen van een index. Zoals je al hebt gezien, kun je een migratie die onomkeerbaar is, ongedaan maken. Net zoals u checkout . kunt gebruiken in Git kun je een migratie ongedaan maken als je migrate uitvoert naar een eerdere migratie.

Veel ingebouwde migratiebewerkingen definiëren al een omgekeerde actie. De omgekeerde actie voor het toevoegen van een veld is bijvoorbeeld om de corresponderende kolom te verwijderen. De omgekeerde actie voor het maken van een model is om de bijbehorende tabel te laten vallen.

Sommige migratiebewerkingen zijn niet omkeerbaar. Er is bijvoorbeeld geen omgekeerde actie voor het verwijderen van een veld of het verwijderen van een model, want zodra de migratie is toegepast, zijn de gegevens verdwenen.

In de vorige sectie gebruikte je de RunSQL operatie. Toen u probeerde de migratie ongedaan te maken, is er een fout opgetreden. Volgens de fout kan een van de bewerkingen in de migratie niet ongedaan worden gemaakt. Django kan standaard onbewerkte SQL niet terugdraaien. Omdat Django niet weet wat er door de operatie is uitgevoerd, kan het niet automatisch een tegengestelde actie genereren.

Een migratie omkeerbaar maken

Om een ​​migratie omkeerbaar te maken, moeten alle bewerkingen erin omkeerbaar zijn. Het is niet mogelijk om een ​​deel van een migratie ongedaan te maken, dus een enkele niet-omkeerbare bewerking maakt de hele migratie onomkeerbaar.

Een RunSQL maken bewerking omkeerbaar, moet u SQL opgeven om uit te voeren wanneer de bewerking wordt omgekeerd. De reverse SQL wordt geleverd in de reverse_sql argument.

De tegenovergestelde actie van het toevoegen van een index is om deze te laten vallen. Om uw migratie omkeerbaar te maken, geeft u de reverse_sql . op om de index te verwijderen:

# migrations/0002_add_index_runsql.py

from django.db import migrations, models

class Migration(migrations.Migration):
    atomic = False

    dependencies = [
        ('app', '0001_initial'),
    ]

    operations = [
        migrations.RunSQL(
            'CREATE INDEX "app_sale_sold_at_b9438ae4" '
            'ON "app_sale" ("sold_at");',

            reverse_sql='DROP INDEX "app_sale_sold_at_b9438ae4";',
        ),
    ]

Probeer nu de migratie ongedaan te maken:

$ python manage.py showmigrations app
app
 [X] 0001_initial
 [X] 0002_add_index_runsql

$ python manage.py migrate app 0001
Operations to perform:
  Target specific migration: 0001_initial, from app
Running migrations:
  Rendering model states... DONE
 Unapplying app.0002_add_index_runsql... OK

$ python manage.py showmigrations app
app
 [X] 0001_initial
 [ ] 0002_add_index_runsql

De tweede migratie werd teruggedraaid en de index werd verwijderd door Django. Nu is het veilig om het migratiebestand te verwijderen:

$ rm app/migrations/0002_add_index_runsql.py

Het is altijd een goed idee om reverse_sql . op te geven . In situaties waarin het ongedaan maken van een onbewerkte SQL-bewerking geen actie vereist, kunt u de bewerking als omkeerbaar markeren met behulp van de speciale sentinel migrations.RunSQL.noop :

migrations.RunSQL(
    sql='...',  # Your forward SQL here
    reverse_sql=migrations.RunSQL.noop,
),


Modelstatus en databasestatus begrijpen

In uw vorige poging om de index handmatig te maken met behulp van RunSQL , Django genereerde keer op keer dezelfde migratie, ook al was de index in de database gemaakt. Om te begrijpen waarom Django dat deed, moet je eerst begrijpen hoe Django beslist wanneer nieuwe migraties moeten worden gegenereerd.


Wanneer Django een nieuwe migratie genereert

Tijdens het genereren en toepassen van migraties synchroniseert Django tussen de status van de database en de status van de modellen. Wanneer u bijvoorbeeld een veld aan een model toevoegt, voegt Django een kolom toe aan de tabel. Wanneer u een veld uit het model verwijdert, verwijdert Django de kolom uit de tabel.

Om de modellen en de database te synchroniseren, houdt Django een status bij die de modellen vertegenwoordigt. Om de database met de modellen te synchroniseren, genereert Django migratiebewerkingen. Migratiebewerkingen vertalen zich naar een leverancierspecifieke SQL die in de database kan worden uitgevoerd. Wanneer alle migratiebewerkingen zijn uitgevoerd, wordt verwacht dat de database en de modellen consistent zijn.

Om de status van de database te krijgen, verzamelt Django de bewerkingen van alle eerdere migraties. Wanneer de geaggregeerde status van de migraties niet consistent is met de status van de modellen, genereert Django een nieuwe migratie.

In het vorige voorbeeld hebt u de index gemaakt met onbewerkte SQL. Django wist niet dat je de index hebt gemaakt omdat je geen bekende migratiebewerking hebt gebruikt.

Toen Django alle migraties aggregeerde en vergeleek met de staat van de modellen, ontdekte hij dat er een index ontbrak. Dit is de reden waarom, zelfs nadat je de index handmatig had gemaakt, Django nog steeds dacht dat deze ontbrak en er een nieuwe migratie voor genereerde.



Hoe database en status te scheiden in migraties

Aangezien Django niet in staat is om de index te maken zoals u dat wilt, wilt u uw eigen SQL leveren, maar Django toch laten weten dat u deze hebt gemaakt.

Met andere woorden, u moet iets in de database uitvoeren en Django voorzien van de migratiebewerking om de interne status te synchroniseren. Om dat te doen, biedt Django ons een speciale migratiebewerking genaamd SeparateDatabaseAndState . Deze operatie is niet goed bekend en moet worden gereserveerd voor speciale gevallen zoals deze.

Het is veel gemakkelijker om migraties te bewerken dan ze helemaal opnieuw te schrijven, dus begin met het genereren van een migratie op de gebruikelijke manier:

$ python manage.py makemigrations --name add_index_separate_database_and_state

Migrations for 'app':
  app/migrations/0002_add_index_separate_database_and_state.py
    - Alter field sold_at on sale

Dit is de inhoud van de migratie gegenereerd door Django, hetzelfde als voorheen:

# migrations/0002_add_index_separate_database_and_state.py

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('app', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='sale',
            name='sold_at',
            field=models.DateTimeField(
                auto_now_add=True,
                db_index=True,
            ),
        ),
    ]

Django genereerde een AlterField bewerking op het veld sold_at . De bewerking maakt een index en werkt de status bij. We willen deze bewerking behouden, maar een ander commando geven om uit te voeren in de database.

Nogmaals, om de opdracht te krijgen, gebruik je de SQL die is gegenereerd door Django:

$ python manage.py sqlmigrate app 0002
BEGIN;
--
-- Alter field sold_at on sale
--
CREATE INDEX "app_sale_sold_at_b9438ae4" ON "app_sale" ("sold_at");
COMMIT;

Voeg de CONCURRENTLY . toe zoekwoord op de juiste plaats:

CREATE INDEX CONCURRENTLY "app_sale_sold_at_b9438ae4"
ON "app_sale" ("sold_at");

Bewerk vervolgens het migratiebestand en gebruik SeparateDatabaseAndState om uw gewijzigde SQL-opdracht voor uitvoering te verstrekken:

# migrations/0002_add_index_separate_database_and_state.py

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('app', '0001_initial'),
    ]

    operations = [

        migrations.SeparateDatabaseAndState(

            state_operations=[
                migrations.AlterField(
                    model_name='sale',
                    name='sold_at',
                    field=models.DateTimeField(
                        auto_now_add=True,
                        db_index=True,
                    ),
                ),
            ],

            database_operations=[
                migrations.RunSQL(sql="""
                    CREATE INDEX CONCURRENTLY "app_sale_sold_at_b9438ae4"
                    ON "app_sale" ("sold_at");
                """, reverse_sql="""
                    DROP INDEX "app_sale_sold_at_b9438ae4";
                """),
            ],
        ),

    ],

De migratiebewerking SeparateDatabaseAndState accepteert 2 lijsten met bewerkingen:

  1. state_operations zijn bewerkingen die moeten worden toegepast op de interne modelstatus. Ze hebben geen invloed op de database.
  2. database_operations zijn bewerkingen die moeten worden toegepast op de database.

Je hebt de oorspronkelijke bewerking behouden die door Django is gegenereerd in state_operations . Bij gebruik van SeparateDatabaseAndState , dit is wat u meestal wilt doen. Merk op dat de db_index=True argument wordt aan het veld gegeven. Deze migratieoperatie laat Django weten dat er een index op het veld is.

Je hebt de SQL gebruikt die door Django is gegenereerd en de CONCURRENTLY . toegevoegd trefwoord. Je hebt de speciale actie RunSQL gebruikt om onbewerkte SQL uit te voeren tijdens de migratie.

Als u de migratie probeert uit te voeren, krijgt u de volgende uitvoer:

$ python manage.py migrate app
Operations to perform:
  Apply all migrations: app
Running migrations:
  Applying app.0002_add_index_separate_database_and_state...Traceback (most recent call last):
  File "/venv/lib/python3.7/site-packages/django/db/backends/utils.py", line 83, in _execute
    return self.cursor.execute(sql)
psycopg2.InternalError: CREATE INDEX CONCURRENTLY cannot run inside a transaction block



Niet-atomaire migraties

In SQL, CREATE , DROP , ALTER , en TRUNCATE bewerkingen worden Data Definition Language genoemd (DDL). In databases die transactionele DDL ondersteunen, zoals PostgreSQL, voert Django standaard migraties uit binnen een databasetransactie. Volgens de bovenstaande fout kan PostgreSQL echter niet tegelijkertijd een index binnen een transactieblok maken.

Om gelijktijdig een index te kunnen maken binnen een migratie, moet u Django vertellen om de migratie niet uit te voeren in een databasetransactie. Om dat te doen, markeert u de migratie als niet-atomair door atomic . in te stellen naar False :

# migrations/0002_add_index_separate_database_and_state.py

from django.db import migrations, models

class Migration(migrations.Migration):
    atomic = False

    dependencies = [
        ('app', '0001_initial'),
    ]

    operations = [

        migrations.SeparateDatabaseAndState(

            state_operations=[
                migrations.AlterField(
                    model_name='sale',
                    name='sold_at',
                    field=models.DateTimeField(
                        auto_now_add=True,
                        db_index=True,
                    ),
                ),
            ],

            database_operations=[
                migrations.RunSQL(sql="""
                    CREATE INDEX CONCURRENTLY "app_sale_sold_at_b9438ae4"
                    ON "app_sale" ("sold_at");
                """,
                reverse_sql="""
                    DROP INDEX "app_sale_sold_at_b9438ae4";
                """),
            ],
        ),

    ],

Nadat u de migratie als niet-atomair heeft gemarkeerd, kunt u de migratie uitvoeren:

$ python manage.py migrate app
Operations to perform:
  Apply all migrations: app
Running migrations:
  Applying app.0002_add_index_separate_database_and_state... OK

U heeft zojuist de migratie uitgevoerd zonder enige downtime te veroorzaken.

Hier zijn enkele zaken waarmee u rekening moet houden wanneer u SeparateDatabaseAndState gebruikt :

  • Databasebewerkingen moeten gelijk zijn aan statusbewerkingen: Inconsistenties tussen de database en de modelstatus kunnen voor veel problemen zorgen. Een goed uitgangspunt is om de door Django gegenereerde bewerkingen in state_operations te houden en bewerk de uitvoer van sqlmigrate te gebruiken in database_operations .

  • Niet-atomaire migraties kunnen niet worden teruggedraaid in geval van een fout: Als er een fout optreedt tijdens de migratie, kunt u niet terugdraaien. U moet de migratie terugdraaien of handmatig voltooien. Het is een goed idee om de bewerkingen die worden uitgevoerd binnen een niet-atomaire migratie tot een minimum te beperken. Als u aanvullende bewerkingen heeft tijdens de migratie, verplaatst u deze naar een nieuwe migratie.

  • Migratie is mogelijk leverancierspecifiek: De SQL die door Django wordt gegenereerd, is specifiek voor de database-backend die in het project wordt gebruikt. Het zou kunnen werken met andere database-backends, maar dat is niet gegarandeerd. Als u meerdere database-backends moet ondersteunen, moet u enkele aanpassingen aan deze aanpak maken.



Conclusie

Je begon deze tutorial met een grote tabel en een probleem. U wilde uw app sneller maken voor uw gebruikers, en u wilde dat doen zonder hen enige downtime te bezorgen.

Aan het einde van de tutorial is het je gelukt om een ​​Django-migratie te genereren en veilig aan te passen om dit doel te bereiken. Je hebt gaandeweg verschillende problemen aangepakt en deze weten op te lossen met behulp van de ingebouwde tools van het migratieframework.

In deze tutorial heb je het volgende geleerd:

  • Hoe Django-migraties intern werken met behulp van model- en databasestatus, en wanneer nieuwe migraties worden gegenereerd
  • Hoe aangepaste SQL in migraties uit te voeren met behulp van de RunSQL actie
  • Wat zijn omkeerbare migraties en hoe maak je een RunSQL actie omkeerbaar
  • Wat atomaire migraties zijn en hoe u het standaardgedrag kunt aanpassen aan uw behoeften
  • Hoe complexe migraties veilig uit te voeren in Django

De scheiding tussen model- en databasestatus is een belangrijk concept. Als u het eenmaal begrijpt en hoe u het kunt gebruiken, kunt u veel beperkingen van de ingebouwde migratiebewerkingen overwinnen. Enkele voorbeelden van gebruik die bij u opkomen zijn het toevoegen van een index die al in de database is gemaakt en het verstrekken van leveranciersspecifieke argumenten aan DDL-commando's.



  1. Meerdere databases tegelijk opvragen

  2. Een primaire sleutel toevoegen aan een bestaande tabel in SQL Server (T-SQL-voorbeelden)

  3. Reguliere expressie (RegEx) voor IPv6 gescheiden van IPv4

  4. Converteer JS date time naar MySQL datetime