Skip to content

Commit 3f38b47

Browse files
oleg-jukovecDifferentialOrange
authored andcommitted
select: don't replace EQ/REQ by GE/LE in planner with after
Before the patch we copy an original EQ/REQ condition to post-filter and change the original to GE/LE. The problem is that EQ/REQ can't be a stop condition. As a result EQ/REQ + after unexpectedly became a full scan. The patch removes this behavior, the query becomes more expected and in base executes as regular EQ/REQ. We had an idea to replace EQ with GE+LE. This would help to skip less tuples in the executor inside scroll_to_after_tuple. But unfortunately, due to a bug[1], this will break the current behavior. So we need to fix the bug first. In additional, the 'potentially long select'[2] warning is confused by the GE/LE in the query plan. This patch only changes the internal behavior and does not affect a client code. 1. #301 2. #277
1 parent 5f29872 commit 3f38b47

File tree

3 files changed

+51
-34
lines changed

3 files changed

+51
-34
lines changed

crud/compare/plan.lua

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -231,48 +231,33 @@ function plan.new(space, conditions, opts)
231231
return nil, err
232232
end
233233

234-
-- Since we use pagination we should continue iteration since after tuple.
235-
-- Such iterator could be run only with index:pairs(key(after_tuple), 'GT/LT').
236-
-- To preserve original condition we should manually inject it in `filter_conditions`
237-
-- See function `parse` in crud/select/filters.lua file for details.
238-
if scan_after_tuple ~= nil then
239-
if scan_iter == box.index.REQ or scan_iter == box.index.EQ then
240-
table.insert(conditions, conditions[scan_condition_num])
241-
end
242-
end
243-
234+
local is_equal_iter = scan_iter == box.index.EQ or scan_iter == box.index.REQ
244235
if opts.first ~= nil then
245236
total_tuples_count = math.abs(opts.first)
246237

247238
if opts.first < 0 then
248239
scan_iter = utils.invert_tarantool_iter(scan_iter)
249240

250-
-- scan condition becomes border consition
251-
scan_condition_num = nil
252-
253-
if scan_after_tuple ~= nil then
254-
if has_keydef then
255-
local key_def = keydef_lib.new(scan_index.parts)
256-
scan_value = key_def:extract_key(scan_after_tuple)
241+
-- it makes no sence for EQ/REQ
242+
if not is_equal_iter then
243+
-- scan condition becomes border condition
244+
scan_condition_num = nil
245+
246+
if scan_after_tuple ~= nil then
247+
-- after becomes a new scan value
248+
if has_keydef then
249+
local key_def = keydef_lib.new(scan_index.parts)
250+
scan_value = key_def:extract_key(scan_after_tuple)
251+
else
252+
scan_value = utils.extract_key(scan_after_tuple, scan_index.parts)
253+
end
257254
else
258-
scan_value = utils.extract_key(scan_after_tuple, scan_index.parts)
255+
scan_value = nil
259256
end
260-
else
261-
scan_value = nil
262257
end
263258
end
264259
end
265260

266-
-- Moreover, for correct pagination we change iterator
267-
-- to continue iterating in direct and reverse order.
268-
if scan_after_tuple ~= nil then
269-
if scan_iter == box.index.EQ then
270-
scan_iter = box.index.GE
271-
elseif scan_iter == box.index.REQ then
272-
scan_iter = box.index.LE
273-
end
274-
end
275-
276261
local sharding_key = nil
277262
if opts.bucket_id == nil then
278263
local sharding_index = opts.sharding_key_as_index_obj or primary_index

crud/select/executor.lua

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,41 @@ function executor.execute(space, index, filter_func, opts)
7979

8080
local value = opts.scan_value
8181
if opts.after_tuple ~= nil then
82-
local new_value = generate_value(opts.after_tuple, opts.scan_value, index.parts, opts.tarantool_iter)
83-
if new_value ~= nil then
84-
value = new_value
82+
local iter = opts.tarantool_iter
83+
if iter == box.index.EQ or iter == box.index.REQ then
84+
-- we need to make sure that the keys are equal
85+
-- the code is correct even if value is a partial key
86+
local parts = {}
87+
for i, _ in ipairs(value) do
88+
-- the code required for tarantool 1.10.6 at least
89+
table.insert(parts, index.parts[i])
90+
end
91+
92+
local is_eq = iter == box.index.EQ
93+
local is_after_bigger
94+
if has_keydef then
95+
local key_def = keydef_lib.new(parts)
96+
local cmp = key_def:compare_with_key(opts.after_tuple, value)
97+
is_after_bigger = (is_eq and cmp > 0) or (not is_eq and cmp < 0)
98+
else
99+
local comparator
100+
if is_eq then
101+
comparator = select_comparators.gen_func('<=', parts)
102+
else
103+
comparator = select_comparators.gen_func('>=', parts)
104+
end
105+
local after_key = utils.extract_key(opts.after_tuple, parts)
106+
is_after_bigger = not comparator(after_key, value)
107+
end
108+
if is_after_bigger then
109+
-- it makes no sence to continue
110+
return resp
111+
end
112+
else
113+
local new_value = generate_value(opts.after_tuple, value, index.parts, iter)
114+
if new_value ~= nil then
115+
value = new_value
116+
end
85117
end
86118
end
87119

test/unit/select_plan_test.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ g.test_first = function()
276276
t.assert_equals(plan.scan_value, {90}) -- after_tuple id
277277
t.assert_equals(plan.after_tuple, after_tuple)
278278
t.assert_equals(plan.scan_condition_num, 1)
279-
t.assert_equals(plan.tarantool_iter, box.index.GE) -- inverted iterator
279+
t.assert_equals(plan.tarantool_iter, box.index.EQ)
280280
t.assert_equals(plan.total_tuples_count, 10)
281281
t.assert_equals(plan.sharding_key, nil)
282282
t.assert_equals(plan.field_names, nil)

0 commit comments

Comments
 (0)