Załóżmy, że chcę wyświetlić listę biegaczy zamówioną przez ich ostatni czas sprintu.Django: Zamawianie zestawu zapytań na podstawie najnowszego pola modeli podrzędnych
class Runner(models.Model):
name = models.CharField(max_length=255)
class Sprint(models.Model):
runner = models.ForeignKey(Runner)
time = models.PositiveIntegerField()
created = models.DateTimeField(auto_now_add=True)
Jest to szybki szkic tego, co chciałbym zrobić w SQL:
SELECT runner.id, runner.name, sprint.time
FROM runner
LEFT JOIN sprint ON (sprint.runner_id = runner.id)
WHERE
sprint.id = (
SELECT sprint_inner.id
FROM sprint as sprint_inner
WHERE sprint_inner.runner_id = runner.id
ORDER BY sprint_inner.created DESC
LIMIT 1
)
OR sprint.id = NULL
ORDER BY sprint.time ASC
W Django QuerySet documentation Zjednoczone:
Dopuszczalne jest określenie boiska wielofunkcyjnego o wartościach do nakazywania wyników według (na przykład pola ManyToManyField). Zwykle nie jest to rozsądna rzecz do zrobienia i jest to naprawdę zaawansowana funkcja użytkowania. Jeśli jednak wiesz, że twoje filtrowanie lub dostępne dane z zestawu zapytań oznacza, że będzie tylko jeden element zamówienia dla każdego z głównych pozycji, które wybierzesz, kolejność może dokładnie wynosić , co chcesz zrobić. Skorzystaj z porządkowania na polach wielowartościowych z ostrożnością i sprawdź, czy wyniki są zgodne z oczekiwaniami.
Chyba muszę zastosować jakiś filtr tutaj, ale nie jestem pewien, co dokładnie Django oczekuje ...
Jedna uwaga, ponieważ nie jest oczywiste w tym przykładzie: tabela Runner będzie mieć kilka sto wpisów, sprintów będzie również kilkaset, aw niektóre dni później prawdopodobnie kilka tysięcy wpisów. Dane będą wyświetlane w widoku stronicowanym, więc sortowanie w Pythonie nie jest opcją.
Jedyną inną możliwością, którą widzę jest pisanie samego SQL, ale chciałbym tego uniknąć za wszelką cenę
Czy to nie powoduje stosunkowo wysokiego zużycia pamięci? O ile widzę, wciąga co najmniej każdego biegacza do pamięci i buduje raczej dużą listę swoich identyfikatorów sprintu. Robiąc to na każdym widoku strony z kilkuset biegaczami w DB, czuję się * trochę * niewygodny. To jest przypadek, w którym buforowanie się rozpoczyna. – Strayer
Po przetestowaniu tego z 10 000 uczestników, zużyto mniej niż 10 MB (3 MB faktycznie ...) pamięci RAM. Jeśli uważasz, że będziesz potrzebować czegoś więcej, naprawdę powinieneś używać surowego SQL. Jak zawsze najlepszym sposobem na to jest profilowanie - nie spekuluj. Przedwczesna optymalizacja i wszystko to ... – Matt
A kilkaset płyt naprawdę nie jest dużo ... na pewno nie na tyle, aby uzasadnić obawy dotyczące optymalizacji wydajności. Kilkaset tysięcy rekordów jest zwykle tam, gdzie zaczynasz o tym myśleć, a nawet wtedy zwykle nie stanowi to problemu (wrzucanie do indeksu lub dwóch i jest rozwiązany). – Matt