OR'ed optimization in 3.0 is ineffective when `WHERE` clause contains two
expression and they do NOT match order of SP input arguments
--------------------------------------------------------------------------------------------------------------------------------------
Key: CORE-4537
URL: http://tracker.firebirdsql.org/browse/CORE-4537
Project: Firebird Core
Issue Type: Bug
Affects Versions: 3.0 Alpha 2
Reporter: Pavel Zotov
DDL:
####
create or alter procedure null_arg_force_idx_usage as begin end;
create or alter procedure null_arg_optimization_test_01 as begin end;
create or alter procedure null_arg_optimization_test_02 as begin end;
recreate table tmp(id int, doc_id int, qty int);
commit;
set term ^;
execute block as
declare i int = 0;
declare n int = 1000000;
begin
while(i<n) do insert into tmp(id, doc_id, qty) values(:i, rand()*100, 1)
returning :i+1 into i;
end
^ set term ;^
commit;
commit;
create unique index tmp_id_unq on tmp(id);
create index tmp_doc_id on tmp(doc_id);
commit;
set term ^;
create or alter procedure null_arg_force_idx_usage(
a_doc_list_id bigint default null
,a_doc_data_id bigint default null
)
returns(
dd_first_id int,
dd_first_qty numeric(12,2)
)
as
begin
select d.id, d.qty
from tmp d
where
d.id between coalesce( :a_doc_data_id, -2147483648) and coalesce(
:a_doc_data_id, 2147483647)
and
d.doc_id between coalesce( :a_doc_list_id, -2147483648) and
coalesce( :a_doc_list_id, 2147483647)
rows 1
into dd_first_id, dd_first_qty;
suspend;
end
^
create or alter procedure null_arg_optimization_test_01(
a_doc_list_id bigint default null
,a_doc_data_id bigint default null
)
returns(
dd_first_id int,
dd_first_qty numeric(12,2)
)
as
begin
select d.id, d.qty
from tmp d
where -- OR'ed optimization, 3.0 only
(d.doc_id = :a_doc_list_id or :a_doc_list_id is null)
and
(d.id = :a_doc_data_id or :a_doc_data_id is null)
rows 1
into dd_first_id, dd_first_qty;
suspend;
end
^
create or alter procedure null_arg_optimization_test_02(
a_doc_list_id bigint default null
,a_doc_data_id bigint default null
)
returns(
dd_first_id int,
dd_first_qty numeric(12,2)
)
as
begin
select d.id, d.qty
from tmp d
where -- OR'ed optimization, 3.0 only
(d.id = :a_doc_data_id or :a_doc_data_id is null)
and
(d.doc_id = :a_doc_list_id or :a_doc_list_id is null)
rows 1
into dd_first_id, dd_first_qty;
suspend;
end
^
set term ;^
commit;
So, the table tmp(id int, doc_id int, qty int) contains 10^6 rows and we have
three procedures which all take two arguments (both nullable) and returns first
record from TMP which match to one and/or two values of input args (or returns
first record if no arguments passed).
Procedure `null_arg_force_idx_usage` does not use so called "OR'ed
optimization" - it only forces FB to use indexes via BETWEEN + pair of literals
which covers all possible values of input args. It is provided here only for
comparison.
Procedures `null_arg_optimization_test_01` and `null_arg_optimization_test_02`
differs only in the order of expressions in WHERE-clause.
The following samples shows statistics of these SPs.
1.1 select * from null_arg_force_idx_usage(null, null) ==> IR = 1, NIR = 0;
174 ms, 1331 fetch(es)
1.2 select * from null_arg_optimization_test_01(null, null) ==> IR = 0, NIR =
1; 0 ms, 6 fetch(es) -- ok, but why NATURAL scan here ?
1.3 select * from null_arg_optimization_test_02(null, null) ==> IR = 0, NIR =
1; 0 ms, 6 fetch(es) -- the same as 1.2
2.1 select * from null_arg_force_idx_usage(1) ==> IR = 1, NIR = 0; 23 ms, 738
fetch(es)
2.2 select * from null_arg_optimization_test_01(1) ==> IR = 1, NIR = 0; 0 ms,
11 fetch(es) -- again: why NATURAL scan here ?
2.3 select * from null_arg_optimization_test_02(1) ==> IR = 0, NIR = 145; 0 ms,
296 fetch(es) -- the same as 2.2
3.1 select * from null_arg_force_idx_usage(-1); ==> no statistics, 21 ms, 730
fetch(es)
3.2 select * from null_arg_optimization_test_01(-1); ==> no statistics, 0 ms, 3
fetch(es)
3.3 select * from null_arg_optimization_test_02(-1); ==> IR = 0, NIR =
1'000'000 (!), 938 ms, 2014194 fetch(es) -- quite ineffective
4.1 select * from null_arg_force_idx_usage(null,1); ==> IR=1; 14 ms, 607
fetch(es)
4.2 select * from null_arg_optimization_test_01(null,1); ==> IR = 0, NIR=2; 0
ms, 8 fetch(es) -- why TWO naturals here ?
4.3 select * from null_arg_optimization_test_02(null,1); ==> IR=0, NIR=1
5.1 select * from null_arg_force_idx_usage(null,-1); ==> no statistics; 0 ms, 3
fetch(es)
5.2 select * from null_arg_optimization_test_01(null,-1); ==> IR=0,
NIR=1'000'000(!); 938 ms, 2014194 fetch(es) -- quite ineffective
5.3 select * from null_arg_optimization_test_02(null,-1); ==> no statistics; 0
ms, 3 fetch(es)
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://tracker.firebirdsql.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
------------------------------------------------------------------------------
Slashdot TV.
Video for Nerds. Stuff that matters.
http://tv.slashdot.org/
Firebird-Devel mailing list, web interface at
https://lists.sourceforge.net/lists/listinfo/firebird-devel