Проблема с сабжем в том, что mysql сортирует сначала все выбранные данные, а потом отдает кусочек, который ты указал в limit. Соответстветственно, даже при наличии индекса по полю сортировки он выпадает в filesort если в таблице есть крупные поля.
Обычный подход состоит в том, чтобы сделать задуманое двумя запросами: первым (легким) выгрести только id отсортированных записей и избежать filesort, а вторым уже получить полные записи для этих id.
Ну, например, вот так:
class FoobarManager(models.Manager): def latest(self, limit=10): """ more effecient version of query to avoid filesort """ ids = list(self.values_list('id', flat=True).order_by('-modified')[:limit]) return self.filter(id__in=ids).extra( select={'manual': 'FIELD(id,%s)' % ','.join(map(str, ids))}, order_by=['manual'])
Идея насчет реализации order_by(‘manual’) взята отсюда, а сама необходимость в нем описана вот тут.
Можно не делать order_by(‘manual’), а сделать повторный order_by(‘-modified’) при желании. По идее, производительность не пострадает.
Второй способ решения этой проблемы — вынос больших текстовых полей в отдельную таблицу, выбирать из которой можно по связке one2one.
В связи с этим возникает идея использовать Django MultiTable Inheritance и класть в таблицу предка мелкие поля, в наследника — крупные, а уж запрос Django ORM должен и сам сгенерировать довольно оптимальный. Как–то оно попрозрачнее получится. Надо попробовать, короче