Django при выборках с условиями по внешним ключам, связанным с проверкой на NULL, генерирует запросы, содержащие JOIN по каждому такому ключу. К примеру, для модели
class ForumPlugin(models.Model): name = models.CharField( null=False, blank=False, max_length=50, unique=True, verbose_name=_('name') ) class Thread(MPTTModel): parent = TreeForeignKey( 'self', null=True, blank=True, related_name='children', verbose_name=_('parent thread') ) plugin = models.ForeignKey( ForumPlugin, null=True, blank=True, related_name='threads', verbose_name=_('plugin') )
При выполнении выборки
Thread.objects.filter(plugin_isnull=True, parent_isnull=True)
Djando формирует такой запрос:
SELECT `forum_thread`.`id`, `forum_thread`.`parent_id`, `forum_thread`.`plugin_id`, `forum_thread`.`lft`, `forum_thread`.`rght`, `forum_thread`.`tree_id`, `forum_thread`.`level` FROM `forum_thread` LEFT OUTER JOIN `forum_thread` T2 ON (`forum_thread`.`parent_id` = T2.`id`) LEFT OUTER JOIN `forum_forumplugin` ON (`forum_thread`.`plugin_id` = `forum_forumplugin`.`id`) WHERE (T2.`id` IS NULL AND `forum_forumplugin`.`id` IS NULL AND ) ORDER BY `forum_thread`.`id
Естественно время исполнения такого запроса увеличивается на несколько порядков, что при больших таблицах может быть критично. Так на моем проекте на таблице порядка 20-30к записей такая выборка вместо положенной 1мс выполняется от 100мс до 300мс, что увеличивает время генерации страницы вдвое.
К сожалению бага разработчикам ORM известна уже четыре года и имеет долгую и печальную историю.
В данный момент присутствует во всех стабильных версиях, в том числе в 1.4.3. Предполагается, что в 1.5 она наконец-то будет исправлена.
В качестве обходного пути советуют использовать двойное отрицание:
Thread.objects.exclude(plugin_isnull=False, parent_isnull=False)
но мне не удалось на практике таким способом избавится от проблемы. Обращение напрямую к полю parent_id также не помогает.
Будьте внимательны при проектировании моделей и старайтесь учитывать эту особенность Django, и избегать выборок по внешним ключам с использованием NULL условий.
ссылка на оригинал статьи http://habrahabr.ru/post/165895/
Добавить комментарий