从Django查询中删除多余的INNER JOIN

时间:2016-11-17 19:39:39

标签: django django-orm

我有这样的模型描述音乐专辑,音乐专辑,以及对特定曲目的个人倾听:

class Album(models.Model):
    name = models.CharField(max_length=255)

class Track(models.Model):
    name = models.CharField(max_length=255)

class Listen(models.Model):
    track = models.ForeignKey('Track', related_name='listens', db_index=True)
    album = models.ForeignKey('Album', related_name='listens', db_index=True, blank=True)

要获取相册中的所有曲目,按照他们听过的次数排序,我可以这样做:

Track.objects \
    .annotate( listen_count=models.Count('listens', distinct=True) ) \
    .filter(listens__album=1294) \
    .order_by('-listen_count')

这样可以正确获得结果,但效果似乎不高。生成的查询的简化版本是:

SELECT track.id,
       track.name,
       COUNT(DISTINCT listen.id) AS listen_count
FROM track
LEFT OUTER JOIN listen ON (track.id = listen.track_id)
INNER JOIN listen T3 ON (track.id = T3.track_id)
WHERE T3.album_id = 1294
GROUP BY track.id, track.name
ORDER BY listen_count DESC

我可以通过丢失INNER JOIN

来获得相同的结果
SELECT track.id,
       track.name,
       COUNT(DISTINCT listen.id) AS listen_count
FROM track
LEFT OUTER JOIN listen ON (track.id = listen.track_id)
WHERE listen.album_id = 1294
GROUP BY track.id, track.name
ORDER BY listen_count DESC

使用少一个索引,大约是速度的一半。但我无法解决如何让Django ORM这样做。 (我现在正在使用SQLite,如果这有所不同,虽然稍后会使用Postgresql。)

1 个答案:

答案 0 :(得分:3)

如果您Heart Attack拳头和> tt2 <- subset(tt, tt$State=="TX") > tt3 <- tt2[order(tt2$`Heart Attack`),] > tt3$`Hospital Name`[1] [1] "CYPRESS FAIRBANKS MEDICAL CENTER" 之后,您的JOIN将被重复使用

.filter

将导致

.annotate