2016-11-17 39 views
1

我有模特這樣描述的音樂專輯,請加入他們跟蹤,和個人監聽特定曲目:刪除多餘INNER從一個Django查詢

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。)

+0

做過濾1,然後註釋+訂單 – Todor

回答

3

如果.filter拳頭後,您的連接將被重用

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

.annotate會導致

SELECT 
    "music_track"."id", 
    "music_track"."name", 
    COUNT(DISTINCT "music_listen"."id") AS "listen_count" 
FROM "music_track" 
INNER JOIN "music_listen" ON ("music_track"."id" = "music_listen"."track_id") 
WHERE "music_listen"."album_id" = 1294 
GROUP BY "music_track"."id", "music_track"."name" 
ORDER BY "listen_count" DESC 
+0

哦,那麼簡單!我目前在管理器方法中有註釋部分,所以在我可以將過濾器放在第一位之前,我需要重新組織一些東西,但這應該是可能的。 *所以*更快,謝謝! –

+0

如果你錯過了這個文檔,請看看:[註釋()和過濾器()子句的順序](https://docs.djangoproject.com/en/1.10/topics/db/aggregation/#order -of-註釋和過濾器子句) – Todor