Wydajność jest jednym z najważniejszych aspektów, które należy wziąć pod uwagę podczas tworzenia aplikacji internetowych. Analiza sposobu pobierania danych z bazy danych jest dobrym punktem wyjścia przy poszukiwaniu ulepszeń. W tym artykule znajdziesz przykłady, jak poprawić wydajność za pomocą funkcji agregujących i filtrowania danych na poziomie bazy danych.
Na początek trochę kontekstu
Ten artykuł został zainspirowany prawdziwym problemem, z którym miałem kiedyś do czynienia. Poradzenie sobie z nim wiele mnie nauczyło i wciąż mam go w pamięci. Uważam, że przykłady są dobrym źródłem wiedzy i mogą wiele wyjaśnić. W tym artykule chciałbym podzielić się z wami kilkoma przykładami użycia metod zapytań Active Record.
Aby nie wprowadzać szczegółów specyficznych dla domeny, użyję przykładowej aplikacji dla biblioteki, aby zilustrować przykłady. Wszystko jest dość proste, jak pokazano na poniższym diagramie. Mamy cztery tabele: autorzy, książki, użytkownicy i wypożyczenia. Jeden użytkownik może wypożyczyć wiele książek, a jedna książka może być wypożyczona przez wielu użytkowników, więc potrzebujemy tabeli łączącej, aby modelować relacje wiele do wielu. W naszym przypadku jest to tabela wypożyczeń. Przechowujemy tam również dodatkowe informacje, takie jak daty wypożyczenia i zwrotu. Autor może mieć wiele książek przypisanych do swojego nazwiska. Książka ma również atrybut określający jej gatunek.
Statystyki odczytu użytkowników
Zadanie polegało na przygotowaniu statystyk dla pojedynczego użytkownika, abyśmy mogli określić, ile książek z każdego gatunku zostało wypożyczonych. Moim pierwszym pomysłem było pobranie wszystkich książek, które zostały wypożyczone przez użytkownika, pogrupowanie ich według gatunku, a następnie wykonanie mapowania, tak aby każdy gatunek miał przypisaną liczbę książek zamiast listy. Oto co wymyśliłem:
Chociaż to podejście działa i wygląda czysto, nie wykorzystuje wszystkich możliwości, jakie oferują metody zapytań Active Record. Dzięki nim, jesteśmy w stanie filtrować i agregować dane na poziomie bazy danych bez użycia surowego SQL bezpośrednio w naszej aplikacji kod. Działanie na poziomie db zwiększa również naszą wydajność.
W powyższym przykładzie możemy użyć metody group zamiast grupy Rubiegowedług metody. Zastosuje ona GROUPBY do zapytania tSQL. Ponadto metodę mapowania i rozmiaru można zastąpić funkcją agregacji liczby. Ostatecznie otrzymujemy zapytanie, które wygląda następująco:
Book.joins(:rentals).where(rentals: { user: user }).group(:genre).count(:books)
Wygląda to jeszcze prościej!
Inne przydatne przykłady
Poniżej znajdziesz kilka innych sposobów korzystania z metod zapytań, które moim zdaniem warto znać.
Zaproszenie dla nieaktywnych użytkowników
ZADANIE: Odfiltrować użytkowników, którzy nigdy nie wypożyczyli książki lub zrobili to ponad rok temu.
Moglibyśmy pobrać wszystkich użytkowników z uwzględnieniem powiązanych wypożyczalni, a następnie przefiltrować ich za pomocą metody select.
User.includes(:rentals).select do |user|
user.rentals.empty? | user.rentals.none? { |rental| rental.start_date >= Date.today - 1.year }
end
Ale oczywiście nie ma potrzeby pobierania wszystkiego. Korzystając z metod zapytań, możemy odfiltrować je na poziomie bazy danych. Najpierw wybierzmy użytkowników, którzy wypożyczyli jakieś książki w ciągu ostatniego roku, a następnie wykluczmy ich z ostatecznej selekcji.
ZADANIE: Zdobądź autorów z jedną lub zerową liczbą wypożyczonych książek
Zrobienie tego za pomocą metody select jest super proste, ale znowu - nie ma potrzeby operowania na tak dużym zestawie danych, ponieważ db może je przefiltrować za nas:
Ważne jest, aby pamiętać o jednej rzeczy podczas korzystania z złączeń left_joins (i ogólnie złączeń zewnętrznych). Jeśli istnieją rekordy w lewej tabeli (tutaj: autorzy), które nie mają odpowiadających im rekordów w prawej tabeli (tutaj: książki), to w rezultacie kolumny prawej tabeli zostaną wypełnione wartościami zerowymi.
Ponieważ potrzebujemy również autorów z jedną książką przypisaną w systemie, jest jeszcze kilka operacji do wykonania. Będziemy musieli wykonać grupowanie, liczenie i dodanie warunku. Oto jak to wszystko połączyć:
Warunek pojawia się po funkcji agregacji, więc musimy użyć klauzuli HAVING zamiast klauzuli WHERE, aby go określić.
Metody zapytań Active Record są warte sprawdzenia, gdy myślimy o wydajności aplikacji. Mogą one uprościć kod i sprawić, że będzie on działał szybciej. Mam nadzieję, że udostępnione przykłady pomogą ci w odkrywaniu możliwości, jakie oferują metody zapytań.