Я пытаюсь оптимизировать запрос к базе данных для следующих моделей:
Модель диалога:
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";
"""),
],
),
Но после этого запрос к БД все еще очень и очень медленный, что я тут не так делаю ?? Пожалуйста, помогите.