mini_sql 1.0.1 → 1.1.0
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 +1 -1
- data/CHANGELOG +4 -0
- data/README.md +36 -0
- 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 +17 -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 +61 -30
- data/lib/mini_sql/inline_param_encoder.rb +4 -3
- data/lib/mini_sql/mysql/connection.rb +6 -0
- data/lib/mini_sql/mysql/deserializer_cache.rb +3 -3
- 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 +6 -0
- data/lib/mini_sql/postgres/deserializer_cache.rb +5 -5
- 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/deserializer_cache.rb +3 -3
- data/lib/mini_sql/result.rb +10 -0
- data/lib/mini_sql/serializer.rb +29 -15
- data/lib/mini_sql/sqlite/connection.rb +9 -1
- data/lib/mini_sql/sqlite/deserializer_cache.rb +3 -3
- 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
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ce3e8b5fee8c39506de8439826252434ddce6249287bb3a74c411a41a5e5726
|
4
|
+
data.tar.gz: cbab24b31bbf55e39cb824224e694e117b42c30e20189f64ffd2163cab3e12b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f01c57922c3ead43474e02585c365b914880ef6924f7acce041e2ee0e984217eadf4aa25f81a0c0c79ee2b9de7235311a2d7155be1a512f2f545d6fbe81ab6e5
|
7
|
+
data.tar.gz: 47de031da6a0efaeded3981fa2eadefd4a5261cbef73f2fcfb998dd1e671c6c19015a2b97ef70d7311d847558934f8ec8fe6678f2d665cc8ad6dffe6d10a879d
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -187,6 +187,21 @@ Note, in Postgres streaming is going to be slower than non-streaming options due
|
|
187
187
|
|
188
188
|
Streaming support is only implemented in the postgres backend at the moment, PRs welcome to add to other backends.
|
189
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
|
+
|
190
205
|
## I want more features!
|
191
206
|
|
192
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.
|
@@ -194,6 +209,27 @@ MiniSql is designed to be very minimal. Even though the query builder and type m
|
|
194
209
|
## Development
|
195
210
|
|
196
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.
|
197
233
|
|
198
234
|
## Contributing
|
199
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
|
@@ -0,0 +1,80 @@
|
|
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 'draper'
|
13
|
+
gem 'pry'
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'active_record'
|
17
|
+
require 'benchmark/ips'
|
18
|
+
require 'mini_sql'
|
19
|
+
|
20
|
+
require '../mini_sql/bench/shared/generate_data'
|
21
|
+
|
22
|
+
ar_connection, conn_config = GenerateData.new(count_records: 1_000).call
|
23
|
+
MINI_SQL = MiniSql::Connection.get(ar_connection.raw_connection)
|
24
|
+
|
25
|
+
|
26
|
+
Benchmark.ips do |r|
|
27
|
+
r.report('query_hash') do |n|
|
28
|
+
while n > 0
|
29
|
+
MINI_SQL.query_hash('select id, title from topics order by id limit 1000').each do |hash|
|
30
|
+
[hash['id'], hash['title']]
|
31
|
+
end
|
32
|
+
n -= 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
r.report('query_array') do |n|
|
36
|
+
while n > 0
|
37
|
+
MINI_SQL.query_array('select id, title from topics order by id limit 1000').each do |id, title|
|
38
|
+
[id, title]
|
39
|
+
end
|
40
|
+
n -= 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
r.report('query') do |n|
|
44
|
+
while n > 0
|
45
|
+
MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
|
46
|
+
[obj.id, obj.title]
|
47
|
+
end
|
48
|
+
n -= 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
r.compare!
|
53
|
+
end
|
54
|
+
|
55
|
+
# Comparison:
|
56
|
+
# query_array: 1663.3 i/s
|
57
|
+
# query: 1254.5 i/s - 1.33x (± 0.00) slower
|
58
|
+
# query_hash: 1095.4 i/s - 1.52x (± 0.00) slower
|
59
|
+
|
60
|
+
|
61
|
+
Benchmark.ips do |r|
|
62
|
+
r.report('query_single') do |n|
|
63
|
+
while n > 0
|
64
|
+
MINI_SQL.query_single('select id from topics order by id limit 1000')
|
65
|
+
n -= 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
r.report('query_array') do |n|
|
69
|
+
while n > 0
|
70
|
+
MINI_SQL.query_array('select id from topics order by id limit 1000').flatten
|
71
|
+
n -= 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
r.compare!
|
76
|
+
end
|
77
|
+
|
78
|
+
# Comparison:
|
79
|
+
# query_single: 2445.1 i/s
|
80
|
+
# query_array: 1681.1 i/s - 1.45x (± 0.00) slower
|
@@ -0,0 +1,59 @@
|
|
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
|
+
|
24
|
+
sql = <<~SQL
|
25
|
+
select users.first_name, count(distinct topics.id) topics_count
|
26
|
+
from topics
|
27
|
+
inner join users on user_id = users.id
|
28
|
+
inner join categories on category_id = categories.id
|
29
|
+
where users.id = ?
|
30
|
+
group by users.id
|
31
|
+
SQL
|
32
|
+
|
33
|
+
Benchmark.ips do |x|
|
34
|
+
x.report("ps") do |n|
|
35
|
+
while n > 0
|
36
|
+
MINI_SQL.prepared.query(sql, rand(100))
|
37
|
+
n -= 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
x.report("without ps") do |n|
|
41
|
+
while n > 0
|
42
|
+
MINI_SQL.query(sql, rand(100))
|
43
|
+
n -= 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
x.compare!
|
48
|
+
end
|
49
|
+
|
50
|
+
# Warming up --------------------------------------
|
51
|
+
# ps 1.008k i/100ms
|
52
|
+
# without ps 284.000 i/100ms
|
53
|
+
# Calculating -------------------------------------
|
54
|
+
# ps 10.287k (± 4.2%) i/s - 51.408k in 5.006807s
|
55
|
+
# without ps 2.970k (± 5.3%) i/s - 15.052k in 5.083272s
|
56
|
+
#
|
57
|
+
# Comparison:
|
58
|
+
# ps: 10287.2 i/s
|
59
|
+
# without ps: 2970.0 i/s - 3.46x (± 0.00) slower
|