Mikrooptymalizacja zapytań w Django

Mikrooptymalizacją nazywam drobne usprawnienia w kodzie, które nie mają wpływu na architekturę. Nie jestem pedantem, wolę miano człowieka oszczędnego ;).

Główną okazją do mikrooptymalizacji jaka zdarza mi się w codziennej pracy, jest ograniczanie "zasięgu" zapytań do bazy danych.

Przykłady

Widzę dość często taką sytuację:

articles = Articles.objects.filter(author='Bruno')

if articles:
    # a thing

W takim przypadku pobieramy WSZYSTKIE artykuły Bruna tylko po to, żeby zerknąć czy istnieją jakiekolwiek. Taki kod generuje potencjalnie bardzo duże zapytanie:

SELECT * FROM "articles_article" WHERE author == "Bruno";

Kiedy tak naprawdę potrzebujemy tylko wiedzieć czy Bruno napisał chociaż jeden artykuł. Dokumentacja na ratunek nam przyśle exists():

articles = Articles.objects.filter(author='Bruno')

if articles.exists():
    # a thing

Ale w dokumentacji jesteśmy uczciwie ostrzegani, że exists() wygeneruje takie samo zapytanie co nasz poprzedni przypadek, po prostu po stronie Django rezultaty nie będą deserializowane do obiektów.

Jeżeli naprawdę chcecie być pewni, że Wasze zapytanie będzie możliwie jak najmniejsze - polecam bramkę numer 3:

articles = Articles.objects.filter(author='Bruno')

if articles[:1].count():
    # a thing

W tym przypadku najpierw ograniczamy całe zapytanie za pomocą LIMIT 1 i zamiast pobierania całego wiersza z bazy używamy tylko COUNT(*) za pomocą opisanego w dokumentacji count()


To tyle na dziś. Morał mamy następujący: czytajmy dokumentacje do Django, jest bardzo dobra, wyczerpująca i opisuje realne przypadki użycia. Jeżeli chcecie poznać inne sztuczki na mikrooptymalizację zapytań - polecam zerknąć na rozdział dotyczący zapytań, w szczególności zwróćcie uwagę na select_related, values_list, update, first/last oraz latest.