Django оптимизация запросов ORM - PullRequest
0 голосов
/ 03 марта 2020

Я пытаюсь оптимизировать запрос к базе данных для следующих моделей:

Модель диалога:

class Conversation(_BaseModel):
    is_test = models.BooleanField(default=False)
    meta = JSONField(default=dict)
    timestamp = models.DateTimeField()
    bot_version = models.CharField(max_length=128, blank=True)
    listen_mode = models.BooleanField(default=False)

Модель сообщения:

class Message(_BaseModel):

    conversation = models.ForeignKey(
        'Conversation', on_delete=models.CASCADE, related_name='messages'
    )
timestamp = models.DateTimeField()
    message = models.TextField(null=True, blank=True, db_index=True)
    response = models.TextField(null=True, blank=True)
    data = JSONField(blank=True, null=True)
    meta = JSONField(default=dict, blank=True)

Запрос:

conversations = Conversation.objects.filter(
                ~Q(messages__message='[{"text": "", "type": "text"}]') | ~Q(messages__message='[{"type": "text", "text": ""}]')
            )

Но я получаю отставание, поскольку оно настолько медленное, поскольку таблица сообщений в БД содержит более 5 миллионов строк. Поэтому я прочитал и попытался использовать индексы БД, где я добавил индекс в поле сообщения в таблице сообщений.

message = models.TextField(null=True, blank=True, db_index=True)

, и у меня возникла ошибка

django.db.utils.OperationalError: index row size 3096 exceeds maximum 2712 for index "bot_api_message_message_00003"
HINT:  Values larger than 1/3 of a buffer page cannot be indexed.
Consider a function index of an MD5 hash of the value, or use full text indexing

Это это когда я наткнулся на решение, которое закончилось тем, что я создал файл миграции с измененным полем сообщения и вручную написал sql, чтобы создать индекс в БД, используя MD5 поля сообщения, например

operations = [

    migrations.SeparateDatabaseAndState(

        state_operations = [
            migrations.AlterField(
                model_name='message',
                name='message',
                field=models.TextField(blank=True, db_index=True, null=True),
            ),
        ],

        database_operations=[
            migrations.RunSQL(sql="""
                CREATE INDEX CONCURRENTLY "bot_api_message_message_00004"
                ON "bot_api_message"(md5("message")) 
                WHERE md5("message") != md5('[{"type": "text", "text": ""}]')
                OR md5("message") != md5('[{"text": "", "type": "text"}]');
            """,
            reverse_sql="""
                DROP INDEX "bot_api_message_message_00004";
            """),
        ],
    ),

Но после этого запрос к БД все еще очень и очень медленный, что я тут не так делаю ?? Пожалуйста, помогите.

...