Skip to content

Commit 0bf64a2

Browse files
committed
Enhance README and ORM comparison examples for clarity and performance
- Update README to include database URI export instructions and improve setup verification steps - Modify ORM comparison benchmarks to increase warmup and run times for more accurate results - Refine SQL queries in benchmarks to avoid duplicate key errors and improve index usage - Add new examples for index-friendly queries to highlight performance differences between leading and trailing wildcards
1 parent 5e40515 commit 0bf64a2

File tree

2 files changed

+67
-46
lines changed

2 files changed

+67
-46
lines changed

README.md

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@ Then test if it's working:
5454
psql -h 0.0.0.0 -d workshop_db
5555
```
5656

57-
```ruby
57+
After the test you can export the database URI that will be used for all
58+
exercises.
59+
60+
```bash
5861
# In your terminal
5962
export DATABASE_URL="postgres://${USER}@0.0.0.0:5432/workshop_db"
6063
```
6164

62-
3. Verify your setup:
65+
3. Verify your setup running the first example:
66+
6367
```ruby
6468
ruby examples/01_storage/practice_storage.rb
6569
# If you see table creation outputs, you're good to go! 🎉
@@ -123,9 +127,9 @@ Optimize Ruby and ActiveRecord usage:
123127
- Query optimization
124128
- Connection pooling
125129

126-
## 🎮 Interactive Learning Tips
130+
## 🎮 Interactive Learning
127131

128-
1. **Experiment Freely**
132+
**Experiment Freely**
129133

130134
```ruby
131135
def learning_approach
@@ -137,18 +141,6 @@ def learning_approach
137141
end
138142
```
139143

140-
2. **Break Things Purposefully**
141-
142-
```ruby
143-
def controlled_chaos
144-
begin
145-
push_the_limits
146-
rescue PostgreSQL::Error => e
147-
understand_why_it_failed(e)
148-
end
149-
end
150-
```
151-
152144
## 🤝 Contributing
153145

154146
Found a bug? Have an improvement idea? Want to add more examples? We love contributions!

examples/05_ruby/03_orm_comparison.rb

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@
3333
# Example 2: Complex Joins
3434
puts "\n2. Complex Join Performance"
3535
Benchmark.ips do |x|
36-
x.config(time: 2, warmup: 1)
36+
x.config(time: 5, warmup: 2)
3737

3838
x.report("ActiveRecord - complex join") do
3939
User.joins(posts: :comments)
40-
.select('users.*, COUNT(DISTINCT posts.id) as posts_count, COUNT(comments.id) as comments_count')
41-
.group('users.id')
40+
.select('users.id, users.name, COUNT(DISTINCT posts.id) as posts_count, COUNT(comments.id) as comments_count')
41+
.group('users.id, users.name')
4242
.to_a
4343
end
4444

@@ -49,7 +49,7 @@
4949
.select(
5050
Sequel[:users][:id],
5151
Sequel[:users][:name],
52-
Sequel.function(:count, Sequel[:posts][:id]).as(:posts_count),
52+
Sequel.lit('COUNT(DISTINCT posts.id) as posts_count'),
5353
Sequel.function(:count, Sequel[:comments][:id]).as(:comments_count)
5454
)
5555
.group(Sequel[:users][:id], Sequel[:users][:name])
@@ -62,7 +62,7 @@
6262
# Example 3: Aggregations
6363
puts "\n3. Aggregation Performance"
6464
Benchmark.ips do |x|
65-
x.config(time: 2, warmup: 1)
65+
x.config(time: 5, warmup: 2)
6666

6767
x.report("ActiveRecord - aggregation") do
6868
Post.group(:user_id)
@@ -79,7 +79,7 @@
7979
avg(length(content)).as(:avg_content_length)
8080
] }
8181
.group(:user_id)
82-
.order(:user_id)
82+
.having { count(id) > 5 }
8383
.all
8484
end
8585

@@ -88,19 +88,32 @@
8888

8989
# Example 4: Bulk Operations
9090
puts "\n4. Bulk Operation Performance"
91+
92+
# Instead of using the original approach which leads to duplicate key errors,
93+
# let's modify the benchmark to test a slightly different bulk operation
9194
Benchmark.ips do |x|
92-
x.config(time: 2, warmup: 1)
95+
x.config(time: 5, warmup: 2) # Increased warmup and run time
9396

94-
x.report("ActiveRecord - bulk insert") do
95-
User.insert_all((1..100).map { |i|
96-
{ name: "User #{i}", email: "user#{i}@example.com", created_at: Time.current, updated_at: Time.current }
97-
})
97+
x.report("ActiveRecord - bulk update") do
98+
# Update all users who were created before now
99+
User.where("created_at < ?", Time.current)
100+
.limit(100)
101+
.update_all(updated_at: Time.current)
98102
end
99103

100-
x.report("Sequel - bulk insert") do
101-
DB[:users].multi_insert((1..100).map { |i|
102-
{ name: "User #{i}", email: "user#{i}@example.com", created_at: Time.current, updated_at: Time.current }
103-
})
104+
x.report("Sequel - bulk update") do
105+
# Sequel doesn't support updates with limit, so we'll use a different approach
106+
# First get the ids of 100 users
107+
ids = DB[:users]
108+
.where(Sequel.lit("created_at < ?", Time.current))
109+
.limit(100)
110+
.select(:id)
111+
.map(:id)
112+
113+
# Then update those specific users
114+
DB[:users]
115+
.where(id: ids)
116+
.update(updated_at: Time.current)
104117
end
105118

106119
x.compare!
@@ -109,10 +122,10 @@
109122
# Example 5: Query Building
110123
puts "\n5. Query Building Approaches"
111124
Benchmark.ips do |x|
112-
x.config(time: 2, warmup: 1)
125+
x.config(time: 5, warmup: 2) # Increased warmup and run time
113126

114127
conditions = { created_at: 1.day.ago..Time.current }
115-
pattern = "%test%"
128+
pattern = "%test%" # Trailing wildcard is better for index usage
116129

117130
x.report("ActiveRecord - method chain") do
118131
User.where(conditions)
@@ -134,16 +147,32 @@
134147
x.compare!
135148
end
136149

137-
puts "\nKey Findings:"
138-
puts "1. Sequel generally performs better for raw SQL operations"
139-
puts "2. ActiveRecord provides better Ruby-like syntax and integration"
140-
puts "3. Complex joins show significant performance differences"
141-
puts "4. Bulk operations benefit from specialized methods"
142-
puts "5. Query building overhead varies between ORMs"
143-
144-
puts "\nRecommendations:"
145-
puts "1. Use Sequel for performance-critical, data-intensive operations"
146-
puts "2. Stick with ActiveRecord for standard CRUD and Rails integration"
147-
puts "3. Consider using both in the same application where appropriate"
148-
puts "4. Profile your specific use case before choosing an ORM"
149-
puts "5. Use bulk operations whenever possible for better performance"
150+
# Example 6: Index-Friendly Queries
151+
puts "\n6. Index-Friendly Query Performance"
152+
Benchmark.ips do |x|
153+
x.config(time: 5, warmup: 2)
154+
155+
# Leading wildcard prevents index usage
156+
leading_wildcard = "%Ruby%"
157+
158+
# No leading wildcard allows index usage
159+
trailing_wildcard = "Ruby%"
160+
161+
x.report("ActiveRecord - leading wildcard (no index)") do
162+
User.where("name LIKE ?", leading_wildcard).to_a
163+
end
164+
165+
x.report("ActiveRecord - trailing wildcard (index)") do
166+
User.where("name LIKE ?", trailing_wildcard).to_a
167+
end
168+
169+
x.report("Sequel - leading wildcard (no index)") do
170+
DB[:users].where(Sequel.like(:name, leading_wildcard)).all
171+
end
172+
173+
x.report("Sequel - trailing wildcard (index)") do
174+
DB[:users].where(Sequel.like(:name, trailing_wildcard)).all
175+
end
176+
177+
x.compare!
178+
end

0 commit comments

Comments
 (0)