Skip to content

Commit 4ea6e54

Browse files
MDEV-41252: partial join cost Assertion failure in recompute_join_cost_with_limit()
recompute_join_cost_with_limit() computes the cost of the first table's partial join as best_read*fraction - pos->read_time*fraction. When the two costs are nearly equal and large (e.g. with a huge optimizer_scan_setup_cost, or when fraction is close to 1), the two products are rounded independently. The difference can then be a small negative number whose magnitude exceeds the absolute DBL_EPSILON tolerance used by the debug assertion, even though it is only a floating-point rounding artifact. Fix: scale the assertion tolerance with the magnitude of the operands (DBL_EPSILON * pos->read_time * fraction). Negative values are still clamped to 0.0 as before. Add test cases to optimizer_crash.test, one with a very large optimizer_scan_setup_cost and optimizer_join_limit_pref_ratio=1, and one with a large LIMIT on a 30000-row table.
1 parent 2340857 commit 4ea6e54

3 files changed

Lines changed: 75 additions & 1 deletion

File tree

‎mysql-test/main/order_by_limit_join.result‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,4 +684,39 @@ SELECT * FROM t1 ORDER BY c1 LIMIT 1;
684684
c1
685685
1
686686
DROP TABLE t1;
687+
#
688+
# MDEV-41252: Assertion partial_join_cost >= -2.2204460492503131e-16
689+
# when optimizer_scan_setup_cost=100000000, and
690+
# optimizer_join_limit_pref_ratio=1
691+
#
692+
CREATE TABLE t (c INT NOT NULL UNIQUE) ENGINE=InnoDB;
693+
INSERT INTO t VALUES (0),(1),(2),(3),(4),(5);
694+
ANALYZE TABLE t;
695+
Table Op Msg_type Msg_text
696+
test.t analyze status Engine-independent statistics collected
697+
test.t analyze status OK
698+
SET optimizer_scan_setup_cost=100000000;
699+
SET optimizer_join_limit_pref_ratio=1;
700+
EXPLAIN SELECT c FROM t ORDER BY c LIMIT 1;
701+
id select_type table type possible_keys key key_len ref rows Extra
702+
1 SIMPLE t index NULL c 4 NULL 1
703+
SET optimizer_join_limit_pref_ratio= DEFAULT;
704+
SET optimizer_scan_setup_cost= DEFAULT;
705+
DROP TABLE t;
706+
# another variant, with only optimizer_join_limit_pref_ratio=1
707+
CREATE TABLE t (c INT NOT NULL UNIQUE) ENGINE=InnoDB;
708+
INSERT INTO t SELECT seq FROM seq_1_to_30000;
709+
ANALYZE TABLE t;
710+
Table Op Msg_type Msg_text
711+
test.t analyze status Engine-independent statistics collected
712+
test.t analyze status OK
713+
SET optimizer_join_limit_pref_ratio=1;
714+
EXPLAIN SELECT c FROM t ORDER BY c LIMIT 28000;
715+
id select_type table type possible_keys key key_len ref rows Extra
716+
1 SIMPLE t index NULL c 4 NULL 28000
717+
SET optimizer_join_limit_pref_ratio= DEFAULT;
718+
DROP TABLE t;
719+
#
720+
# End of 11.4 tests
721+
#
687722
set optimizer_join_limit_pref_ratio=default;

‎mysql-test/main/order_by_limit_join.test‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,41 @@ INSERT INTO t1 VALUES (1),(2);
344344
SELECT * FROM t1 ORDER BY c1 LIMIT 1;
345345
DROP TABLE t1;
346346

347+
--echo #
348+
--echo # MDEV-41252: Assertion partial_join_cost >= -2.2204460492503131e-16
349+
--echo # when optimizer_scan_setup_cost=100000000, and
350+
--echo # optimizer_join_limit_pref_ratio=1
351+
--echo #
352+
CREATE TABLE t (c INT NOT NULL UNIQUE) ENGINE=InnoDB;
353+
INSERT INTO t VALUES (0),(1),(2),(3),(4),(5);
354+
ANALYZE TABLE t;
355+
356+
SET optimizer_scan_setup_cost=100000000;
357+
SET optimizer_join_limit_pref_ratio=1;
358+
359+
EXPLAIN SELECT c FROM t ORDER BY c LIMIT 1;
360+
361+
SET optimizer_join_limit_pref_ratio= DEFAULT;
362+
SET optimizer_scan_setup_cost= DEFAULT;
363+
364+
DROP TABLE t;
365+
366+
--echo # another variant, with only optimizer_join_limit_pref_ratio=1
367+
368+
CREATE TABLE t (c INT NOT NULL UNIQUE) ENGINE=InnoDB;
369+
INSERT INTO t SELECT seq FROM seq_1_to_30000;
370+
ANALYZE TABLE t;
371+
372+
SET optimizer_join_limit_pref_ratio=1;
373+
374+
EXPLAIN SELECT c FROM t ORDER BY c LIMIT 28000;
375+
376+
SET optimizer_join_limit_pref_ratio= DEFAULT;
377+
378+
DROP TABLE t;
379+
380+
--echo #
381+
--echo # End of 11.4 tests
382+
--echo #
383+
347384
set optimizer_join_limit_pref_ratio=default;

‎sql/sql_select.cc‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12005,9 +12005,11 @@ double recompute_join_cost_with_limit(const JOIN *join, bool skip_sorting,
1200512005
/*
1200612006
Handle possible rounding errors when
1200712007
partial_join_cost==pos->read_time*fraction:
12008+
The rounding error grows with the cost, so the tolerance is taken
12009+
in proportion to it.
1200812010
Catch larger negatives, proceed with non-negative cost.
1200912011
*/
12010-
DBUG_ASSERT(partial_join_cost >= -DBL_EPSILON);
12012+
DBUG_ASSERT(partial_join_cost >= -DBL_EPSILON*pos->read_time*fraction);
1201112013
if (partial_join_cost < 0.0)
1201212014
partial_join_cost= 0.0;
1201312015

0 commit comments

Comments
 (0)