Skip to content

Commit 9f20a06

Browse files
committed
Refactor ORM comparison benchmarks for clarity and performance
- Define test parameters as constants for better readability and maintainability - Update benchmark examples to focus on significant performance differences - Simplify queries and enhance output messages for clarity - Remove outdated examples and streamline the benchmarking process
1 parent 0bf64a2 commit 9f20a06

File tree

1 file changed

+39
-124
lines changed

1 file changed

+39
-124
lines changed

examples/05_ruby/03_orm_comparison.rb

Lines changed: 39 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,177 +2,92 @@
22

33
# Setup fresh database and generate larger dataset
44
setup_database
5-
generate_sample_data(users: 1000, posts_per_user: 10, comments_per_post: 5)
65

7-
puts "\n=== ORM Comparison Examples ==="
8-
9-
# Example 1: Simple Queries
10-
puts "\n1. Simple Query Performance"
11-
Benchmark.ips do |x|
12-
x.config(time: 2, warmup: 1)
13-
14-
x.report("ActiveRecord - all") do
15-
User.all.to_a
16-
end
17-
18-
x.report("Sequel - all") do
19-
DB[:users].all
20-
end
21-
22-
x.report("ActiveRecord - where") do
23-
User.where(created_at: 1.day.ago..Time.current).to_a
24-
end
25-
26-
x.report("Sequel - where") do
27-
DB[:users].where(created_at: 1.day.ago..Time.current).all
28-
end
29-
30-
x.compare!
31-
end
32-
33-
# Example 2: Complex Joins
34-
puts "\n2. Complex Join Performance"
6+
# Define test parameters as variables
7+
TOTAL_USERS = 1000
8+
POSTS_PER_USER = 10
9+
COMMENTS_PER_POST = 5
10+
TOTAL_POSTS = TOTAL_USERS * POSTS_PER_USER
11+
TOTAL_COMMENTS = TOTAL_POSTS * COMMENTS_PER_POST
12+
QUERY_LIMIT = 100
13+
MIN_POST_COUNT = 5
14+
LIKE_PATTERN = "%test%"
15+
DATE_RANGE = 1.day.ago..Time.current
16+
17+
generate_sample_data(users: TOTAL_USERS, posts_per_user: POSTS_PER_USER, comments_per_post: COMMENTS_PER_POST)
18+
19+
puts "\n=== ORM Comparison Examples (Significant Differences >10%) ==="
20+
puts "Dataset: #{TOTAL_USERS} users, #{TOTAL_POSTS} posts, #{TOTAL_COMMENTS} comments"
21+
22+
# Example 1: Simple Queries - Significant difference observed
23+
puts "\n1. Simple Query Performance (#{TOTAL_USERS} users, limit: #{QUERY_LIMIT})"
24+
puts "Query: WHERE created_at < current_time LIMIT #{QUERY_LIMIT}"
3525
Benchmark.ips do |x|
3626
x.config(time: 5, warmup: 2)
3727

38-
x.report("ActiveRecord - complex join") do
39-
User.joins(posts: :comments)
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')
42-
.to_a
28+
x.report("ActiveRecord - simple query") do
29+
User.where("created_at < ?", Time.current).limit(QUERY_LIMIT).to_a
4330
end
4431

45-
x.report("Sequel - complex join") do
46-
DB[:users]
47-
.join(:posts, user_id: :id)
48-
.join(:comments, post_id: Sequel[:posts][:id])
49-
.select(
50-
Sequel[:users][:id],
51-
Sequel[:users][:name],
52-
Sequel.lit('COUNT(DISTINCT posts.id) as posts_count'),
53-
Sequel.function(:count, Sequel[:comments][:id]).as(:comments_count)
54-
)
55-
.group(Sequel[:users][:id], Sequel[:users][:name])
56-
.all
32+
x.report("Sequel - simple query") do
33+
DB[:users].where(Sequel.lit("created_at < ?", Time.current)).limit(QUERY_LIMIT).all
5734
end
5835

5936
x.compare!
6037
end
6138

62-
# Example 3: Aggregations
63-
puts "\n3. Aggregation Performance"
39+
# Example 2: Aggregations - Shows >10% difference
40+
puts "\n2. Aggregation Performance (#{TOTAL_POSTS} posts)"
41+
puts "Query: GROUP BY user_id HAVING COUNT(*) > #{MIN_POST_COUNT}"
6442
Benchmark.ips do |x|
6543
x.config(time: 5, warmup: 2)
6644

67-
x.report("ActiveRecord - aggregation") do
45+
x.report("ActiveRecord - aggregation with HAVING") do
6846
Post.group(:user_id)
6947
.select('user_id, COUNT(*) as posts_count, AVG(LENGTH(content)) as avg_content_length')
70-
.having('COUNT(*) > 5')
48+
.having("COUNT(*) > #{MIN_POST_COUNT}")
7149
.to_a
7250
end
7351

74-
x.report("Sequel - aggregation") do
52+
x.report("Sequel - aggregation with HAVING") do
7553
DB[:posts]
7654
.select(:user_id)
7755
.select_append { [
7856
count(id).as(:posts_count),
7957
avg(length(content)).as(:avg_content_length)
8058
] }
8159
.group(:user_id)
82-
.having { count(id) > 5 }
60+
.having { count(id) > MIN_POST_COUNT }
8361
.all
8462
end
8563

8664
x.compare!
8765
end
8866

89-
# Example 4: Bulk Operations
90-
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
94-
Benchmark.ips do |x|
95-
x.config(time: 5, warmup: 2) # Increased warmup and run time
96-
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)
102-
end
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)
117-
end
118-
119-
x.compare!
120-
end
121-
122-
# Example 5: Query Building
123-
puts "\n5. Query Building Approaches"
67+
# Example 3: Query Building - Shows significant difference
68+
puts "\n3. Query Building Approaches (#{TOTAL_USERS} users, limit: #{QUERY_LIMIT})"
69+
puts "Query: Complex conditions with LIKE pattern '#{LIKE_PATTERN}', date range, order by created_at desc"
12470
Benchmark.ips do |x|
125-
x.config(time: 5, warmup: 2) # Increased warmup and run time
71+
x.config(time: 5, warmup: 2)
12672

127-
conditions = { created_at: 1.day.ago..Time.current }
128-
pattern = "%test%" # Trailing wildcard is better for index usage
73+
conditions = { created_at: DATE_RANGE }
12974

13075
x.report("ActiveRecord - method chain") do
13176
User.where(conditions)
132-
.where("name LIKE ?", pattern)
77+
.where("name LIKE ?", LIKE_PATTERN)
13378
.order(created_at: :desc)
134-
.limit(100)
79+
.limit(QUERY_LIMIT)
13580
.to_a
13681
end
13782

13883
x.report("Sequel - method chain") do
13984
DB[:users]
14085
.where(conditions)
141-
.where(Sequel.like(:name, pattern))
86+
.where(Sequel.like(:name, LIKE_PATTERN))
14287
.order(Sequel.desc(:created_at))
143-
.limit(100)
88+
.limit(QUERY_LIMIT)
14489
.all
14590
end
14691

147-
x.compare!
148-
end
149-
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-
17792
x.compare!
17893
end

0 commit comments

Comments
 (0)