2017-10-17 1 views
2

Ich habe eine Situation, in der Django langsam ist, Zeilen aus einer Tabelle zu löschen, wenn sie über einen Fremdschlüssel (FK) mit einer anderen Tabelle verknüpft sind. aber wurden nicht über das Django ORM erstellt.Django langsam zum Löschen von Zeilen basierend auf Fremdschlüssel, wenn Zeilen nicht durch ORM erstellt werden

Ich habe folgendes Django Modell für Record:

class Record(models.Model): 

    job = models.ForeignKey(Job, on_delete=models.CASCADE) 
    index = models.IntegerField(null=True, default=None) 
    record_id = models.CharField(max_length=1024, null=True, default=None) 
    document = models.TextField(null=True, default=None) 
    error = models.TextField(null=True, default=None) 

Das zum Modell zusammenhängt Job über die job-Säule (job_id in MySQL nach Django Migration Erstellung).

Record Zeilen werden jedoch nicht über Django geschrieben, sondern von Apache Spark über jdbc.write(). Ein typisches Beispiel könnte 1 Job mit 45k verwandten Record Reihen sein.

Das Problem ist, während eine Job Instanz über die Django ORM über job.delete() Löschen nicht die zugehörigen Record Zeilen löschen, ist es ziemlich langsam, 5-7 Sekunden für 1 Job mit 45k zugeordnet Record Zeilen 20-30 Sekunden für 160k und so weiter.

Mein Verständnis ist, dass Django emuliertON DELETE CASCADE, um verschiedene DB-Backends unterzubringen, die Sinn macht. Aber ich frage mich: Wenn die Record Zeilen nicht über das Django ORM erstellt werden, umgeht das eine Art von interner Django-Indizierung, die sonst dieses kaskadierende Löschen von verknüpften Record Zeilen viel schneller machen würde?

Die Record Modell Tabellenerstellung SQL sieht wie folgt aus:

core_record | CREATE TABLE `core_record` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `index` int(11) DEFAULT NULL, 
    `record_id` varchar(1024) DEFAULT NULL, 
    `document` longtext, 
    `error` longtext, 
    `job_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `core_record_job_id_8016b123_fk_core_job_id` (`job_id`), 
    CONSTRAINT `core_record_job_id_8016b123_fk_core_job_id` FOREIGN KEY (`job_id`) REFERENCES `core_job` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=338041 DEFAULT CHARSET=utf8 

Wie erwartet, gibt es keine ON DELETE CASCADE für job_id ist. Aber ich habe bemerkt, dass die FK-Beschränkung eine seltsame KEY von core_record_job_id_8016b123_fk_core_job_id hat, von der ich dachte, dass sie eine Art von interner Django-Indexierung vorschlagen könnte. Nach meinem Verständnis indexiert eine InnoDB-Engine automatisch FK-Beziehungen, aber diese Affordanz wird nicht genutzt, wenn Django die Tabellen über das ORM verwaltet.

Ein Ansatz scheint, wie es könnte sein, die core_record Tabelle zu ändern ON DELETE CASCADE für den FK aufzunehmen, und dann Django anweisen nichts on_delete zu tun, auf MySQL angewiesen geordneten Zeilen zu löschen. Aber ich frage mich, ob es Alternativen gibt? Ich möchte vermeiden, die Tabelle manuell zu ändern, wenn möglich, und Django erlauben, die SQL-Migrationen zu verwalten.

Wenn Django eine Art von interner Indexierung für FKs hat, gibt es eine Möglichkeit, Datenbank-/Tabellenzeilen in Django zu indizieren, wenn das ORM die Zeilen nicht erstellt hat?

Alle Vorschläge oder Einsichten sehr geschätzt.

Antwort

0

Es wurde beendet, die Tabelle außerhalb des Django-Kontextes zu erstellen, aber immer noch ein Modell in Django zum Abrufen von Datensätzen und zum Aktualisieren bei Bedarf.

Das Modell sieht thusly, mit der ausgeprägten Bit managed = False sein:

class Record(models.Model): 

    ''' 
    DB model for individual records. 
    Note: This DB model is not managed by Django. 
    ''' 

    job = models.ForeignKey(Job, on_delete=models.CASCADE) 
    index = models.IntegerField(null=True, default=None) 
    record_id = models.CharField(max_length=1024, null=True, default=None) 
    document = models.TextField(null=True, default=None) 
    error = models.TextField(null=True, default=None) 

    # this model is managed outside of Django 
    class Meta: 
     managed = False 

In einigen Voruntersuchungen, Löschen 150k Datensätze mit FKs 3 bis 4 Minuten gingen, auf Sekunden, wenn auf MySQLs unter Berufung Einbau- Indizierung und ON DELETE CASCADE Einstellungen. Ganz zufrieden mit dem Arrangement: Fähigkeit, bequem in Django abzufragen, aber die Leistung von nativem MySQL.

Verwandte Themen