6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00
firebird-qa/tests/bugs/core_5489_test.py

120 lines
3.3 KiB
Python

#coding:utf-8
"""
ID: issue-5759
ISSUE: 5759
TITLE: Bad performance for NULLs filtering inside a navigational index scan
DESCRIPTION:
See prototype and explanations for this test in CORE_5435.fbt
Confirmed improvement:
3.0.2.32643, 4.0.0.563:
**********
PLAN (TEST ORDER TEST_F01_ID)
1 records fetched
1143 ms, 2375 read(s), 602376 fetch(es) ---------------- poor :(
Table Natural Index
****************************************************
TEST 300000
3.0.2.32708, 4.0.0.572:
**********
PLAN (TEST ORDER TEST_F01_ID)
0 ms, 22 read(s), 63 fetch(es) --------------------------- cool :)
Table Natural Index
****************************************************
TEST 20
JIRA: CORE-5489
FBTEST: bugs.core_5489
NOTES:
[25.11.2023] pzotov
Writing code requires more care since 6.0.0.150: ISQL does not allow specifying duplicate delimiters without any statements between them (two semicolon, two carets etc).
"""
import pytest
from firebird.qa import *
db = db_factory(page_size=8192)
act = python_act('db')
FETCHES_THRESHOLD = 80
init_sql = """
recreate table test
(
id int not null,
f01 int,
f02 int
);
set term ^;
create or alter procedure sp_add_init_data(a_rows_to_add int)
as
declare n int;
declare i int = 0;
begin
n = a_rows_to_add;
while (i < n) do
begin
insert into test(id, f01, f02) values(:i, nullif(mod(:i, :n/20), 0), iif(mod(:i,3)<2, 0, 1))
returning :i+1 into i;
end
end
^
set term ;^
commit;
execute procedure sp_add_init_data(300000);
commit;
create index test_f01_id on test(f01, id);
create index test_f02_only on test(f02);
commit;
"""
test_script = """
set list on;
select count(*) cnt_check
from (
select *
from test
where f01 -- ###################################################################
IS NULL -- <<< ::: NB ::: we check here 'f01 is NULL', exactly as ticket says.
and f02=0 -- ###################################################################
order by f01, id
) ;
"""
trace = ['time_threshold = 0',
'log_statement_finish = true',
'print_plan = true',
'print_perf = true',
'log_initfini = false',
]
@pytest.mark.version('>=3.0.2')
def test_1(act: Action):
act.isql(switches=[], input=init_sql, combine_output = True)
assert act.clean_stdout == ''
with act.trace(db_events=trace):
act.reset()
act.isql(switches=[], input=test_script, combine_output = True)
# Process trace
run_with_plan = ''
num_of_fetches = 99999999
for line in act.trace_log:
if line.lower().startswith('plan ('):
run_with_plan = line.strip().upper()
elif 'fetch(es)' in line:
words = line.split()
for k in range(len(words)):
if words[k].startswith('fetch'):
num_of_fetches = int(words[k-1])
# Check
assert run_with_plan == 'PLAN (TEST ORDER TEST_F01_ID)'
assert num_of_fetches < FETCHES_THRESHOLD