Skip to content

Commit 2407329

Browse files
committed
Optimize Dataset#all and #with_sql_all
This allocates an array with the expected size up front, and avoids a C -> Ruby call per row. Instead of checking whether Sequel::Model::ClassMethods is already defined during load, check it inside optimize_model_load. This allows for optimization in the case where sequel/core is required, then the database is setup, and then sequel is required. However, this approach also results in unnecessary slowdown of Dataset#each when models are not used. An alternative approach will be used in a future commit to avoid this.
1 parent 96fc41e commit 2407329

File tree

3 files changed

+78
-19
lines changed

3 files changed

+78
-19
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
=== master
22

3+
* Optimize Dataset#all and #with_sql_all (jeremyevans)
4+
35
* Fix runtime warnings when using Dataset#as_hash and #to_hash_groups with invalid columns (jeremyevans)
46

57
* Fix Dataset#map return value when the null_dataset extension is used (jeremyevans)

ext/sequel_pg/sequel_pg.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@
7777
#define SPG_YIELD_COLUMNS_SET 19
7878
#define SPG_YIELD_FIRST_SET 20
7979
#define SPG_YIELD_ARRAY_SET 21
80+
#define SPG_YIELD_ALL 22
81+
#define SPG_YIELD_ALL_MODEL 23
8082

8183
/* External functions defined by ruby-pg */
8284
PGconn* pg_get_pgconn(VALUE);
@@ -114,6 +116,8 @@ static VALUE spg_sym_array_set;
114116
static VALUE spg_sym_hash;
115117
static VALUE spg_sym_hash_groups;
116118
static VALUE spg_sym_model;
119+
static VALUE spg_sym_all;
120+
static VALUE spg_sym_all_model;
117121
static VALUE spg_sym__sequel_pg_type;
118122
static VALUE spg_sym__sequel_pg_value;
119123

@@ -1470,6 +1474,10 @@ static VALUE spg_yield_hash_rows_internal(VALUE self, PGresult *res, int enc_ind
14701474
}
14711475
} else if (pg_type == spg_sym_model && rb_type(pg_value) == T_CLASS) {
14721476
type = SPG_YIELD_MODEL;
1477+
} else if (pg_type == spg_sym_all_model && rb_type(pg_value) == T_CLASS) {
1478+
type = SPG_YIELD_ALL_MODEL;
1479+
} else if (pg_type == spg_sym_all) {
1480+
type = SPG_YIELD_ALL;
14731481
}
14741482
}
14751483
}
@@ -1760,6 +1768,35 @@ static VALUE spg_yield_hash_rows_internal(VALUE self, PGresult *res, int enc_ind
17601768
rb_yield(pg_type);
17611769
}
17621770
break;
1771+
case SPG_YIELD_ALL_MODEL:
1772+
{
1773+
VALUE ary = rb_ary_new2(ntuples);
1774+
VALUE obj;
1775+
for(i=0; i<ntuples; i++) {
1776+
h = rb_hash_new_capa(nfields);
1777+
for(j=0; j<nfields; j++) {
1778+
rb_hash_aset(h, colsyms[j], spg__col_value(self, res, i, j, colconvert, enc_index));
1779+
}
1780+
obj = rb_obj_alloc(pg_value);
1781+
rb_ivar_set(obj, spg_id_values, h);
1782+
rb_ary_store(ary, i, obj);
1783+
}
1784+
rb_yield(ary);
1785+
}
1786+
break;
1787+
case SPG_YIELD_ALL:
1788+
{
1789+
VALUE ary = rb_ary_new2(ntuples);
1790+
for(i=0; i<ntuples; i++) {
1791+
h = rb_hash_new_capa(nfields);
1792+
for(j=0; j<nfields; j++) {
1793+
rb_hash_aset(h, colsyms[j], spg__col_value(self, res, i, j, colconvert, enc_index));
1794+
}
1795+
rb_ary_store(ary, i, h);
1796+
}
1797+
rb_yield(ary);
1798+
}
1799+
break;
17631800
}
17641801
return self;
17651802
}
@@ -2083,6 +2120,8 @@ void Init_sequel_pg(void) {
20832120
spg_sym_hash = ID2SYM(rb_intern("hash"));
20842121
spg_sym_hash_groups = ID2SYM(rb_intern("hash_groups"));
20852122
spg_sym_model = ID2SYM(rb_intern("model"));
2123+
spg_sym_all = ID2SYM(rb_intern("all"));
2124+
spg_sym_all_model = ID2SYM(rb_intern("all_model"));
20862125
spg_sym__sequel_pg_type = ID2SYM(rb_intern("_sequel_pg_type"));
20872126
spg_sym__sequel_pg_value = ID2SYM(rb_intern("_sequel_pg_value"));
20882127

lib/sequel_pg/sequel_pg.rb

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,35 @@ def to_hash_groups(key_column, value_column = nil, opts = Sequel::OPTS)
9191
end
9292
end
9393

94-
if defined?(Sequel::Model::ClassMethods)
95-
# If model loads are being optimized and this is a model load, use the optimized
96-
# version.
97-
def each(&block)
98-
if optimize_model_load?
99-
clone(:_sequel_pg_type=>:model, :_sequel_pg_value=>row_proc).fetch_rows(sql, &block)
100-
else
101-
super
94+
# If model loads are being optimized and this is a model load, use the optimized
95+
# version.
96+
def each(&block)
97+
if optimize_model_load?
98+
clone(:_sequel_pg_type=>:model, :_sequel_pg_value=>row_proc).fetch_rows(sql, &block)
99+
else
100+
super
101+
end
102+
end
103+
104+
# Delegate to with_sql_all using the default SQL
105+
def all(&block)
106+
with_sql_all(sql, &block)
107+
end
108+
109+
# Always use optimized version
110+
def with_sql_all(sql, &block)
111+
return super if opts[:graph] || opts[:cursor]
112+
type = optimize_model_load? ? :all_model : :all
113+
rp = row_proc
114+
clone(:_sequel_pg_type=>type, :_sequel_pg_value=>rp).fetch_rows(sql) do |array|
115+
if rp && type == :all
116+
array.map!{|h| rp.call(h)}
102117
end
118+
post_load(array)
119+
array.each(&block) if block
120+
return array
103121
end
122+
[]
104123
end
105124

106125
protected
@@ -153,18 +172,17 @@ def _select_set_single
153172

154173
private
155174

156-
if defined?(Sequel::Model::ClassMethods)
157-
# The model load can only be optimized if it's for a model and it's not a graphed dataset
158-
# or using a cursor.
159-
def optimize_model_load?
175+
# The model load can only be optimized if it's for a model and it's not a graphed dataset
176+
# or using a cursor.
177+
def optimize_model_load?
178+
defined?(Sequel::Model::ClassMethods) &&
160179
(rp = row_proc) &&
161-
rp.is_a?(Class) &&
162-
rp < Sequel::Model &&
163-
rp.method(:call).owner == Sequel::Model::ClassMethods &&
164-
opts[:optimize_model_load] != false &&
165-
!opts[:use_cursor] &&
166-
!opts[:graph]
167-
end
180+
rp.is_a?(Class) &&
181+
rp < Sequel::Model &&
182+
rp.method(:call).owner == Sequel::Model::ClassMethods &&
183+
opts[:optimize_model_load] != false &&
184+
!opts[:use_cursor] &&
185+
!opts[:graph]
168186
end
169187
end
170188

0 commit comments

Comments
 (0)