I Modelle wie diese beschreiben, Musik-Alben haben, verfolgt auf sie, und einzelne hört auf bestimmte Spuren:eine überflüssige INNER aus einer Django Abfrage JOIN Entfernen
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)
auf einem Album, alle Titel zu erhalten, geordnet nach die Anzahl, wie oft sie gehört habe, kann ich:
Track.objects \
.annotate(listen_count=models.Count('listens', distinct=True)) \
.filter(listens__album=1294) \
.order_by('-listen_count')
Diese Ergebnisse bekommt richtig, aber es scheint ineffizient. Eine vereinfachte Version der resultierenden Abfrage ist:
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
ich die gleichen Ergebnisse durch den Verlust bekommen, dass 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
Das verwendet man weniger Index und etwa die Hälfte der Geschwindigkeit. Aber ich kann nicht herausfinden, wie ich das Django ORM dazu bringen kann. (Ich bin derzeit mit SQLite, wenn das einen Unterschied macht, wird, obwohl Postgresql verwenden später.)
Tun Sie die Filterung 1., dann die Annotation + die Bestellung – Todor