1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-31258 Assertion `cond_selectivity <= 1.000000001' upon range query

This was caused of two minor issues:
- get_quick_record_count() returned the number of rows for range with
  least cost, when it should have returned the minum number of rows
  for any range.
- When changing REF to RANGE, we also changed records_out, which
  should not be done (number of records in the result will not
  change).

The above change can cause a small change in row estimates where the
optimizer chooses a clustered key with more rows than a range one
secondary key (unlikely case).
This commit is contained in:
Monty
2023-05-27 12:18:49 +03:00
parent 368dd22a81
commit 209fed8eed
3 changed files with 98 additions and 7 deletions

View File

@ -3786,3 +3786,43 @@ DROP TABLE t1;
set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages= set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save; @innodb_stats_persistent_sample_pages_save;
#
# MDEV-31258 Assertion `cond_selectivity <= 1.000000001' upon range
# query
#
CREATE TABLE t1 (id int, a int, b char(3), PRIMARY KEY (id), KEY idx (a,b)) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(1,8,'UT'),(2,0,'NU'),(3,1,'SD'),(4,0,'QU'),(5,0,'FL'),(6,0,'ZR'),
(7,3,'LA'),(8,5,'NU'),(9,0,'NU'),(10,0,'SD'),(11,0,'NU'),(12,1,'SD'),
(13,0,'BD'),(14,0,'PA'),(15,0,'VT'),(16,4,'WA'),(17,0,'ME'),(18,6,'OH'),
(19,0,'ME'),(20,4,'NU'),(21,0,'SC'),(22,0,'GA'),(23,1,'CO'),(24,0,'IL'),
(25,0,'GA'),(26,0,'HI'),(27,0,'BU'),(28,0,'NU'),(29,7,'LA'),(30,0,'NU'),
(31,0,'JR'),(32,6,'BR'),(33,0,'NU'),(34,6,'CO'),(35,7,'NU'),(36,2,'LA'),
(37,0,'PR'),(38,1,'UT'),(39,2,'BR'),(40,1,'HI'),(41,0,'SD'),(42,0,'RI'),
(43,2,'LA'),(44,0,'TN'),(45,4,'HI'),(46,0,'VT'),(47,1,'NU'),(48,0,'SC'),
(49,0,'TX'),(50,8,'DC'),(51,4,'NU'),(52,0,'AL'),(53,0,'CO'),(54,9,'PR'),
(55,0,'AR'),(56,0,'SD'),(57,0,'RI'),(58,0,'XE'),(59,0,'NU'),(60,4,'EL'),
(61,2,'LA'),(62,5,'UT'),(63,3,'NU'),(64,0,'RI'),(65,1,'NU'),(66,0,'BR'),
(67,3,'WA'),(68,0,'TN'),(69,3,'HI'),(70,0,'OH'),(71,8,'GA'),(72,6,'AL'),
(73,6,'NU'),(74,1,'HI'),(75,5,'JR'),(76,3,'RI'),(77,0,'DC'),(78,0,'SC'),
(79,0,'CO'),(80,2,'BO'),(81,8,'XE'),(82,1,'NU'),(83,0,'SD'),(84,0,'PA'),
(85,5,'PA'),(86,0,'QU'),(87,0,'PA'),(88,0,'NU'),(89,0,'ND'),(90,0,'UT'),
(91,0,'NU'),(92,0,'NU'),(93,6,'ZR'),(94,0,'NU'),(95,2,'EL'),(96,0,'NU'),
(97,0,'RI'),(98,5,'DC'),(99,7,'JR'),(100,5,'CO'),(101,0,'UT'),(102,0,'QU'),
(103,0,'NU'),(104,0,'GA'),(105,7,'AK'),(106,0,'ZR'),(107,0,'YT'),(108,0,'MD'),
(109,0,'NU'),(110,1,'EL'),(111,0,'ME'),(112,0,'VT'),(113,2,'NU'),(114,0,'CO'),
(115,5,'TN'),(116,0,'OH'),(117,0,'GA'),(118,9,'GA'),(119,0,'CO'),(120,0,'AL'),
(121,0,'NU'),(122,2,'NE'),(123,2,'TX'),(124,3,'CO'),(125,0,'TN'),(126,0,'WA'),
(127,0,'NE'),(128,6,'TN'),(129,0,'BR'),(130,0,'ID'),(131,0,'NU'),(132,2,'EL'),
(133,0,'PR'),(134,0,'NU'),(135,1,'AZ'),(136,7,'EL'),(137,0,'TN'),(138,0,'PA'),
(139,5,'QU'),(140,0,'AR'),(141,0,'DC'),(142,2,'WA'),(143,7,'OH'),(144,2,'CO'),
(145,6,'NU'),(146,9,'FL'),(147,0,'HI'),(148,0,'WA'),(149,1,'BR'),(150,3,'QU');
SELECT id, MIN(id) FROM t1
WHERE (b > 'TX' OR b BETWEEN 'NE' AND 'SC') AND id IN (1,7,8) AND a = 5
GROUP BY id;
id MIN(id)
8 8
DROP TABLE t1;
#
# End of 11.0 tests
#

View File

@ -2563,3 +2563,45 @@ DROP TABLE t1;
set global innodb_stats_persistent= @innodb_stats_persistent_save; set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages= set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save; @innodb_stats_persistent_sample_pages_save;
--echo #
--echo # MDEV-31258 Assertion `cond_selectivity <= 1.000000001' upon range
--echo # query
--echo #
CREATE TABLE t1 (id int, a int, b char(3), PRIMARY KEY (id), KEY idx (a,b)) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(1,8,'UT'),(2,0,'NU'),(3,1,'SD'),(4,0,'QU'),(5,0,'FL'),(6,0,'ZR'),
(7,3,'LA'),(8,5,'NU'),(9,0,'NU'),(10,0,'SD'),(11,0,'NU'),(12,1,'SD'),
(13,0,'BD'),(14,0,'PA'),(15,0,'VT'),(16,4,'WA'),(17,0,'ME'),(18,6,'OH'),
(19,0,'ME'),(20,4,'NU'),(21,0,'SC'),(22,0,'GA'),(23,1,'CO'),(24,0,'IL'),
(25,0,'GA'),(26,0,'HI'),(27,0,'BU'),(28,0,'NU'),(29,7,'LA'),(30,0,'NU'),
(31,0,'JR'),(32,6,'BR'),(33,0,'NU'),(34,6,'CO'),(35,7,'NU'),(36,2,'LA'),
(37,0,'PR'),(38,1,'UT'),(39,2,'BR'),(40,1,'HI'),(41,0,'SD'),(42,0,'RI'),
(43,2,'LA'),(44,0,'TN'),(45,4,'HI'),(46,0,'VT'),(47,1,'NU'),(48,0,'SC'),
(49,0,'TX'),(50,8,'DC'),(51,4,'NU'),(52,0,'AL'),(53,0,'CO'),(54,9,'PR'),
(55,0,'AR'),(56,0,'SD'),(57,0,'RI'),(58,0,'XE'),(59,0,'NU'),(60,4,'EL'),
(61,2,'LA'),(62,5,'UT'),(63,3,'NU'),(64,0,'RI'),(65,1,'NU'),(66,0,'BR'),
(67,3,'WA'),(68,0,'TN'),(69,3,'HI'),(70,0,'OH'),(71,8,'GA'),(72,6,'AL'),
(73,6,'NU'),(74,1,'HI'),(75,5,'JR'),(76,3,'RI'),(77,0,'DC'),(78,0,'SC'),
(79,0,'CO'),(80,2,'BO'),(81,8,'XE'),(82,1,'NU'),(83,0,'SD'),(84,0,'PA'),
(85,5,'PA'),(86,0,'QU'),(87,0,'PA'),(88,0,'NU'),(89,0,'ND'),(90,0,'UT'),
(91,0,'NU'),(92,0,'NU'),(93,6,'ZR'),(94,0,'NU'),(95,2,'EL'),(96,0,'NU'),
(97,0,'RI'),(98,5,'DC'),(99,7,'JR'),(100,5,'CO'),(101,0,'UT'),(102,0,'QU'),
(103,0,'NU'),(104,0,'GA'),(105,7,'AK'),(106,0,'ZR'),(107,0,'YT'),(108,0,'MD'),
(109,0,'NU'),(110,1,'EL'),(111,0,'ME'),(112,0,'VT'),(113,2,'NU'),(114,0,'CO'),
(115,5,'TN'),(116,0,'OH'),(117,0,'GA'),(118,9,'GA'),(119,0,'CO'),(120,0,'AL'),
(121,0,'NU'),(122,2,'NE'),(123,2,'TX'),(124,3,'CO'),(125,0,'TN'),(126,0,'WA'),
(127,0,'NE'),(128,6,'TN'),(129,0,'BR'),(130,0,'ID'),(131,0,'NU'),(132,2,'EL'),
(133,0,'PR'),(134,0,'NU'),(135,1,'AZ'),(136,7,'EL'),(137,0,'TN'),(138,0,'PA'),
(139,5,'QU'),(140,0,'AR'),(141,0,'DC'),(142,2,'WA'),(143,7,'OH'),(144,2,'CO'),
(145,6,'NU'),(146,9,'FL'),(147,0,'HI'),(148,0,'WA'),(149,1,'BR'),(150,3,'QU');
SELECT id, MIN(id) FROM t1
WHERE (b > 'TX' OR b BETWEEN 'NE' AND 'SC') AND id IN (1,7,8) AND a = 5
GROUP BY id;
DROP TABLE t1;
--echo #
--echo # End of 11.0 tests
--echo #

View File

@ -5206,7 +5206,17 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
TRUE, /* remove_where_parts*/ TRUE, /* remove_where_parts*/
FALSE)) == FALSE)) ==
1)) 1))
DBUG_RETURN(select->quick->records); {
/*
opt_range_condition_rows was updated in test_quick_select to be
the smallest number of rows in any range.
select->quick->records is the number of rows in range with
smallest cost.
*/
DBUG_ASSERT(select->quick->records >=
table->opt_range_condition_rows);
DBUG_RETURN(table->opt_range_condition_rows);
}
if (unlikely(error == -1)) if (unlikely(error == -1))
{ {
table->reginfo.impossible_range=1; table->reginfo.impossible_range=1;
@ -9268,11 +9278,11 @@ best_access_path(JOIN *join,
TABLE::OPT_RANGE *range= &table->opt_range[key_no]; TABLE::OPT_RANGE *range= &table->opt_range[key_no];
/* /*
Ensure that 'range' and 's' are comming from the same source Ensure that 'range' and 's' are coming from the same source
The complex 'double' comparison is there because floating point The complex 'double' comparison is there because floating point
registers complications when costs are calculated. registers complications when costs are calculated.
*/ */
DBUG_ASSERT(range->rows == s->found_records); DBUG_ASSERT(range->rows >= s->found_records);
DBUG_ASSERT((range->cost.total_cost() == 0.0 && DBUG_ASSERT((range->cost.total_cost() == 0.0 &&
s->quick->read_time == 0.0) || s->quick->read_time == 0.0) ||
(range->cost.total_cost() / s->quick->read_time <= 1.0000001 && (range->cost.total_cost() / s->quick->read_time <= 1.0000001 &&
@ -13610,9 +13620,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tab->use_quick=1; tab->use_quick=1;
tab->ref.key= -1; tab->ref.key= -1;
tab->ref.key_parts=0; // Don't use ref key. tab->ref.key_parts=0; // Don't use ref key.
join->best_positions[i].records_read= join->best_positions[i].records_read= rows2double(tab->quick->records);
join->best_positions[i].records_out=
rows2double(tab->quick->records);
/* /*
We will use join cache here : prevent sorting of the first We will use join cache here : prevent sorting of the first
table only and sort at the end. table only and sort at the end.
@ -31314,6 +31323,7 @@ static bool get_range_limit_read_cost(const POSITION *pos,
if (pos) if (pos)
{ {
double cond_selectivity;
/* /*
Take into count table selectivity as the number of accepted Take into count table selectivity as the number of accepted
rows for this table will be 'records_out'. rows for this table will be 'records_out'.
@ -31325,7 +31335,6 @@ static bool get_range_limit_read_cost(const POSITION *pos,
account that using key2 we have to examine much fewer rows. account that using key2 we have to examine much fewer rows.
*/ */
best_rows= pos->records_out; // Best rows with any key/keys best_rows= pos->records_out; // Best rows with any key/keys
double cond_selectivity;
/* /*
We assign "double range_rows" from integer #rows a few lines above We assign "double range_rows" from integer #rows a few lines above
so comparison with 0.0 makes sense so comparison with 0.0 makes sense