2
2
3
3
# Setup fresh database and generate larger dataset
4
4
setup_database
5
- generate_sample_data ( users : 1000 , posts_per_user : 10 , comments_per_post : 5 )
6
5
7
- puts "\n === ORM Comparison Examples ==="
8
-
9
- # Example 1: Simple Queries
10
- puts "\n 1. 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 "\n 2. 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 "\n 1. Simple Query Performance (#{ TOTAL_USERS } users, limit: #{ QUERY_LIMIT } )"
24
+ puts "Query: WHERE created_at < current_time LIMIT #{ QUERY_LIMIT } "
35
25
Benchmark . ips do |x |
36
26
x . config ( time : 5 , warmup : 2 )
37
27
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
43
30
end
44
31
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
57
34
end
58
35
59
36
x . compare!
60
37
end
61
38
62
- # Example 3: Aggregations
63
- puts "\n 3. Aggregation Performance"
39
+ # Example 2: Aggregations - Shows >10% difference
40
+ puts "\n 2. Aggregation Performance (#{ TOTAL_POSTS } posts)"
41
+ puts "Query: GROUP BY user_id HAVING COUNT(*) > #{ MIN_POST_COUNT } "
64
42
Benchmark . ips do |x |
65
43
x . config ( time : 5 , warmup : 2 )
66
44
67
- x . report ( "ActiveRecord - aggregation" ) do
45
+ x . report ( "ActiveRecord - aggregation with HAVING " ) do
68
46
Post . group ( :user_id )
69
47
. select ( 'user_id, COUNT(*) as posts_count, AVG(LENGTH(content)) as avg_content_length' )
70
- . having ( ' COUNT(*) > 5' )
48
+ . having ( " COUNT(*) > #{ MIN_POST_COUNT } " )
71
49
. to_a
72
50
end
73
51
74
- x . report ( "Sequel - aggregation" ) do
52
+ x . report ( "Sequel - aggregation with HAVING " ) do
75
53
DB [ :posts ]
76
54
. select ( :user_id )
77
55
. select_append { [
78
56
count ( id ) . as ( :posts_count ) ,
79
57
avg ( length ( content ) ) . as ( :avg_content_length )
80
58
] }
81
59
. group ( :user_id )
82
- . having { count ( id ) > 5 }
60
+ . having { count ( id ) > MIN_POST_COUNT }
83
61
. all
84
62
end
85
63
86
64
x . compare!
87
65
end
88
66
89
- # Example 4: Bulk Operations
90
- puts "\n 4. 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 "\n 5. Query Building Approaches"
67
+ # Example 3: Query Building - Shows significant difference
68
+ puts "\n 3. 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"
124
70
Benchmark . ips do |x |
125
- x . config ( time : 5 , warmup : 2 ) # Increased warmup and run time
71
+ x . config ( time : 5 , warmup : 2 )
126
72
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 }
129
74
130
75
x . report ( "ActiveRecord - method chain" ) do
131
76
User . where ( conditions )
132
- . where ( "name LIKE ?" , pattern )
77
+ . where ( "name LIKE ?" , LIKE_PATTERN )
133
78
. order ( created_at : :desc )
134
- . limit ( 100 )
79
+ . limit ( QUERY_LIMIT )
135
80
. to_a
136
81
end
137
82
138
83
x . report ( "Sequel - method chain" ) do
139
84
DB [ :users ]
140
85
. where ( conditions )
141
- . where ( Sequel . like ( :name , pattern ) )
86
+ . where ( Sequel . like ( :name , LIKE_PATTERN ) )
142
87
. order ( Sequel . desc ( :created_at ) )
143
- . limit ( 100 )
88
+ . limit ( QUERY_LIMIT )
144
89
. all
145
90
end
146
91
147
- x . compare!
148
- end
149
-
150
- # Example 6: Index-Friendly Queries
151
- puts "\n 6. 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
92
x . compare!
178
93
end
0 commit comments