speeding up rails
ruby on rails langzamer
- Benchmarks in vergelijking met andere talen
- Interpreted vs. compiled language
- Garbage collection
- Langzamere method calls
Oorzaken
- Meestal database queries
- Teveel data inladen
- N+1 queries
- Te weinig cached waardes
- Te weinig database queries
Lijkt snel
- Applicatie kan snel zijn in het begin
- Steeds meer database entries
- Groot verschil
Existence checks
- Worden heel vaak gebruikt
- Verschillende functies
-
present?
-
empty?
-
any?
-
exists?
- Andere tel-gebaseerde manieren
Present?
Build.where(:created_at => 7.days.ago..1.day.ago).passed.present?
SELECT "builds".* FROM "builds" WHERE ("builds"."created_at" BETWEEN
2017-02-22 21:22:27.133402' AND '2017-02-28 21:22:27.133529') AND
"builds"."result" = $1 [["result", "passed"]]
- Laadt alle records in
- Omzetten naar ActiveRecord objecten
- Checken of array leeg is
any? & empty?
Build.where(:created_at => 7.days.ago..1.day.ago).passed.any?
Build.where(:created_at => 7.days.ago..1.day.ago).passed.empty? SELECT COUNT(*) FROM "builds" WHERE ("builds"."created_at" BETWEEN '2017-02-22 21:22:16.885942' AND '2017-02-28 21:22:16.886077') AND "builds"."result" = $1 [["result", "passed"]]
- Geoptimaliseerd in Rails
- Count query is efficiënt
Exists?
Build.where(:created_at => 7.days.ago..1.day.ago).passed.exists?
SELECT 1 AS one FROM "builds" WHERE ("builds"."created_at" BETWEEN
'2017-02-22 21:23:04.066301' AND '2017-02-28 21:23:04.066443') AND
"builds"."result" = $1 LIMIT 1 [["result", "passed"]]
- Nog meer geoptimaliseerd
- Beste keuze
-
SELECT 1...LIMIT 1
Performance
present? => 2892.7 ms
any? => 400.9 ms
empty? => 403.9 ms
exists? => 1.1 ms
Soms 400 keer sneller
200ms is acceptabel
Altijd exists? gebruiken
- Meestal de beste performance
- Any? is sneller als de records in het geheugen zitten
project = Project.find_by_name('ivaldi')
project.builds.load
project.builds.any? # no database hit
project.builds.exists? # hits the database
DATABASE indexes
add_index :projects, :name
- Record ophalen a.d.h.v. bepaalde column
- Bijvoorbeeld column 'name'
- Standaard wordt elk record 1 voor 1 nagelopen, tot een match
Vuistregel
- Alles wat gebruikt wordt in de volgende gedeeltes van queries
WHERE, HAVING, ORDER BY
Bijvoorbeeld:
Project.find_by(name: 'Ivaldi')
Test
- 10.000 projects met index (name), 10.000 companies zonder
- Beiden zelfde ID
Benchmark.ms { Project.find_by_name('Tremayne Cummerata') }
# 0.5210000090301037
Benchmark.ms { Company.find_by_name('Mrs. Elvie Thompson') }
# 0.9719999507069588
Index foreign keys
- belongs_to of has_many relaties
- Let op bij polymorphic relaties
# Maakt geen verschil
add_index :projects, :owner_id
add_index :projects, :owner_type
# Wordt wel sneller
add_index :projects, [:owner_id, :owner_type]
Ordered records
- De column waarop vaak gesorteerd wordt
Project.order(:name)
add_index :name
test
Benchmark.ms { Project.order(:name) }
# 0.07900013588368893
Benchmark.ms { Company.order(:name) }
# 0.10000006295740604
Altijd indexes gebruiken?
- Performance kan sterk verbeterd worden
- Soms kan het geen nut hebben (of langzamer maken)
- Tabellen met veel verwijderde records of velden
- Hele grote tabellen nemen meer ruimte in beslag voor de indexes
speeding up rails
By Dimitri Snijder
speeding up rails
- 33