Django добавить операцию Run SQL после добавления ограничения ForeignKey при миграции - PullRequest
0 голосов
/ 06 мая 2020

Я использую Django 2,1 , Python 3,6 и MySQL 8 .

В базе достаточно огромная таблица с большим количеством больших строк, поэтому перенос, примененный к этой таблице, занимает часы. Я обнаружил, что если я удалю полнотекстовый индекс из этой таблицы, он активирует inplace alghorithm таблицы модификации - это намного быстрее.

Так что мне нужно воспользоваться этим в Django. Я подумал об удалении полнотекстового индекса в качестве первой операции миграции и создании его снова после всех остальных операций.

operations = [
    migrations.CreateModel(
        name='NewModel',
        fields=[
            ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
        ],
        options={
            'abstract': False,
        },
    ),
    migrations.RunSQL(
        ('DROP INDEX fulltext_idx_content ON summarizer_model',),
        ('CREATE FULLTEXT INDEX fulltext_idx_content ON summarizer_model(content)',),
    ),
    migrations.AddField(
        model_name='model',
        name='new_model',
        field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='new_models_objects', to='summarizer.new_model'),
    ),
    migrations.RunSQL(
        ('CREATE FULLTEXT INDEX fulltext_idx_content ON summarizer_model(content)',),
        ('DROP INDEX fulltext_idx_content ON summarizer_model',),
    ),
]

(Я быстро анонимизировал приведенный выше фрагмент кода, поэтому, если есть какой-то логический ошибка, пожалуйста, извините - здесь не тот случай :))

Проблема в том, что Django миграция всегда помещает добавление ограничения ForeignKey в качестве последней операции. Итак, после моего последнего RunSQL, который создает индекс обратно. Это делает его очень медленным (копирование всей таблицы с новым столбцом).

Есть ли способ преодолеть это? Думаю, было бы странно помещать другой файл миграции только для создания индекса. Я просто хочу временно удалить индекс на время миграции.

Спасибо

1 Ответ

0 голосов
/ 08 мая 2020

После того, как я покопался во внутренностях Django миграций, я обнаружил, что некоторые операции миграции в Django добавляют SQL-запросы в так называемый deferred_sql список в объекте схемы. Итак, зная, что решение моей проблемы было унаследовано от операции RunSQL. Вместо немедленного выполнения SQL я добавляю его в список deferred_sql и ... готово!

class DeferredForwardRunSQL(RunSQL):
def database_forwards(self, app_label, schema_editor, from_state, to_state):
    schema_editor.deferred_sql.append(self.sql[0])

Мне также нужно было изменить последнюю операцию Run SQL из миграции:

operations = [
    migrations.CreateModel(
        name='NewModel',
        fields=[
            ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
        ],
        options={
            'abstract': False,
        },
    ),
    migrations.RunSQL(
        ('DROP INDEX fulltext_idx_content ON summarizer_model',),
        ('CREATE FULLTEXT INDEX fulltext_idx_content ON summarizer_model(content)',),
    ),
    migrations.AddField(
        model_name='model',
        name='new_model',
        field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='new_models_objects', to='summarizer.new_model'),
    ),
    DeferredForwardRunSQL(
        ('CREATE FULLTEXT INDEX fulltext_idx_content ON summarizer_model(content)',),
        ('DROP INDEX fulltext_idx_content ON summarizer_model',),
    ),
]

Хорошо работает и в обратном направлении

...