Prestanda är en av de viktigaste aspekterna att ta hänsyn till när man utvecklar webbapplikationer. Att analysera hur data hämtas från en databas är en bra utgångspunkt när man letar efter förbättringar. I den här artikeln hittar du exempel på hur du kan förbättra prestandan genom att använda aggregerade funktioner och filtrera data på databasnivå.
Lite sammanhang till att börja med
Den här artikeln är inspirerad av ett verkligt problem som jag en gång har ställts inför. Att hantera det lärde mig mycket, och jag har det fortfarande som en referens i mitt sinne. Jag tycker att exempel är en bra inlärningsresurs, de kan klargöra mycket. I den här artikeln vill jag dela med mig av några exempel på hur man använder Active Record-frågemetoderna.
För att inte introducera domänspecifika detaljer kommer jag att använda en exempelapplikation för ett bibliotek för att illustrera exempel. Det hela är ganska enkelt, som visas i diagrammet nedan. Vi har fyra tabeller: författare, böcker, användare och uthyrning. En användare kan låna många böcker och en bok kan lånas av många användare, så vi behöver en joining-tabell för att modellera många-till-många-relationer. I vårt fall är det tabellen rentals. Vi lagrar också ytterligare information där, nämligen datum för lån och återlämning. En författare kan ha många böcker kopplade till sitt namn. En bok har också ett attribut som definierar dess genre.
Statistik över användarläsning
Uppgiften var att ta fram statistik för en enskild användare, så att vi kunde se hur många böcker från varje genre som lånats ut. Min första tanke var att hämta alla böcker som har lånats av användaren, gruppera dem efter genre och sedan göra mappningen, så att varje genre har ett antal böcker tilldelade istället för en lista. Här är vad jag kom fram till:
Även om det här tillvägagångssättet fungerar och ser snyggt ut utnyttjar det inte alla de möjligheter som Active Record-frågemetoderna erbjuder. Tack vare dem kan vi filtrera och aggregera data på databasnivå utan att använda rå SQL direkt i våra kod. Att arbeta på en db-nivå ökar också vår effektivitet.
I exemplet ovan kan vi använda metoden group i stället för Ruby's groupper metod. Den kommer att tillämpa GROUPBY-klausul till tSQL-frågan. Dessutom kan kartläggnings- och storleksmetoden ersättas med en räkneaggregationsfunktion. I slutändan har vi kvar en fråga som ser ut så här:
Book.joins(:rentals).where(rentals: { user: user }).group(:genre).count(:books)
Det ser ännu enklare ut!
Andra användbara exempel
Nedan hittar du några andra sätt att använda frågemetoderna som jag tycker är värda att känna till.
Inbjudan till inaktiva användare
UPPGIFT: Filtrera användare som aldrig har lånat en bok eller som gjorde det för mer än ett år sedan.
Vi kan hämta alla användare genom att inkludera de associerade hyrorna och sedan filtrera dem med hjälp av select-metoden.
User.includes(:rentals).select do |user|
användare.uthyrning.tom? || user.rentals.none? { |rental| rental.start_date >= Datum.idag - 1.år }
end
Men det finns naturligtvis inget behov av att hämta allt. Genom att använda query-metoderna kan vi filtrera bort det på db-nivå. Låt oss först välja ut användare som har lånat några böcker under det senaste året och sedan utesluta dem från det slutliga urvalet.
UPPGIFT: Hitta författare med en eller noll utlånade böcker
Att göra det med select-metoden är superenkelt, men återigen - det finns inget behov av att arbeta med en så stor uppsättning data eftersom db kan filtrera det åt oss:
Det är viktigt att komma ihåg en sak när du använder left_joins (och outer joins i allmänhet). Om det finns poster i den vänstra tabellen (här: författare) som inte har motsvarande poster i den högra tabellen (här: böcker), kommer kolumnerna i den högra tabellen att fyllas i med nollvärden.
Eftersom vi också behöver författare med en bok tilldelad i systemet, finns det några fler operationer att göra. Vi måste göra grupperingar, räkna och lägga till ett villkor. Så här sätter vi ihop det hela:
Villkoret kommer efter aggregeringsfunktionen, så vi måste använda HAVING-satsen i stället för WHERE-satsen för att ange det.
Active Record-frågemetoderna är värda att kontrollera när man tänker på applikationsprestanda. De kan förenkla din kod och få den att fungera snabbare. Jag hoppas att de delade exemplen kommer att hjälpa dig att utforska de möjligheter som frågemetoderna har att erbjuda.