Проблема с производительностью Django и Postgres при одном обновлении

#python #python-3.x #django #postgresql

#python #python-3.x #django #postgresql

Вопрос:

У меня периодически возникает проблема с производительностью Django и Postgres при обновлении одной строки в небольшой таблице строк «< 1 м».

APM сообщает о проблеме в строке обновления, которая:

 Model.objects.filter(id=model_id).update(field=True)
  

Предложение filter использует первичный ключ таблицы, а запрос, выполняемый django, является:

 'UPDATE "model" SET "field" = true WHERE "model"."id" = 12345'
  

Ошибка возникает из-за того, что выполнение занимает более 5 секунд.

Этот код выполняется в задаче celery, которая получает идентификатор модели в качестве аргумента и выполняется обычно большую часть времени.

Я знаю, что это очень открытый вопрос, но любая идея или помощь в отношении того, что может произойти, приветствуется.

У меня заканчиваются Python 3.7, Django 2.0.13 и Postgres 9.5.

Комментарии:

1. Индексируются ли столбцы, участвующие в фильтре? Если вы запустите запрос непосредственно в Postgres с EXPLAIN перед ним, что он вернет?

2. Я обновил вопрос с помощью этой информации. Спасибо.

3. Обновление вопроса, вероятно, где-то потерялось, потому что я не могу увидеть там информацию об индексе столбца ни EXPLAIN .

4. Вы можете включить auto_explain для автоматической регистрации EXPLAIN для медленных запросов (может быть снижение производительности, если у вас много медленных запросов).

5. Скорее всего, он заблокирован из-за блокировки. Вы можете установить log_lock_waits, чтобы он регистрировал ожидания блокировки дольше, чем deadlock_timeout.

Ответ №1:

Проблема возникла из-за того, что мы запускали задачу, но иногда она выполнялась до фиксации текущей транзакции, что приводило к блокировке.

Решение состояло в том, чтобы использовать перехват django on_commit следующим образом:

 class DoSomethingTask(Task):
    def apply_async(self, *args, **kwargs):
        transaction.on_commit(
            lambda: super(DoSomethingTask, self).apply_async(*args, **kwargs))


@app.task(base=DoSomethingTask,...)
def do_something(tutor_id):
    ...