Prestaties zijn een van de belangrijkste aspecten om rekening mee te houden bij het ontwikkelen van webapplicaties. Analyseren hoe gegevens worden opgehaald uit een database is een goed startpunt bij het zoeken naar verbeteringen. In dit artikel vind je voorbeelden van hoe je de prestaties kunt verbeteren door het gebruik van aggregaatfuncties en het filteren van gegevens op databaseniveau.
Wat context om te beginnen
Dit artikel is geïnspireerd op een echt probleem waar ik ooit mee te maken heb gehad. Ik heb er veel van geleerd en ik heb het nog steeds als referentie in mijn hoofd. Ik denk dat voorbeelden een goed leermiddel zijn, ze kunnen veel verduidelijken. In dit artikel wil ik een aantal voorbeelden met je delen van het gebruik van de Active Record query methoden.
Om geen domeinspecifieke details te introduceren, zal ik een voorbeeldapplicatie voor een bibliotheek gebruiken om voorbeelden te illustreren. Het is allemaal vrij eenvoudig, zoals te zien is in het diagram hieronder. We hebben vier tabellen: auteurs, boeken, gebruikers en verhuur. Eén gebruiker kan veel boeken lenen en één boek kan door veel gebruikers geleend worden, dus hebben we een joined tabel nodig om many-to-many relaties te modelleren. In ons geval is dat de verhuurtabel. We slaan er ook wat extra informatie in op, namelijk de data van lenen en terugbrengen. Een auteur kan veel boeken op zijn naam hebben staan. Een boek heeft ook een attribuut dat het genre definieert.
Leesstatistieken voor gebruikers
De taak was om statistieken te maken voor één gebruiker, zodat we konden zien hoeveel boeken van elk genre waren geleend. Mijn eerste gedachte was om alle boeken op te halen die zijn geleend door de gebruiker, ze te groeperen op genre en dan de mapping te doen, zodat aan elk genre een aantal boeken is toegewezen in plaats van een lijst. Dit is wat ik bedacht heb:
Deze aanpak werkt en ziet er netjes uit, maar maakt geen gebruik van alle mogelijkheden die de querymethoden van Active Record bieden. Dankzij deze methoden kunnen we gegevens filteren en aggregeren op databaseniveau zonder direct ruwe SQL te gebruiken in onze code. Werken op db-niveau verhoogt ook onze efficiëntie.
In het bovenstaande voorbeeld kunnen we de groepmethode gebruiken in plaats van Ruby's groepdoor methode. Het zal de GROEPBY-clausule in de tSQL query. Verder kunnen de mapping en size methode vervangen worden door een count aggregation functie. Uiteindelijk houden we een query over die er als volgt uitziet:
Boek.joins(:rentals).where(rentals: { user: user }).group(:genre).count(:books)
Het ziet er nog eenvoudiger uit!
Andere nuttige voorbeelden
Hieronder vind je enkele andere manieren om de querymethoden te gebruiken die ik de moeite waard vind om te weten.
Uitnodiging voor inactieve gebruikers
TASK: Filter gebruikers die nog nooit een boek hebben geleend of dit meer dan een jaar geleden hebben gedaan.
We kunnen alle gebruikers ophalen door de bijbehorende huur op te nemen en ze vervolgens filteren met de select-methode.
User.includes(:rentals).select do |user|
user.rentals.empty? | user.rentals.none? { | rental.start_date >= Date.today - 1.year }
einde
Maar het is natuurlijk niet nodig om alles op te halen. Door de querymethoden te gebruiken, kunnen we het op db-niveau filteren. Laten we eerst gebruikers selecteren die het afgelopen jaar een aantal boeken hebben geleend en deze vervolgens uitsluiten van de uiteindelijke selectie.
TASK: Ontvang auteurs met één of nul geleende boeken
Het doen met de select-methode is super eenvoudig, maar nogmaals - het is niet nodig om te werken op zo'n grote set gegevens als de db het voor ons kan filteren:
Het is belangrijk om één ding te onthouden bij het gebruik van left_joins (en outer joins in het algemeen). Als er records zijn in de linkertabel (hier: auteurs) die geen corresponderende records hebben in de rechtertabel (hier: boeken), dan worden de kolommen in de rechtertabel gevuld met nulwaarden.
Omdat we ook auteurs nodig hebben die één boek toegewezen hebben gekregen in het systeem, moeten we nog een paar bewerkingen uitvoeren. We moeten groeperen, tellen en een voorwaarde toevoegen. Hier is hoe we het allemaal samenvoegen:
De voorwaarde komt na de aggregatiefunctie, dus we moeten de HAVING-clausule gebruiken in plaats van de WHERE-clausule om deze te specificeren.
De Active Record query methoden zijn de moeite waard om te controleren als je aan applicatieprestaties denkt. Ze kunnen je code vereenvoudigen en sneller laten werken. Ik hoop dat de gedeelde voorbeelden je zullen helpen bij het verkennen van de mogelijkheden die de querymethoden te bieden hebben.