mini_sql 0.2.5 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +66 -0
- data/.rubocop.yml +5 -2
- data/CHANGELOG +22 -0
- data/README.md +66 -1
- data/bench/builder_perf.rb +138 -0
- data/bench/decorator_perf.rb +143 -0
- data/bench/mini_sql_methods_perf.rb +80 -0
- data/bench/prepared_perf.rb +59 -0
- data/bench/shared/generate_data.rb +133 -0
- data/bench/topic_perf.rb +21 -327
- data/bench/topic_wide_perf.rb +92 -0
- data/lib/mini_sql.rb +20 -8
- data/lib/mini_sql/abstract/prepared_binds.rb +74 -0
- data/lib/mini_sql/abstract/prepared_cache.rb +45 -0
- data/lib/mini_sql/builder.rb +66 -23
- data/lib/mini_sql/connection.rb +14 -2
- data/lib/mini_sql/decoratable.rb +22 -0
- data/lib/mini_sql/inline_param_encoder.rb +4 -5
- data/lib/mini_sql/mysql/connection.rb +6 -0
- data/lib/mini_sql/mysql/deserializer_cache.rb +9 -15
- data/lib/mini_sql/mysql/prepared_binds.rb +15 -0
- data/lib/mini_sql/mysql/prepared_cache.rb +21 -0
- data/lib/mini_sql/mysql/prepared_connection.rb +44 -0
- data/lib/mini_sql/postgres/connection.rb +75 -3
- data/lib/mini_sql/postgres/deserializer_cache.rb +32 -15
- data/lib/mini_sql/postgres/prepared_binds.rb +15 -0
- data/lib/mini_sql/postgres/prepared_cache.rb +25 -0
- data/lib/mini_sql/postgres/prepared_connection.rb +36 -0
- data/lib/mini_sql/postgres_jdbc/connection.rb +3 -1
- data/lib/mini_sql/postgres_jdbc/deserializer_cache.rb +10 -14
- data/lib/mini_sql/result.rb +30 -0
- data/lib/mini_sql/serializer.rb +84 -0
- data/lib/mini_sql/sqlite/connection.rb +9 -1
- data/lib/mini_sql/sqlite/deserializer_cache.rb +9 -15
- data/lib/mini_sql/sqlite/prepared_binds.rb +15 -0
- data/lib/mini_sql/sqlite/prepared_cache.rb +21 -0
- data/lib/mini_sql/sqlite/prepared_connection.rb +40 -0
- data/lib/mini_sql/version.rb +1 -1
- data/mini_sql.gemspec +6 -5
- metadata +49 -15
- data/.travis.yml +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df275ffff82e8f6fc97b466178d50bcb8e3d5af55167f811abce10356e248770
|
4
|
+
data.tar.gz: 7b943e8a2dca0d546c0140d0957d4712d4f11610f169caefcd01aa7ea8e75e9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fda186dcae83e032b1f120782edd86c8d1d7e276afeb040479fca4e5cc6a52e40499f45df5c9a3303c7823e0e9fed128c17b422bdd12903fa50c4198732c25b
|
7
|
+
data.tar.gz: affcf46e3c8cfffd001fbef3c5d49f938c694a7b85412df7855938fb1326330a386d0557021bd2b1156f7e0bd10a6c1c560cc171190e0ff21e5a06e3375ee984
|
@@ -0,0 +1,66 @@
|
|
1
|
+
name: Mini SQL Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
push:
|
6
|
+
branches:
|
7
|
+
- master
|
8
|
+
|
9
|
+
env:
|
10
|
+
PGHOST: localhost
|
11
|
+
PGPORT: 5432
|
12
|
+
PGPASSWORD: postgres
|
13
|
+
PGUSER: postgres
|
14
|
+
MINI_SQL_MYSQL_HOST: 127.0.0.1
|
15
|
+
MINI_SQL_MYSQL_PORT: 3306
|
16
|
+
MINI_SQL_MYSQL_PASSWORD: mysql
|
17
|
+
jobs:
|
18
|
+
build:
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
name: Ruby ${{ matrix.ruby }}
|
21
|
+
services:
|
22
|
+
postgres:
|
23
|
+
image: postgres:10
|
24
|
+
env:
|
25
|
+
POSTGRES_PASSWORD: postgres
|
26
|
+
ports:
|
27
|
+
- 5432:5432
|
28
|
+
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
29
|
+
mysql:
|
30
|
+
image: mysql:5.7
|
31
|
+
env:
|
32
|
+
MYSQL_ROOT_PASSWORD: mysql
|
33
|
+
ports:
|
34
|
+
- 3306:3306
|
35
|
+
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
36
|
+
strategy:
|
37
|
+
matrix:
|
38
|
+
ruby: ["2.7", "2.6", "2.5"]
|
39
|
+
experimental: [false]
|
40
|
+
include:
|
41
|
+
- ruby: ruby-head
|
42
|
+
experimental: true
|
43
|
+
steps:
|
44
|
+
- uses: actions/checkout@v2
|
45
|
+
- uses: ruby/setup-ruby@v1
|
46
|
+
with:
|
47
|
+
ruby-version: ${{ matrix.ruby }}
|
48
|
+
- name: Bundler cache
|
49
|
+
uses: actions/cache@v2
|
50
|
+
with:
|
51
|
+
path: vendor/bundle
|
52
|
+
key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
53
|
+
restore-keys: |
|
54
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-
|
55
|
+
- name: Create Databases
|
56
|
+
run: |
|
57
|
+
createdb test_mini_sql
|
58
|
+
mysql --host=127.0.0.1 --port=3306 --user=root --password=mysql -e 'CREATE DATABASE test_mini_sql'
|
59
|
+
- name: Setup gems
|
60
|
+
run: |
|
61
|
+
bundle config path vendor/bundle
|
62
|
+
bundle install --jobs 4
|
63
|
+
- name: Tests
|
64
|
+
run: bundle exec rake test
|
65
|
+
- name: Rubocop
|
66
|
+
run: bundle exec rubocop
|
data/.rubocop.yml
CHANGED
data/CHANGELOG
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
2021-03-22 - 1.1.1
|
2
|
+
|
3
|
+
- FIX: compatability with ActiveRecord param encoder
|
4
|
+
|
5
|
+
2021-03-22 - 1.1.0
|
6
|
+
|
7
|
+
- FEATURE: added new APIs to support prepared statements
|
8
|
+
|
9
|
+
2020-12-31 - 1.0.1
|
10
|
+
|
11
|
+
- FIX: revert perf fix broke param_encoder interface, we were expecting never to be called if no encoding was to happen
|
12
|
+
|
13
|
+
2020-12-30 - 1.0
|
14
|
+
|
15
|
+
- Added serialization support using MiniSql::Serializer.to_json / .from_json
|
16
|
+
- Fixed minor issue with cache poisoning when using query_decorator
|
17
|
+
- Version 1.0 to reflect the stability of the interfaces and project, used in productions for almost 2 years now
|
18
|
+
|
19
|
+
2020-06-25 - 0.3
|
20
|
+
|
21
|
+
- Added support for query_each and query_each_hash, which lazily queries rows and enables selecting large result sets by streaming
|
22
|
+
|
1
23
|
2020-04-07 - 0.2.5
|
2
24
|
|
3
25
|
- Added support for custom type maps with Postgres connections
|
data/README.md
CHANGED
@@ -130,10 +130,12 @@ When using Postgres, native type mapping implementation is used. This is roughly
|
|
130
130
|
implemented as:
|
131
131
|
|
132
132
|
```ruby
|
133
|
-
type_map
|
133
|
+
type_map ||= PG::BasicTypeMapForResults.new(conn)
|
134
134
|
# additional specific decoders
|
135
135
|
```
|
136
136
|
|
137
|
+
The type mapper instansitated once on-demand at boot and reused by all mini_sql connections.
|
138
|
+
|
137
139
|
Initializing the basic type map for Postgres can be a costly operation. You may
|
138
140
|
wish to amend the type mapper so for example you only return strings:
|
139
141
|
|
@@ -158,6 +160,48 @@ mini_sql_cnn = MiniSql::Connection.get(pg_cnn, type_map: pg_cnn.type_map_for_res
|
|
158
160
|
|
159
161
|
Note the type mapper for Rails may miss some of the mapping MiniSql ships with such as `IPAddr`, MiniSql is also careful to use the very efficient TimestampUtc decoders where available.
|
160
162
|
|
163
|
+
## Streaming support
|
164
|
+
|
165
|
+
In some exceptional cases you may want to stream results directly from the database. This enables selection of 100s of thousands of rows with limited memory impact.
|
166
|
+
|
167
|
+
Two interfaces exists for this:
|
168
|
+
|
169
|
+
`query_each` : which can be used to get materialized objects
|
170
|
+
`query_each_hash` : which can be used to iterate through Hash objects
|
171
|
+
|
172
|
+
Usage:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
mini_sql_cnn.query_each("SELECT * FROM tons_of_cows limit :limit", limit: 1_000_000) do |row|
|
176
|
+
puts row.cow_name
|
177
|
+
puts row.cow_age
|
178
|
+
end
|
179
|
+
|
180
|
+
mini_sql_cnn.query_each_hash("SELECT * FROM one_million_cows") do |row|
|
181
|
+
puts row["cow_name"]
|
182
|
+
puts row["cow_age"]
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
Note, in Postgres streaming is going to be slower than non-streaming options due to internal implementation in the pq gem, each row gets a full result object and additional bookkeeping is needed. Only use it if you need to optimize memory usage.
|
187
|
+
|
188
|
+
Streaming support is only implemented in the postgres backend at the moment, PRs welcome to add to other backends.
|
189
|
+
|
190
|
+
## Prepared Statements
|
191
|
+
See [benchmark mini_sql](https://github.com/discourse/mini_sql/tree/master/bench/prepared_perf.rb)
|
192
|
+
[benchmark mini_sql vs rails](https://github.com/discourse/mini_sql/tree/master/bench/bilder_perf.rb).
|
193
|
+
|
194
|
+
By default prepared cache size is 500 queries. Use prepared queries only for frequent queries.
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
conn.prepared.query("select * from table where id = ?", id: 10)
|
198
|
+
|
199
|
+
ids = rand(100) < 90 ? [1] : [1, 2]
|
200
|
+
builder = conn.build("select * from table /*where*/")
|
201
|
+
builder.where("id IN (?)", ids)
|
202
|
+
builder.prepared(ids.size == 1).query # most frequent query
|
203
|
+
```
|
204
|
+
|
161
205
|
## I want more features!
|
162
206
|
|
163
207
|
MiniSql is designed to be very minimal. Even though the query builder and type materializer give you a lot of mileage, it is not intended to be a fully fledged ORM. If you are looking for an ORM I recommend investigating ActiveRecord or Sequel which provide significantly more features.
|
@@ -165,6 +209,27 @@ MiniSql is designed to be very minimal. Even though the query builder and type m
|
|
165
209
|
## Development
|
166
210
|
|
167
211
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
212
|
+
### Local testing
|
213
|
+
```bash
|
214
|
+
docker run --name mini-sql-mysql --rm -it -p 33306:3306 -e MYSQL_DATABASE=test_mini_sql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d mysql:5.7
|
215
|
+
export MINI_SQL_MYSQL_HOST=127.0.0.1
|
216
|
+
export MINI_SQL_MYSQL_PORT=33306
|
217
|
+
|
218
|
+
docker run --name mini-sql-postgres --rm -it -p 55432:5432 -e POSTGRES_DB=test_mini_sql -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres
|
219
|
+
export MINI_SQL_PG_USER=postgres
|
220
|
+
export MINI_SQL_PG_HOST=127.0.0.1
|
221
|
+
export MINI_SQL_PG_PORT=55432
|
222
|
+
|
223
|
+
sleep 10 # waiting for up databases
|
224
|
+
|
225
|
+
bundle exec rake
|
226
|
+
|
227
|
+
# end working on mini-sql
|
228
|
+
docker stop mini-sql-postgres mini-sql-mysql
|
229
|
+
```
|
230
|
+
|
231
|
+
Sqlite tests rely on the SQLITE_STMT view existing. This is enabled by default on most systems, however some may
|
232
|
+
opt for a leaner install. See: https://bugs.archlinux.org/task/70072. You may have to recompile sqlite on such systems.
|
168
233
|
|
169
234
|
## Contributing
|
170
235
|
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
gem 'mini_sql', path: '../'
|
8
|
+
gem 'pg'
|
9
|
+
gem 'activerecord'
|
10
|
+
gem 'activemodel'
|
11
|
+
gem 'benchmark-ips'
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'active_record'
|
15
|
+
require 'benchmark/ips'
|
16
|
+
require 'mini_sql'
|
17
|
+
|
18
|
+
require '../mini_sql/bench/shared/generate_data'
|
19
|
+
|
20
|
+
ar_connection, _ = GenerateData.new(count_records: 10_000).call
|
21
|
+
MINI_SQL = MiniSql::Connection.get(ar_connection.raw_connection)
|
22
|
+
|
23
|
+
def mini_sql(is_prepared, user_id)
|
24
|
+
MINI_SQL
|
25
|
+
.build(<<~SQL)
|
26
|
+
/*select*/ from topics /*join*/ /*where*/ /*group_by*/
|
27
|
+
SQL
|
28
|
+
.select('users.first_name, count(distinct topics.id) topics_count')
|
29
|
+
.join('users on user_id = users.id')
|
30
|
+
.join('categories on category_id = categories.id')
|
31
|
+
.where('users.id = ?', user_id)
|
32
|
+
.group_by('users.id')
|
33
|
+
.prepared(is_prepared)
|
34
|
+
.query
|
35
|
+
end
|
36
|
+
|
37
|
+
def mini_sql_optim(is_prepared, user_id)
|
38
|
+
@builder ||=
|
39
|
+
MINI_SQL
|
40
|
+
.build(<<~SQL)
|
41
|
+
/*select*/ from topics /*join*/ /*where*/ /*group_by*/
|
42
|
+
SQL
|
43
|
+
.select('users.first_name, count(distinct topics.id) topics_count')
|
44
|
+
.join('users on user_id = users.id')
|
45
|
+
.join('categories on category_id = categories.id')
|
46
|
+
.where('users.id = :user_id')
|
47
|
+
.group_by('users.id')
|
48
|
+
|
49
|
+
@builder
|
50
|
+
.prepared(is_prepared)
|
51
|
+
.query(user_id: user_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def ar_prepared(user_id)
|
55
|
+
Topic
|
56
|
+
.select(User.arel_table[:first_name] , Topic.arel_table[:id].count)
|
57
|
+
.joins(:user, :category)
|
58
|
+
.where(user_id: user_id)
|
59
|
+
.group(User.arel_table[:id])
|
60
|
+
.load
|
61
|
+
end
|
62
|
+
|
63
|
+
def ar_prepared_optim(user_id)
|
64
|
+
@rel ||= Topic
|
65
|
+
.select(User.arel_table[:first_name] , Topic.arel_table[:id].count)
|
66
|
+
.joins(:user, :category)
|
67
|
+
.group(User.arel_table[:id])
|
68
|
+
|
69
|
+
@rel
|
70
|
+
.where(user_id: user_id)
|
71
|
+
.load
|
72
|
+
end
|
73
|
+
|
74
|
+
def ar_unprepared(user_id)
|
75
|
+
Topic
|
76
|
+
.select('users.first_name, count(distinct topics.id) topics_count')
|
77
|
+
.joins(:user, :category)
|
78
|
+
.where(user_id: user_id)
|
79
|
+
.group('users.id')
|
80
|
+
.load
|
81
|
+
end
|
82
|
+
|
83
|
+
Benchmark.ips do |x|
|
84
|
+
x.report("mini_sql_prepared") do |n|
|
85
|
+
while n > 0
|
86
|
+
mini_sql(true, rand(100))
|
87
|
+
n -= 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
x.report("mini_sql") do |n|
|
91
|
+
while n > 0
|
92
|
+
mini_sql(false, rand(100))
|
93
|
+
n -= 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
x.report("mini_sql_prepared_optim") do |n|
|
98
|
+
while n > 0
|
99
|
+
mini_sql_optim(true, rand(100))
|
100
|
+
n -= 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
x.report("mini_sql_optim") do |n|
|
104
|
+
while n > 0
|
105
|
+
mini_sql_optim(false, rand(100))
|
106
|
+
n -= 1
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
x.report("ar_prepared") do |n|
|
111
|
+
while n > 0
|
112
|
+
ar_prepared(rand(100))
|
113
|
+
n -= 1
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
x.report("ar_prepared_optim") do |n|
|
118
|
+
while n > 0
|
119
|
+
ar_prepared_optim(rand(100))
|
120
|
+
n -= 1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
x.report("ar_unprepared") do |n|
|
125
|
+
while n > 0
|
126
|
+
ar_unprepared(rand(100))
|
127
|
+
n -= 1
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
x.compare!
|
132
|
+
end
|
133
|
+
|
134
|
+
# Comparison:
|
135
|
+
# mini_sql_prepared: 8386.2 i/s
|
136
|
+
# mini_sql: 2742.3 i/s - 3.06x (± 0.00) slower
|
137
|
+
# ar_prepared: 1599.3 i/s - 5.24x (± 0.00) slower
|
138
|
+
# ar_unprepared: 868.9 i/s - 9.65x (± 0.00) slower
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
gem 'pg', github: 'ged/ruby-pg'
|
8
|
+
gem 'mini_sql', path: '../'
|
9
|
+
gem 'activerecord'
|
10
|
+
gem 'activemodel'
|
11
|
+
gem 'benchmark-ips'
|
12
|
+
gem 'sequel', github: 'jeremyevans/sequel'
|
13
|
+
gem 'sequel_pg', github: 'jeremyevans/sequel_pg', require: 'sequel'
|
14
|
+
gem 'draper'
|
15
|
+
gem 'pry'
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'active_record'
|
19
|
+
require 'benchmark/ips'
|
20
|
+
require 'mini_sql'
|
21
|
+
|
22
|
+
require '../mini_sql/bench/shared/generate_data'
|
23
|
+
|
24
|
+
ar_connection, conn_config = GenerateData.new(count_records: 1_000).call
|
25
|
+
MINI_SQL = MiniSql::Connection.get(ar_connection.raw_connection)
|
26
|
+
DB = Sequel.connect(ar_connection.instance_variable_get(:@config).slice(:database, :user, :password, :host, :adapter))
|
27
|
+
|
28
|
+
|
29
|
+
# https://github.com/drapergem/draper
|
30
|
+
class TopicDraper < Draper::Decorator
|
31
|
+
delegate :id
|
32
|
+
|
33
|
+
def title_bang
|
34
|
+
object.title + '!!!'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# https://ruby-doc.org/stdlib-2.5.1/libdoc/delegate/rdoc/SimpleDelegator.html
|
39
|
+
class TopicSimpleDelegator < SimpleDelegator
|
40
|
+
def title_bang
|
41
|
+
title + '!!!'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TopicSequel < Sequel::Model(DB[:topics]); end
|
46
|
+
class TopicDecoratorSequel < TopicSequel
|
47
|
+
def title_bang
|
48
|
+
title + '!!!'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Topic < ActiveRecord::Base;end
|
53
|
+
class TopicArModel < Topic
|
54
|
+
def title_bang
|
55
|
+
title + '!!!'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module TopicDecorator
|
60
|
+
def title_bang
|
61
|
+
title + '!!!'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
Benchmark.ips do |r|
|
66
|
+
r.report('query_decorator') do |n|
|
67
|
+
while n > 0
|
68
|
+
MINI_SQL.query_decorator(TopicDecorator, 'select id, title from topics order by id limit 1000').each do |obj|
|
69
|
+
obj.title_bang
|
70
|
+
obj.id
|
71
|
+
end
|
72
|
+
n -= 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
r.report('extend') do |n|
|
76
|
+
while n > 0
|
77
|
+
MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
|
78
|
+
d_obj = obj.extend(TopicDecorator)
|
79
|
+
d_obj.title_bang
|
80
|
+
d_obj.id
|
81
|
+
end
|
82
|
+
n -= 1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
r.report('draper') do |n|
|
86
|
+
while n > 0
|
87
|
+
MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
|
88
|
+
d_obj = TopicDraper.new(obj)
|
89
|
+
d_obj.title_bang
|
90
|
+
d_obj.id
|
91
|
+
end
|
92
|
+
n -= 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
r.report('simple_delegator') do |n|
|
96
|
+
while n > 0
|
97
|
+
MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
|
98
|
+
d_obj = TopicSimpleDelegator.new(obj)
|
99
|
+
d_obj.title_bang
|
100
|
+
d_obj.id
|
101
|
+
end
|
102
|
+
n -= 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
r.report('query') do |n|
|
106
|
+
while n > 0
|
107
|
+
MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
|
108
|
+
obj.title + '!!!'
|
109
|
+
obj.id
|
110
|
+
end
|
111
|
+
n -= 1
|
112
|
+
end
|
113
|
+
end
|
114
|
+
r.report('ar model') do |n|
|
115
|
+
while n > 0
|
116
|
+
TopicArModel.limit(1000).order(:id).select(:id, :title).each do |obj|
|
117
|
+
obj.title_bang
|
118
|
+
obj.id
|
119
|
+
end
|
120
|
+
n -= 1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
r.report('sequel model') do |n|
|
124
|
+
while n > 0
|
125
|
+
TopicDecoratorSequel.limit(1000).order(:id).select(:id, :title).each do |obj|
|
126
|
+
obj.title_bang
|
127
|
+
obj.id
|
128
|
+
end
|
129
|
+
n -= 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
r.compare!
|
134
|
+
end
|
135
|
+
|
136
|
+
# Comparison:
|
137
|
+
# query: 1102.9 i/s
|
138
|
+
# query_decorator: 1089.0 i/s - same-ish: difference falls within error
|
139
|
+
# sequel model: 860.2 i/s - 1.28x (± 0.00) slower
|
140
|
+
# simple_delegator: 679.8 i/s - 1.62x (± 0.00) slower
|
141
|
+
# extend: 678.1 i/s - 1.63x (± 0.00) slower
|
142
|
+
# draper: 587.2 i/s - 1.88x (± 0.00) slower
|
143
|
+
# ar model: 172.5 i/s - 6.39x (± 0.00) slower
|