В моем приложении django я определил модель следующим образом:
class NamedContainer(models.Model):
name = models.CharField(max_length=50)
capacity_ml = models.PositiveIntegerField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['name', 'capacity_ml']
Со временем эта таблица стала достаточно большой, чтобы начать вызывать некоторые проблемы с производительностью запросов, особенно при использовании предела /смещение для нарезки .Другие методы нарезки могут иметь лучшую производительность по конструкции, но пока, к сожалению, я застрял с лимитом / смещением.
Однако MySQL имеет технику, называемую «поиск в конце строки» , которая значительнопомогает с моей проблемой, и, короче говоря, необработанный запрос MySQL, использующий эту технику, может выглядеть примерно так:
SELECT t2.* FROM (
SELECT *
FROM `core_namedcontainer`
WHERE `updated_at` >= '2019-01-01 05:00:00.000Z'
ORDER BY id ASC
LIMIT 500 OFFSET 10000
) AS t1
JOIN `core_namedcontainer` AS t2
ON t1.id = t2.id
ORDER BY `name` ASC, `capacity_ml` ASC
Мне удалось только манипулировать запросом ORM, чтобы создать запрос типа
SELECT *
FROM `core_namedcontainer`
WHERE (
`core_namedcontainer`.`id` IN (
SELECT U0.`id`
FROM `core_namedcontainer` U0
WHERE (
U0.`updated_at` >= 2019-01-01 05:00:00
)
ORDER BY U0.`name` ASC, U0.`capacity_ml` ASC
LIMIT 500 OFFSET 10000
)
)
ORDER BY `core_namedcontainer`.`name` ASC, `core_namedcontainer`.`capacity_mL` ASC
, который просто использует подзапрос вместо соединения с самим собой, и при оценке запроса MySQL жалуется с помощью
NotSupportedError: (1235, "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'")
Приложение django использует MySQL 5.6 и по ряду причинпотребуется некоторое время, прежде чем он сможет обновиться до чего-то более нового.
Я знаю, что могу просто выполнить необработанный SQL-запрос так, как мне нужно, но я надеюсь, что есть способпереведите эту технику в синтаксис Django ORM, чтобы я мог использовать эту технику в своей модели в качестве базового набора запросов:
class NamedContainerManager(models.Manager):
def get_queryset(self):
queryset = super().get_queryset()
# do some ORM magic here to implement mysql late row lookup in all queries
return queryset
class NamedContainer(models.Model):
...
objects = NamedContainerManager()
Вся помощь очень ценится!