1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Added EQ_REF chaining to the greedy_optimizer

MDEV-28073 Slow query performance in MariaDB when using many table

The idea is to prefer and chain EQ_REF tables (tables that uses an
unique key to find a row) when searching for the best table combination.
This significantly reduces row combinations that has to be examined.
This is optimization is enabled when setting optimizer_prune_level=2
(which is now default).

Implementation:
- optimizer_prune_level has a new level, 2, which enables EQ_REF
  optimization in addition to the pruning done by level 1.
  Level 2 is now default.
- Added JOIN::eq_ref_tables that contains bits of tables that could use
  potentially use EQ_REF access in the query.  This is calculated
  in sort_and_filter_keyuse()

Under optimizer_prune_level=2:
- When the greedy_optimizer notices that the preceding table was an
  EQ_REF table, it tries to add an EQ_REF table next. If an EQ_REF
  table exists, only this one will be considered at this level.
  We also collect all EQ_REF tables chained by the next levels and these
  are ignored on the starting level as we have already examined these.
  If no EQ_REF table exists, we continue as normal.

This optimization speeds up the greedy_optimizer combination test with
~25%

Other things:
- I ported the changes in MySQL 5.7 to greedy_optimizer.test to MariaDB
  to be able to ensure we can handle all cases that MySQL can do.
- I have run all tests with --mysqld=--optimizer_prune_level=1 to verify that
  there where no test changes.
This commit is contained in:
Monty
2022-06-02 19:47:23 +03:00
committed by Oleg Smirnov
parent 6e7376eb59
commit 515b9ad05a
33 changed files with 6187 additions and 2582 deletions

View File

@@ -0,0 +1,57 @@
# include/check_qep.inc
#
# SUMMARY
#
# Designed to be used together with include/expect_qep.inc
#
# $query should be assigned a select statement using
# straight_join to force the tables to be joined in most
# optimal order.
#
# expect_qep.inc will then store the estimated 'Last_query_cost'
# and total # 'Handler_read%' for this straight_joined query.
#
# We should then assign a non-straight_join'ed version of
# the same query to $query and execute it using
# 'include/check_qep.inc'. Its estimated cost and
# #handler_reads will then be verified against the
# previous straight_joined query.
#
# USAGE
#
# let $query= <select straight_join optimal statement>;
# --source include/expect_qep.inc
# let $query= <select statement>;
# --source include/check_qep.inc
#
# EXAMPLE
# t/greedy_optimizer.test
#
flush status;
eval EXPLAIN $query;
eval $query;
let $cost=
query_get_value(SHOW STATUS LIKE 'Last_query_cost', Value, 1);
--disable_warnings
let $reads=
`select sum(variable_value)
from information_schema.session_status
where VARIABLE_NAME like 'Handler_read%'`;
--enable_warnings
#echo Cost: $cost, Handler_reads: $reads;
if ($cost != $best_cost)
{ echo ### FAILED: Query_cost: $cost, expected: $best_cost ###;
}
# Difference in handler reads are ok as tables in MariaDB are sorted according
# to order in the query and the tables in greedy_optimizer.inc has reference to
# rows that does not exists, so different table orders will do different
# number of reads
if ($reads != $best_reads)
{ echo ### NOTE: Handler_reads: $reads, expected: $best_reads ###;
}

View File

@@ -0,0 +1,30 @@
# include/execute_with_statistics.inc
#
# SUMMARY
#
# Explain and execute the select statment in $query.
# Then report 'Last_query_cost' estimate from the query
# optimizer and total number of 'Handler_read%' when the
# query was executed.
# Intended usage is to verify that there are not regressions
# in either calculated or actuall cost for $query.
#
# USAGE
#
# let $query= <select statement>;
# --source include/execute_with_statistics.inc
#
# EXAMPLE
# t/greedy_optimizer.test
#
eval EXPLAIN $query;
SHOW STATUS LIKE 'Last_query_cost';
FLUSH STATUS;
eval $query;
--disable_warnings
SELECT SUM(variable_value) AS Total_handler_reads
FROM information_schema.session_status
WHERE variable_name LIKE 'Handler_read%';
--enable_warnings

View File

@@ -0,0 +1,45 @@
# include/expect_qep.inc
#
# SUMMARY
#
# Designed to be used together with include/check_qep.inc
#
# $query should be assigned a select statement using
# straight_join to force the tables to be joined in most
# optimal order.
#
# expect_qep.inc will then store the estimated 'Last_query_cost'
# and total # 'Handler_read%' for this straight_joined query.
#
# We should then assign a non-straight_join'ed version of
# the same query to $query and execute it using
# 'include/check_qep.inc'. Its estimated cost and
# #handler_reads will then be verified against the
# previous straight_joined query.
#
# USAGE
#
# let $query= <select straight_join optimal statement>;
# --source include/expect_qep.inc
# let $query= <select statement>;
# --source include/check_qep.inc
#
# EXAMPLE
# t/greedy_optimizer.test
#
flush status;
eval EXPLAIN $query;
eval $query;
let $best_cost=
query_get_value(SHOW STATUS LIKE 'Last_query_cost', Value, 1);
--disable_warnings
let $best_reads=
`select sum(variable_value)
from information_schema.session_status
where VARIABLE_NAME like 'Handler_read%'`;
--enable_warnings
#echo Expect, cost: $best_cost, Handler_reads: $best_reads;

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
--source include/have_innodb.inc
#
# A simple test of the greedy query optimization algorithm and the switches that
# control the optimizationprocess.
@@ -248,7 +250,7 @@ explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and
show status like 'Last_query_cost';
set optimizer_prune_level=1;
set optimizer_prune_level=2;
select @@optimizer_prune_level;
set optimizer_search_depth=0;
@@ -381,6 +383,573 @@ LEFT JOIN (
SET optimizer_search_depth = DEFAULT;
DROP TABLE t1,t2,t2_1,t3,t3_1,t4,t4_1,t5,t5_1;
set join_cache_level=@save_join_cache_level;
--echo End of 5.0 tests
set join_cache_level=@save_join_cache_level;
--echo #
--echo # Bug #59326: Greedy optimizer produce stupid query execution plans.
--echo #
CREATE TABLE t10(
K INT NOT NULL AUTO_INCREMENT,
I INT,
PRIMARY KEY(K)
);
INSERT INTO t10(I) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(0);
CREATE TABLE t100 LIKE t10;
INSERT INTO t100(I)
SELECT X.I FROM t10 AS X,t10 AS Y;
CREATE TABLE t10000 LIKE t10;
INSERT INTO t10000(I)
SELECT X.I FROM t100 AS X, t100 AS Y;
--disable_warnings
let $total_handler_reads=
select sum(variable_value) from information_schema.session_status
where VARIABLE_NAME like 'Handler_read%';
--enable_warnings
## All crossproducts should be executed in order t10,t100,t10000
EXPLAIN SELECT * FROM t10,t100,t10000;
EXPLAIN SELECT * FROM t10,t10000,t100;
EXPLAIN SELECT * FROM t100,t10,t10000;
EXPLAIN SELECT * FROM t100,t10000,t10;
EXPLAIN SELECT * FROM t10000,t10,t100;
EXPLAIN SELECT * FROM t10000,t100,t10;
######
## Ordering between T100,T10000 EQ-joined T10 will
## normally be with smallest EQ-table joined first
######
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.K=t10.I;
--source include/expect_qep.inc
## However, swapping EQ_REF-joined tables gives the same cost
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000,t100
WHERE t100.K=t10.I
AND t10000.K=t10.I;
--source include/check_qep.inc
#####
# Expect all variants of EQ joining t100 & t10000 with T10
# to have same cost # handler_reads:
let $query=
SELECT COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.K=t10.I;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000,t100
WHERE t100.K=t10.I
AND t10000.K=t10.I;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.K=t10.K;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000,t100
WHERE t100.K=t10.I
AND t10000.K=t10.K;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t100,t10,t10000
WHERE t100.K=t10.I
AND t10000.K=t10.K;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t100,t10000,t10
WHERE t100.K=t10.I
AND t10000.K=t10.K;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10000,t10,t100
WHERE t100.K=t10.I
AND t10000.K=t10.K;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10000,t100,t10
WHERE t100.K=t10.I
AND t10000.K=t10.K;
--source include/check_qep.inc
#####
## EQ_REF Should be executed before table scan(ALL)
## - Independent of #records in table being EQ_REF-joined
#####
#####
# Expect: Join EQ_REF(t100) before ALL(t10000)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.I=t10.I;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.I=t10.I;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000,t100
WHERE t100.K=t10.I
AND t10000.I=t10.I;
--source include/check_qep.inc
#####
# Expect: Join EQ_REF(t10000) before ALL(t100) (star-join)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000,t100
WHERE t100.I=t10.I
AND t10000.K=t10.I;
--source include/expect_qep.inc
--echo # See BUG#18352936
let $query=
SELECT COUNT(*) FROM t10,t100,t10000
WHERE t100.I=t10.I
AND t10000.K=t10.I;
--source include/check_qep.inc
--echo # See BUG#18352936
let $query=
SELECT COUNT(*) FROM t10,t10000,t100
WHERE t100.I=t10.I
AND t10000.K=t10.I;
--source include/check_qep.inc
#####
# Expect: Join EQ_REF(t10000) before ALL(t100)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000,t100
WHERE t100.I=t10.I
AND t10000.K=t100.I;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t100,t10000
WHERE t100.I=t10.I
AND t10000.K=t100.I;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000,t100
WHERE t100.I=t10.I
AND t10000.K=t100.I;
--source include/check_qep.inc
#####
## EQ_REF & ALL join two instances of t10000 with t10:
## Always EQ_REF join first before producing cross product
#####
#####
# Expected QEP: 'join EQ_REF(X) on X.K=t10.I' before 'cross' ALL(Y)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 y,t10000 x
WHERE x.k=t10.i;
--source include/check_qep.inc
#####
# Expected QEP: 'join EQ_REF(X) on X.K=t10.I' before ALL(Y)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=t10.i;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=t10.i;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 y,t10000 x
WHERE x.k=t10.i
AND y.i=t10.i;
--source include/check_qep.inc
#####
# Expected QEP: 'join EQ_REF(X) on X.K=t10.I' before ALL(Y)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=x.k;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=x.k;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 y,t10000 x
WHERE x.k=t10.i
AND y.i=x.k;
--source include/check_qep.inc
## Create indexes to test REF access
CREATE INDEX IX ON t10(I);
CREATE INDEX IX ON t100(I);
CREATE INDEX IX ON t10000(I);
########
## EQ_REF Should be executed before 'REF'
## - Independent of #records in table being EQ_REF-joined
####
# Expected QEP: 'join EQ_REF(t100) on t100.K=t10.I' before REF(t10000)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.I=t10.I;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t100,t10000
WHERE t100.K=t10.I
AND t10000.I=t10.I;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000,t100
WHERE t100.K=t10.I
AND t10000.I=t10.I;
--source include/check_qep.inc
#####
## EQ_REF & REF join two instances of t10000 with t10:
#####
#####
## Expect this QEP, cost & #handler_read
# Expected QEP: 'join EQ_REF(X) on X.K=t10.I' before 'cross' ALL(Y)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 y,t10000 x
WHERE x.k=t10.i;
--source include/check_qep.inc
#####
# Expected QEP: 'join EQ_REF(X) on X.K=t10.I' before REF(Y)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=t10.i;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=t10.i;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 y,t10000 x
WHERE x.k=t10.i
AND y.i=t10.i;
--source include/check_qep.inc
#####
# Expected QEP: 'join EQ_REF(X) on X.K=t10.I' before REF(Y)
let $query=
SELECT STRAIGHT_JOIN COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=x.k;
--source include/expect_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 x,t10000 y
WHERE x.k=t10.i
AND y.i=x.k;
--source include/check_qep.inc
let $query=
SELECT COUNT(*) FROM t10,t10000 y,t10000 x
WHERE x.k=t10.i
AND y.i=x.k;
--source include/check_qep.inc
########
########
--echo #
--echo # Test improved capabilities of analyzing complex query
--echo # plans without restricting 'optimizer_search_depth'.
--echo # Fix problems like those reported as bug#41740 & bug#58225.
--echo #
--echo # EPLAIN of queries using T1-T62 will timeout/hang wo/ fixes
--echo #
DROP TABLE t10, t10000;
--disable_result_log
let $tabledef=
( K INT NOT NULL AUTO_INCREMENT,
I INT,
A INT,
PRIMARY KEY(K), KEY IX(A)
) engine = InnoDB;
let $analyze = ANALYZE TABLE t100;
let $i= 1;
while ($i < 62)
{
let $create= CREATE TABLE t$i $tabledef;
eval $create;
let $insert =
INSERT INTO t$i(I,A) SELECT X.K,X.K FROM t100 AS X, t100 AS Y WHERE X.K < 20 AND Y.K <= $i;
eval $insert;
let $analyze = $analyze, t$i;
inc $i;
}
eval $analyze;
set optimizer_prune_level=default;
#--enable_result_log
#select @@optimizer_prune_level;
#--disable_result_log
flush status;
#################
## The EXPLAIN'ed query itself can't be part of the verified
## result as the QEP is not 100% predictable due to variation
## in statistics from the engines. This is believed to be
## caused by:
## - Variations in table fill degree.
## - 'Fuzzy' statistics provided by engines.
## - Round errors caused by 'cost' calculation using
## 'only' 64-bit double precision.
## - Other bugs...?
##
###############
## Will test with optimizer_search_depth= [0,1,3,62]
let $depth= 0;
while ($depth<4)
{
if ($depth==0)
{
set optimizer_search_depth=0;
}
if ($depth==1)
{
set optimizer_search_depth=1;
}
if ($depth==2)
{
set optimizer_search_depth=3;
}
if ($depth==3)
{
set optimizer_search_depth=62;
}
inc $depth;
## Test pruning of joined table scans (ALL)
## Prepare of QEP without timeout is heavily dependent
## on maintaining correctly '#rows-sorted' plan
##
let $query= SELECT COUNT(*) FROM t1 AS x;
let $i= 1;
while ($i < 61)
{
let $query= $query JOIN t$i ON t$i.I=x.I;
inc $i;
select @@optimizer_prune_level;
select @@optimizer_search_depth;
eval EXPLAIN $query;
}
## Test pruning of joined table scans (ALL)
## with multiple instances of same table.
## (All instances being equally expensive)
let $query= SELECT COUNT(*) FROM t1 AS x;
let $i= 1;
while ($i <= 56)
{
let $t= t$i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
let $query= $query JOIN $t as t$i ON t$i.I=x.I;
inc $i;
select @@optimizer_prune_level;
select @@optimizer_search_depth;
eval EXPLAIN $query;
}
## A mix of 25% EQ_REF / 75% ALL joins
##
let $query= SELECT COUNT(*) FROM t1 AS x;
let $i= 1;
while ($i < 60)
{
let $query= $query JOIN t$i ON t$i.I = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.K = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.I = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.I = x.I;
inc $i;
eval EXPLAIN $query;
}
## A mix of 50% EQ_REF / 50% ALL joins
##
let $query= SELECT COUNT(*) FROM t1 AS x;
let $i= 1;
while ($i < 60)
{
let $query= $query JOIN t$i ON t$i.I = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.K = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.I = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.K = x.I;
inc $i;
eval EXPLAIN $query;
}
## A mix of 75% EQ_REF / 25% ALL joins
##
let $query= SELECT COUNT(*) FROM t1 AS x;
let $i= 1;
while ($i < 60)
{
let $query= $query JOIN t$i ON t$i.I = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.K = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.K = x.I;
inc $i;
let $query= $query JOIN t$i ON t$i.K = x.I;
inc $i;
eval EXPLAIN $query;
}
## 100% EQ_REF joins
##
let $query= SELECT COUNT(*) FROM t1 AS x;
let $i= 1;
while ($i < 61)
{
let $query= $query JOIN t$i ON t$i.K=x.I;
inc $i;
eval EXPLAIN $query;
}
}
let $drop = DROP TABLE t100;
let $i= 1;
while ($i < 62)
{
let $drop = $drop, t$i;
inc $i;
}
eval $drop;
--enable_result_log
show status like "optimizer%";
SET OPTIMIZER_SEARCH_DEPTH = DEFAULT;
--echo #
--echo # Bug found when testing greedy optimizer tests
--echo #
CREATE TABLE t1 (pk INTEGER,
col_int_key INTEGER,
col_varchar_key VARCHAR(8),
PRIMARY KEY (pk),
KEY (col_varchar_key, col_int_key, pk));
INSERT INTO t1 values (1,1,"A"),(2,2,"B");
explain SELECT * FROM t1 AS alias1
WHERE alias1.col_varchar_key IN (SELECT COUNT(*) FROM t1 AS SQ3_alias2 JOIN t1 AS SQ3_alias3 ON (SQ3_alias3.col_varchar_key = SQ3_alias2.col_varchar_key AND SQ3_alias3.pk = SQ3_alias2.pk));
drop table t1;
--echo #
--echo # This triggered an assert failure while testing
--echo #
CREATE TABLE t1 (a int, b int, key(b));
INSERT INTO t1 VALUES (7,4),(1,1);
CREATE TABLE t2 (d int);
INSERT INTO t2 VALUES (2),(3);
CREATE TABLE t3 (c int);
INSERT INTO t3 VALUES (5),(6);
SELECT * FROM t1 WHERE 5 IN (SELECT t1_a.a FROM t1 as t1_a WHERE 1 IN (SELECT t1_b.a FROM t1 as t1_b LEFT JOIN (t2 JOIN t3) ON (t1_b.a = t2.d) WHERE t1_b.b < 1));
drop table t1,t2,t3;
--echo End of 10.0 tests

View File

@@ -890,7 +890,7 @@ insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B;
explain select * from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
show status like '%cost%';
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 4.016090
select 'The cost of accessing t1 (dont care if it changes' '^';
@@ -904,7 +904,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE A eq_ref PRIMARY PRIMARY 4 test.t1.a 1 Using where
1 SIMPLE B eq_ref PRIMARY PRIMARY 4 test.A.b 1
show status like '%cost%';
show status like 'Last_query_cost';
Variable_name Value
Last_query_cost 28.016090
select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z;

View File

@@ -692,13 +692,13 @@ create table t2 (a int, b int, primary key(a));
insert into t2 select @v:=A.a+10*B.a, @v from t1 A, t1 B;
explain select * from t1;
show status like '%cost%';
show status like 'Last_query_cost';
select 'The cost of accessing t1 (dont care if it changes' '^';
select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z;
explain select * from t1, t2 A, t2 B where A.a = t1.a and B.a=A.b;
show status like '%cost%';
show status like 'Last_query_cost';
select '^^: The above should be ~= 20 + cost(select * from t1). Value less than 20 is an error' Z;

View File

@@ -1744,9 +1744,9 @@ ON t4.carrier = t1.carrier;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index package_id package_id 5 NULL 45 Using where; Using index
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.package_id 1
1 SIMPLE t3 ref package_id package_id 5 test.t2.package_id 1 Using index
1 SIMPLE t4 eq_ref PRIMARY,id PRIMARY 2 test.t1.carrier 1 Using where
1 SIMPLE t5 ref carrier_id carrier_id 5 test.t4.id 22 Using index
1 SIMPLE t3 ref package_id package_id 5 test.t2.package_id 1 Using index
SELECT COUNT(*)
FROM ((t2 JOIN t1 ON t2.package_id = t1.id)
JOIN t3 ON t3.package_id = t1.id)

View File

@@ -1753,9 +1753,9 @@ ON t4.carrier = t1.carrier;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index package_id package_id 5 NULL 45 Using where; Using index
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.package_id 1 Using join buffer (flat, BKA join); Key-ordered Rowid-ordered scan
1 SIMPLE t3 ref package_id package_id 5 test.t2.package_id 1 Using index
1 SIMPLE t4 eq_ref PRIMARY,id PRIMARY 2 test.t1.carrier 1 Using where
1 SIMPLE t5 ref carrier_id carrier_id 5 test.t4.id 22 Using index
1 SIMPLE t3 ref package_id package_id 5 test.t2.package_id 1 Using index
SELECT COUNT(*)
FROM ((t2 JOIN t1 ON t2.package_id = t1.id)
JOIN t3 ON t3.package_id = t1.id)

View File

@@ -437,15 +437,15 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL a4,a6,a5,a7 NULL NULL NULL 3 Using where
1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1 Using index
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.b2 1 Using where; Using index
1 SIMPLE t8 eq_ref PRIMARY PRIMARY 1 test.t1.a4 1 Using index
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 4 test.t1.a2 1 Using index
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.d1 1 Using where
1 SIMPLE t6 eq_ref PRIMARY PRIMARY 4 test.t1.a3 1 Using where; Using index
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 1 test.t1.a7 1
1 SIMPLE t8 eq_ref PRIMARY PRIMARY 1 test.t1.a4 1 Using index
1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1
1 SIMPLE t11 eq_ref PRIMARY PRIMARY 4 test.t1.a5 1
1 SIMPLE t12 eq_ref PRIMARY PRIMARY 4 test.t11.k3 1 Using where
1 SIMPLE l2 eq_ref PRIMARY PRIMARY 4 test.t11.k4 1 Using where
1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1
1 SIMPLE t13 ref PRIMARY,m3 m3 8 const,test.t1.a1 1 Using index
1 SIMPLE l4 eq_ref PRIMARY PRIMARY 4 test.t13.m2 1 Using where; Using index
1 SIMPLE m2 ref PRIMARY,m3 m3 8 const,test.t1.a1 1 Using index
@@ -459,15 +459,15 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL a4,a6,a5,a7 NULL NULL NULL 3 Using where
1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a1 1 Using index
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.b2 1 Using where; Using index
1 SIMPLE t8 eq_ref PRIMARY PRIMARY 1 test.t1.a4 1 Using index
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 4 test.t1.a2 1 Using index
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.d1 1 Using where
1 SIMPLE t6 eq_ref PRIMARY PRIMARY 4 test.t1.a3 1 Using where; Using index
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 1 test.t1.a7 1
1 SIMPLE t8 eq_ref PRIMARY PRIMARY 1 test.t1.a4 1 Using index
1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1
1 SIMPLE t11 eq_ref PRIMARY PRIMARY 4 test.t1.a5 1
1 SIMPLE t12 eq_ref PRIMARY PRIMARY 4 test.t11.k3 1 Using where
1 SIMPLE l2 eq_ref PRIMARY PRIMARY 4 test.t11.k4 1 Using where
1 SIMPLE t9 ref PRIMARY PRIMARY 1 test.t1.a4 1
1 SIMPLE t13 ref PRIMARY,m3 m3 8 const,test.t1.a1 1 Using index
1 SIMPLE l4 eq_ref PRIMARY PRIMARY 4 test.t13.m2 1 Using where; Using index
1 SIMPLE m2 ref PRIMARY,m3 m3 8 const,test.t1.a1 1 Using index

View File

@@ -706,8 +706,9 @@ The following specify which files/extra groups are read (specified before remain
Controls the heuristic(s) applied during query
optimization to prune less-promising partial plans from
the optimizer search space. Meaning: 0 - do not apply any
heuristic, thus perform exhaustive search; 1 - prune
plans based on number of retrieved rows
heuristic, thus perform exhaustive search: 1 - prune
plans based on cost and number of retrieved rows eq_ref:
2 - prune also if we find an eq_ref chain
--optimizer-search-depth=#
Maximum depth of search performed by the query optimizer.
Values larger than the number of relations in a query
@@ -1662,7 +1663,7 @@ old-mode UTF8_IS_UTF8MB3
old-passwords FALSE
old-style-user-limits FALSE
optimizer-max-sel-arg-weight 32000
optimizer-prune-level 1
optimizer-prune-level 2
optimizer-search-depth 62
optimizer-selectivity-sampling-limit 100
optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on

File diff suppressed because it is too large Load Diff

View File

@@ -888,3 +888,4 @@ select left(trace, 100) from information_schema.optimizer_trace;
set optimizer_trace='enabled=off';
--echo # End of 10.6 tests

View File

@@ -203,8 +203,10 @@ explain select * from t1 where a=1 or b=1 {
"considered_execution_plans": [
{
"plan_prefix": [],
"table": "t1",
"get_costs_for_tables": [
{
"best_access_path": {
"table": "t1",
"considered_access_paths": [
{
"access_type": "index_merge",
@@ -220,6 +222,8 @@ explain select * from t1 where a=1 or b=1 {
"uses_join_buffering": false
}
}
}
]
},
{
"plan_prefix": [],

View File

@@ -202,8 +202,10 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"considered_execution_plans": [
{
"plan_prefix": [],
"table": "t1",
"get_costs_for_tables": [
{
"best_access_path": {
"table": "t1",
"considered_access_paths": [
{
"access_type": "ref",
@@ -226,13 +228,14 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"uses_join_buffering": false
}
}
}
]
},
{
"plan_prefix": [],
"table": "t1",
"rows_for_plan": 1,
"cost_for_plan": 1.325146475,
"pruned_by_hanging_leaf": true
"cost_for_plan": 1.325146475
}
]
},

View File

@@ -89,8 +89,10 @@ select * from db1.t1 {
"considered_execution_plans": [
{
"plan_prefix": [],
"table": "t1",
"get_costs_for_tables": [
{
"best_access_path": {
"table": "t1",
"considered_access_paths": [
{
"access_type": "scan",
@@ -106,6 +108,8 @@ select * from db1.t1 {
"uses_join_buffering": false
}
}
}
]
},
{
"plan_prefix": [],
@@ -214,8 +218,10 @@ select * from db1.v1 {
"considered_execution_plans": [
{
"plan_prefix": [],
"table": "t1",
"get_costs_for_tables": [
{
"best_access_path": {
"table": "t1",
"considered_access_paths": [
{
"access_type": "scan",
@@ -231,6 +237,8 @@ select * from db1.v1 {
"uses_join_buffering": false
}
}
}
]
},
{
"plan_prefix": [],

View File

@@ -1257,8 +1257,8 @@ EXPLAIN EXTENDED
SELECT * FROM language, country, continent
WHERE country_group = lang_group AND lang_group IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE language ALL NULL NULL NULL NULL 6 0.00 Using where
1 SIMPLE country ALL NULL NULL NULL NULL 2 0.00 Using where; Using join buffer (flat, BNL join)
1 SIMPLE language ALL NULL NULL NULL NULL 6 16.67 Using where
1 SIMPLE country ALL NULL NULL NULL NULL 2 50.00 Using where; Using join buffer (flat, BNL join)
1 SIMPLE continent ALL NULL NULL NULL NULL 6 100.00 Using join buffer (incremental, BNL join)
Warnings:
Note 1003 select `test`.`language`.`lang_group` AS `lang_group`,`test`.`language`.`lang` AS `lang`,`test`.`country`.`code` AS `code`,`test`.`country`.`country_group` AS `country_group`,`test`.`continent`.`cont_group` AS `cont_group`,`test`.`continent`.`cont` AS `cont` from `test`.`language` join `test`.`country` join `test`.`continent` where `test`.`country`.`country_group` = `test`.`language`.`lang_group` and `test`.`language`.`lang_group` is null

View File

@@ -216,10 +216,10 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE part ALL PRIMARY NULL NULL NULL 200 Using where; Using join buffer (flat, BNL join)
1 SIMPLE lineitem ref PRIMARY,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey,i_l_orderkey,i_l_orderkey_quantity i_l_partkey 5 dbt3_s001.part.p_partkey 30 Using where
1 SIMPLE supplier eq_ref PRIMARY,i_s_nationkey PRIMARY 4 dbt3_s001.lineitem.l_suppkey 1 Using where
1 SIMPLE n2 eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1
1 SIMPLE orders eq_ref|filter PRIMARY,i_o_orderdate,i_o_custkey PRIMARY|i_o_orderdate 4|4 dbt3_s001.lineitem.l_orderkey 1 (27%) Using where; Using rowid filter
1 SIMPLE customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where
1 SIMPLE n1 eq_ref PRIMARY,i_n_regionkey PRIMARY 4 dbt3_s001.customer.c_nationkey 1 Using where
1 SIMPLE n2 eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1
select o_year,
sum(case when nation = 'UNITED STATES' then volume else 0 end) /
sum(volume) as mkt_share

View File

@@ -248,10 +248,10 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE part ALL PRIMARY NULL NULL NULL 200 Using where; Using join buffer (flat, BNL join)
1 SIMPLE lineitem ref PRIMARY,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey,i_l_orderkey,i_l_orderkey_quantity i_l_partkey 5 dbt3_s001.part.p_partkey 30 Using where
1 SIMPLE supplier eq_ref PRIMARY,i_s_nationkey PRIMARY 4 dbt3_s001.lineitem.l_suppkey 1 Using where
1 SIMPLE n2 eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1
1 SIMPLE orders eq_ref PRIMARY,i_o_orderdate,i_o_custkey PRIMARY 4 dbt3_s001.lineitem.l_orderkey 1 Using where
1 SIMPLE customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where
1 SIMPLE n1 eq_ref PRIMARY,i_n_regionkey PRIMARY 4 dbt3_s001.customer.c_nationkey 1 Using where
1 SIMPLE n2 eq_ref PRIMARY PRIMARY 4 dbt3_s001.supplier.s_nationkey 1
select o_year,
sum(case when nation = 'UNITED STATES' then volume else 0 end) /
sum(volume) as mkt_share

View File

@@ -120,19 +120,19 @@ ALTER TABLE t2 ADD FOREIGN KEY FK_DCMNTS_FLDRS ( FOLDERID)
REFERENCES t3 (FOLDERID );
ALTER TABLE t3 ADD FOREIGN KEY FK_FLDRS_PRNTID ( PARENTID)
REFERENCES t3 (FOLDERID );
SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3_a.FOLDERID FROM t3 as t3_a WHERE t3_a.PARENTID IN(SELECT t3_b.FOLDERID FROM t3 as t3_b WHERE t3_b.PARENTID IN(SELECT t3_c.FOLDERID FROM t3 as t3_c WHERE t3_c.PARENTID IN(SELECT t3_d.FOLDERID FROM t3 as t3_d WHERE t3_d.PARENTID IN(SELECT t3_e.FOLDERID FROM t3 as t3_e WHERE t3_e.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3_e.FOLDERNAME = 'Level1') AND t3_d.FOLDERNAME = 'Level2') AND t3_c.FOLDERNAME = 'Level3') AND t3_b.FOLDERNAME = 'CopiedFolder') AND t3_a.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
DOCID DOCNAME DOCTYPEID FOLDERID AUTHOR CREATED TITLE SUBTITLE DOCABSTRACT PUBLISHDATE EXPIRATIONDATE LOCKEDBY STATUS PARENTDOCID REPID MODIFIED MODIFIER PUBLISHSTATUS ORIGINATOR DOCTYPENAME CONTENTSIZE MIMETYPE
c373e9f5ad07993f3859444553544200 Last Discussion c373e9f5ad079174ff17444553544200 c373e9f5ad0796c0eca4444553544200 Goldilocks 2003-06-09 11:21:06 Title: Last Discussion NULL Setting new abstract and keeping doc checked out 2003-06-09 10:51:26 2003-06-09 10:51:26 NULL NULL NULL 03eea05112b845949f3fd03278b5fe43 2003-06-09 11:21:06 admin 0 NULL Discussion NULL NULL
EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3_a.FOLDERID FROM t3 as t3_a WHERE t3_a.PARENTID IN(SELECT t3_b.FOLDERID FROM t3 as t3_b WHERE t3_b.PARENTID IN(SELECT t3_c.FOLDERID FROM t3 as t3_c WHERE t3_c.PARENTID IN(SELECT t3_d.FOLDERID FROM t3 as t3_d WHERE t3_d.PARENTID IN(SELECT t3_e.FOLDERID FROM t3 as t3_e WHERE t3_e.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3_e.FOLDERNAME = 'Level1') AND t3_d.FOLDERNAME = 'Level2') AND t3_c.FOLDERNAME = 'Level3') AND t3_b.FOLDERNAME = 'CopiedFolder') AND t3_a.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL DDOCTYPEID_IDX,DFOLDERID_IDX NULL NULL NULL 9 Using where
1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1
1 PRIMARY t1 eq_ref PRIMARY PRIMARY 34 test.t2.DOCID 1
1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t2.FOLDERID 1 Using where
1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3.PARENTID 1 Using where
1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3.PARENTID 1 Using where
1 PRIMARY t3 eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3.PARENTID 1 Using where
1 PRIMARY t3 ref|filter PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX FFOLDERID_IDX|CMFLDRPARNT_IDX 34|35 test.t3.PARENTID 1 (29%) Using where; Using rowid filter
1 PRIMARY t3_a eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t2.FOLDERID 1 Using where
1 PRIMARY t3_b eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3_a.PARENTID 1 Using where
1 PRIMARY t3_c eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3_b.PARENTID 1 Using where
1 PRIMARY t3_d eq_ref PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 test.t3_c.PARENTID 1 Using where
1 PRIMARY t3_e ref|filter PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX FFOLDERID_IDX|CMFLDRPARNT_IDX 34|35 test.t3_d.PARENTID 1 (29%) Using where; Using rowid filter
drop table t1, t2, t3, t4;
CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB;
INSERT INTO t1 VALUES (1),(2);

View File

@@ -148,9 +148,9 @@ ALTER TABLE t2 ADD FOREIGN KEY FK_DCMNTS_FLDRS ( FOLDERID)
ALTER TABLE t3 ADD FOREIGN KEY FK_FLDRS_PRNTID ( PARENTID)
REFERENCES t3 (FOLDERID );
SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3_a.FOLDERID FROM t3 as t3_a WHERE t3_a.PARENTID IN(SELECT t3_b.FOLDERID FROM t3 as t3_b WHERE t3_b.PARENTID IN(SELECT t3_c.FOLDERID FROM t3 as t3_c WHERE t3_c.PARENTID IN(SELECT t3_d.FOLDERID FROM t3 as t3_d WHERE t3_d.PARENTID IN(SELECT t3_e.FOLDERID FROM t3 as t3_e WHERE t3_e.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3_e.FOLDERNAME = 'Level1') AND t3_d.FOLDERNAME = 'Level2') AND t3_c.FOLDERNAME = 'Level3') AND t3_b.FOLDERNAME = 'CopiedFolder') AND t3_a.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3_a.FOLDERID FROM t3 as t3_a WHERE t3_a.PARENTID IN(SELECT t3_b.FOLDERID FROM t3 as t3_b WHERE t3_b.PARENTID IN(SELECT t3_c.FOLDERID FROM t3 as t3_c WHERE t3_c.PARENTID IN(SELECT t3_d.FOLDERID FROM t3 as t3_d WHERE t3_d.PARENTID IN(SELECT t3_e.FOLDERID FROM t3 as t3_e WHERE t3_e.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3_e.FOLDERNAME = 'Level1') AND t3_d.FOLDERNAME = 'Level2') AND t3_c.FOLDERNAME = 'Level3') AND t3_b.FOLDERNAME = 'CopiedFolder') AND t3_a.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
drop table t1, t2, t3, t4;
# End of 4.1 tests

View File

@@ -2404,6 +2404,21 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 32 test.t1.assignment_group 1 Using where; Using index
2 MATERIALIZED t2 ref idx3,idx4 idx4 35 const 2 Using index condition; Using where
2 MATERIALIZED t3_i eq_ref PRIMARY PRIMARY 32 test.t2.ugroup 1 Using index condition; Using where
set statement optimizer_prune_level=1 for explain SELECT t1.assignment_group
FROM t1, t3
WHERE t1.assignment_group = t3.sys_id AND
t1.dispatch_group IN
(SELECT t2.ugroup
FROM t2, t3 t3_i
WHERE t2.ugroup = t3_i.sys_id AND
t3_i.type LIKE '59e22fb137032000158bbfc8bcbe5d52' AND
t2.user = '86826bf03710200044e0bfc8bcbe5d79');
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2
1 PRIMARY t1 ref idx1,idx2 idx1 35 test.t2.ugroup 2 Using where
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 32 test.t1.assignment_group 1 Using where; Using index
3 MATERIALIZED t2 ref idx3,idx4 idx4 35 const 2 Using index condition; Using where
3 MATERIALIZED t3_i eq_ref PRIMARY PRIMARY 32 test.t2.ugroup 1 Using index condition; Using where
SELECT t1.assignment_group
FROM t1, t3
WHERE t1.assignment_group = t3.sys_id AND

View File

@@ -2446,6 +2446,21 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 32 test.t1.assignment_group 1 Using where; Using index
2 MATERIALIZED t2 ref idx3,idx4 idx4 35 const 2 Using index condition; Using where
2 MATERIALIZED t3_i eq_ref PRIMARY PRIMARY 32 test.t2.ugroup 1 Using index condition; Using where
set statement optimizer_prune_level=1 for explain SELECT t1.assignment_group
FROM t1, t3
WHERE t1.assignment_group = t3.sys_id AND
t1.dispatch_group IN
(SELECT t2.ugroup
FROM t2, t3 t3_i
WHERE t2.ugroup = t3_i.sys_id AND
t3_i.type LIKE '59e22fb137032000158bbfc8bcbe5d52' AND
t2.user = '86826bf03710200044e0bfc8bcbe5d79');
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <subquery3> ALL distinct_key NULL NULL NULL 2
1 PRIMARY t1 ref idx1,idx2 idx1 35 test.t2.ugroup 2 Using where
1 PRIMARY t3 eq_ref PRIMARY PRIMARY 32 test.t1.assignment_group 1 Using where; Using index
3 MATERIALIZED t2 ref idx3,idx4 idx4 35 const 2 Using index condition; Using where
3 MATERIALIZED t3_i eq_ref PRIMARY PRIMARY 32 test.t2.ugroup 1 Using index condition; Using where
SELECT t1.assignment_group
FROM t1, t3
WHERE t1.assignment_group = t3.sys_id AND

View File

@@ -2163,6 +2163,7 @@ eval $q;
set optimizer_switch='materialization=on';
eval explain $q;
eval set statement optimizer_prune_level=1 for explain $q;
eval $q;
DROP TABLE t1,t2,t3;

View File

@@ -1,35 +1,35 @@
SET @start_global_value = @@global.optimizer_prune_level;
SELECT @start_global_value;
@start_global_value
1
2
SET @start_session_value = @@session.optimizer_prune_level;
SELECT @start_session_value;
@start_session_value
1
2
'#--------------------FN_DYNVARS_115_01-------------------------#'
SET @@global.optimizer_prune_level = 0;
SET @@global.optimizer_prune_level = DEFAULT;
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
1
2
SET @@session.optimizer_prune_level = 0;
SET @@session.optimizer_prune_level = DEFAULT;
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
1
2
'#--------------------FN_DYNVARS_115_02-------------------------#'
SET @@global.optimizer_prune_level = DEFAULT;
SELECT @@global.optimizer_prune_level = 1;
@@global.optimizer_prune_level = 1
SELECT @@global.optimizer_prune_level = 2;
@@global.optimizer_prune_level = 2
1
SET @@session.optimizer_prune_level = DEFAULT;
SELECT @@session.optimizer_prune_level = 1;
@@session.optimizer_prune_level = 1
SELECT @@session.optimizer_prune_level = 2;
@@session.optimizer_prune_level = 2
1
'#--------------------FN_DYNVARS_115_03-------------------------#'
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
1
2
SET @@global.optimizer_prune_level = 0;
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
@@ -38,6 +38,10 @@ SET @@global.optimizer_prune_level = 1;
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
1
SET @@global.optimizer_prune_level = 2;
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
2
SET @@global.optimizer_prune_level = TRUE;
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
@@ -49,7 +53,7 @@ SELECT @@global.optimizer_prune_level;
'#--------------------FN_DYNVARS_115_04-------------------------#'
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
1
2
SET @@session.optimizer_prune_level = 0;
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
@@ -58,6 +62,10 @@ SET @@session.optimizer_prune_level = 1;
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
1
SET @@session.optimizer_prune_level = 2;
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
2
SET @@session.optimizer_prune_level = TRUE;
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
@@ -69,7 +77,7 @@ SELECT @@session.optimizer_prune_level;
'#------------------FN_DYNVARS_115_05-----------------------#'
SET @@global.optimizer_prune_level = ON;
ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level'
'Bug# 34840: Since it is a boolean variable, it should not give errors on 'ON' & 'OFF' values';
'Bug# 34840: Since it is not a boolean variable, it should give errors on 'ON' & 'OFF' values';
SET @@global.optimizer_prune_level = OFF;
ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level'
SET @@global.optimizer_prune_level = 'ONN';
@@ -86,10 +94,16 @@ Warning 1292 Truncated incorrect optimizer_prune_level value: '-1024'
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
0
'Bug# 34840: Since it is a boolean variable, it should give errors on numeric values';
'Bug# 34840: Since it is not a boolean variable, it should no give errors on numeric values';
SET @@global.optimizer_prune_level = 65536;
Warnings:
Warning 1292 Truncated incorrect optimizer_prune_level value: '65536'
SET @@global.optimizer_prune_level = 3;
Warnings:
Warning 1292 Truncated incorrect optimizer_prune_level value: '3'
select @@global.optimizer_prune_level;
@@global.optimizer_prune_level
2
SET @@global.optimizer_prune_level = 65530.34;
ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level'
SET @@global.optimizer_prune_level = test;
@@ -121,7 +135,7 @@ Warnings:
Warning 1292 Truncated incorrect optimizer_prune_level value: '65550'
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
1
2
SET @@session.optimizer_prune_level = test;
ERROR 42000: Incorrect argument type to variable 'optimizer_prune_level'
'#------------------FN_DYNVARS_115_06-----------------------#'
@@ -164,8 +178,8 @@ ERROR 42S22: Unknown column 'optimizer_prune_level' in 'field list'
SET @@global.optimizer_prune_level = @start_global_value;
SELECT @@global.optimizer_prune_level;
@@global.optimizer_prune_level
1
2
SET @@session.optimizer_prune_level = @start_session_value;
SELECT @@session.optimizer_prune_level;
@@session.optimizer_prune_level
1
2

View File

@@ -2265,9 +2265,9 @@ COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_PRUNE_LEVEL
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search; 1 - prune plans based on number of retrieved rows
VARIABLE_COMMENT Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search: 1 - prune plans based on cost and number of retrieved rows eq_ref: 2 - prune also if we find an eq_ref chain
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1
NUMERIC_MAX_VALUE 2
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO

View File

@@ -2435,9 +2435,9 @@ COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_PRUNE_LEVEL
VARIABLE_SCOPE SESSION
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search; 1 - prune plans based on number of retrieved rows
VARIABLE_COMMENT Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search: 1 - prune plans based on cost and number of retrieved rows eq_ref: 2 - prune also if we find an eq_ref chain
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1
NUMERIC_MAX_VALUE 2
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO

View File

@@ -60,10 +60,10 @@ SELECT @@session.optimizer_prune_level;
###########################################################
SET @@global.optimizer_prune_level = DEFAULT;
SELECT @@global.optimizer_prune_level = 1;
SELECT @@global.optimizer_prune_level = 2;
SET @@session.optimizer_prune_level = DEFAULT;
SELECT @@session.optimizer_prune_level = 1;
SELECT @@session.optimizer_prune_level = 2;
--echo '#--------------------FN_DYNVARS_115_03-------------------------#'
@@ -77,6 +77,8 @@ SET @@global.optimizer_prune_level = 0;
SELECT @@global.optimizer_prune_level;
SET @@global.optimizer_prune_level = 1;
SELECT @@global.optimizer_prune_level;
SET @@global.optimizer_prune_level = 2;
SELECT @@global.optimizer_prune_level;
SET @@global.optimizer_prune_level = TRUE;
SELECT @@global.optimizer_prune_level;
SET @@global.optimizer_prune_level = FALSE;
@@ -94,6 +96,8 @@ SET @@session.optimizer_prune_level = 0;
SELECT @@session.optimizer_prune_level;
SET @@session.optimizer_prune_level = 1;
SELECT @@session.optimizer_prune_level;
SET @@session.optimizer_prune_level = 2;
SELECT @@session.optimizer_prune_level;
SET @@session.optimizer_prune_level = TRUE;
SELECT @@session.optimizer_prune_level;
SET @@session.optimizer_prune_level = FALSE;
@@ -107,7 +111,7 @@ SELECT @@session.optimizer_prune_level;
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.optimizer_prune_level = ON;
--echo 'Bug# 34840: Since it is a boolean variable, it should not give errors on 'ON' & 'OFF' values';
--echo 'Bug# 34840: Since it is not a boolean variable, it should give errors on 'ON' & 'OFF' values';
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.optimizer_prune_level = OFF;
--Error ER_WRONG_TYPE_FOR_VAR
@@ -122,9 +126,11 @@ SET @@global.optimizer_prune_level = FELSE;
SET @@global.optimizer_prune_level = -1024;
SELECT @@global.optimizer_prune_level;
--echo 'Bug# 34840: Since it is a boolean variable, it should give errors on numeric values';
--echo 'Bug# 34840: Since it is not a boolean variable, it should no give errors on numeric values';
SET @@global.optimizer_prune_level = 65536;
SET @@global.optimizer_prune_level = 3;
select @@global.optimizer_prune_level;
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.optimizer_prune_level = 65530.34;
--Error ER_WRONG_TYPE_FOR_VAR

View File

@@ -159,10 +159,8 @@ Json_writer& Json_writer::add_member(const char *name, size_t len)
auto is_uniq_key= emplaced.second;
if(!is_uniq_key)
{
#ifdef QQQ
sql_print_error("Duplicated key: %s\n", emplaced.first->c_str());
VALIDITY_ASSERT(is_uniq_key);
#endif /* QQQ */
}
}
#endif

View File

@@ -769,7 +769,7 @@ void JOIN::add_keyuses_for_splitting()
added_keyuse->validity_ref= &keyuse_ext->validity_var;
}
if (sort_and_filter_keyuse(thd, &keyuse, true))
if (sort_and_filter_keyuse(this, &keyuse, true))
goto err;
optimize_keyuse(this, &keyuse);

View File

@@ -125,7 +125,8 @@ best_extension_by_limited_search(JOIN *join,
uint idx, double record_count,
double read_time, uint depth,
uint prune_level,
uint use_cond_selectivity);
uint use_cond_selectivity,
table_map *processed_eq_ref_tables);
static uint determine_search_depth(JOIN* join);
C_MODE_START
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
@@ -5468,7 +5469,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
join->unit->item->get_IN_subquery()->test_strategy(SUBS_IN_TO_EXISTS));
if (keyuse_array->elements &&
sort_and_filter_keyuse(thd, keyuse_array,
sort_and_filter_keyuse(join, keyuse_array,
skip_unprefixed_keyparts))
goto error;
DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
@@ -7266,6 +7267,32 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
DBUG_RETURN(FALSE);
}
/*
check if key could be used with eq_ref
The assumption is that all previous key parts where used
*/
static void remember_if_eq_ref_key(JOIN *join, KEYUSE *use)
{
DBUG_ASSERT(use->keypart != FT_KEYPART && use->key != MAX_KEY);
TABLE *table= use->table;
KEY *key= table->key_info+use->key;
ulong key_flags= table->actual_key_flags(key);
/*
Check if possible eq_ref key
This may include keys that does not have HA_NULL_PART_KEY
set, but this is ok as best_access_path will resolve this.
*/
if ((key_flags & (HA_NOSAME | HA_EXT_NOSAME)))
{
uint key_parts= table->actual_n_key_parts(key);
if (use->keypart+1 == key_parts)
join->eq_ref_tables|= table->map;
}
}
/**
Sort the array of possible keys and remove the following key parts:
@@ -7276,14 +7303,19 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
(e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is
used in the query, we drop the partial key parts from consideration).
Special treatment for ft-keys.
Update join->eq_ref_tables with a bitmap of all tables that can possible
have a EQ_REF key.
*/
bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
bool sort_and_filter_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse,
bool skip_unprefixed_keyparts)
{
THD *thd= join->thd;
KEYUSE key_end, *prev, *save_pos, *use;
uint found_eq_constant, i;
bool found_unprefixed_key_part= 0;
join->eq_ref_tables= 0;
DBUG_ASSERT(keyuse->elements);
my_qsort(keyuse->buffer, keyuse->elements, sizeof(KEYUSE),
@@ -7311,18 +7343,45 @@ bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
{
if (use->key == prev->key && use->table == prev->table)
{
if ((prev->keypart+1 < use->keypart && skip_unprefixed_keyparts) ||
(prev->keypart == use->keypart && found_eq_constant))
if (prev->keypart == use->keypart && found_eq_constant)
continue;
if (prev->keypart+1 < use->keypart)
{
found_unprefixed_key_part= 1;
if (skip_unprefixed_keyparts)
continue; /* remove */
}
else if (use->keypart != 0 && skip_unprefixed_keyparts)
continue; /* remove - first found must be 0 */
}
else
{
/* Key changed, check if previous key was a primary/unique key lookup */
if (prev != &key_end && !found_unprefixed_key_part)
remember_if_eq_ref_key(join, prev);
found_unprefixed_key_part= 0;
if (use->keypart != 0)
{
found_unprefixed_key_part= 1;
if (skip_unprefixed_keyparts)
continue; /* remove - first found key part must be 0 */
}
}
}
else /* FT_KEY_PART */
{
if (prev != &key_end && !found_unprefixed_key_part)
remember_if_eq_ref_key(join, prev);
found_unprefixed_key_part= 1; // This key cannot be EQ_REF
}
prev= use;
found_eq_constant= !use->used_tables;
use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
}
else
{
if (prev != &key_end && !found_unprefixed_key_part)
remember_if_eq_ref_key(join, prev);
prev= &key_end;
}
/*
Old gcc used a memcpy(), which is undefined if save_pos==use:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19410
@@ -7336,6 +7395,8 @@ bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
use->table->reginfo.join_tab->keyuse= save_pos;
save_pos++;
}
if (prev != &key_end && !found_unprefixed_key_part)
remember_if_eq_ref_key(join, prev);
i= (uint) (save_pos-(KEYUSE*) keyuse->buffer);
(void) set_dynamic(keyuse,(uchar*) &key_end,i);
keyuse->elements= i;
@@ -7782,6 +7843,8 @@ best_access_path(JOIN *join,
Json_writer_object trace_wrapper(thd, "best_access_path");
trace_wrapper.add_table_name(s);
bitmap_clear_all(eq_join_set);
loose_scan_opt.init(join, s, remaining_tables);
@@ -7947,7 +8010,8 @@ best_access_path(JOIN *join,
(!(key_flags & HA_NULL_PART_KEY) || // (2)
all_key_parts == notnull_part)) // (3)
{
/* Check that eq_ref_tables are correctly updated */
DBUG_ASSERT(join->eq_ref_tables & table->map);
/* TODO: Adjust cost for covering and clustering key */
type= JT_EQ_REF;
trace_access_idx.add("access_type", join_type_str[type])
@@ -9057,10 +9121,7 @@ optimize_straight_join(JOIN *join, table_map remaining_tables)
POSITION *position= join->positions + idx;
Json_writer_object trace_one_table(thd);
if (unlikely(thd->trace_started()))
{
trace_plan_prefix(join, idx, remaining_tables);
trace_one_table.add_table_name(s);
}
/* Find the best access method from 's' to the current partial plan */
best_access_path(join, s, remaining_tables, join->positions, idx,
disable_jbuf, record_count,
@@ -9193,7 +9254,7 @@ greedy_search(JOIN *join,
uint idx= join->const_tables; // index into 'join->best_ref'
uint best_idx;
uint size_remain; // cardinality of remaining_tables
table_map usable_tables;
table_map usable_tables, eq_ref_tables;
POSITION best_pos;
JOIN_TAB *best_table; // the next plan node to be added to the curr QEP
// ==join->tables or # tables in the sj-mat nest we're optimizing
@@ -9220,7 +9281,8 @@ greedy_search(JOIN *join,
record_count,
read_time, search_depth,
prune_level,
use_cond_selectivity) <
use_cond_selectivity,
&eq_ref_tables) <
(int) SEARCH_OK)
DBUG_RETURN(TRUE);
/*
@@ -9915,6 +9977,101 @@ sort_positions(SORT_POSITION *a, SORT_POSITION *b)
}
/*
Call best_access_path() for a set of tables and collect results
@param join JOIN object
@param trace_one_table Current optimizer_trace
@param pos Pointer to remanining tables
@param allowed_tables bitmap of allowed tables. On return set to
the collected tables.
@param store_poisition Points to where to store next found SORT_POSITION.
Will be updated to next free position.
@param stop_on_eq_ref Stop searching for more tables if we found an EQ_REF
table.
@return
0 Normal
1 Eq_ref table found (only if stop_on_eq_ref is used)
join->next_sort_position will be update to next free position.
*/
static bool
get_costs_for_tables(JOIN *join, table_map remaining_tables, uint idx,
double record_count,
Json_writer_object *trace_one_table,
JOIN_TAB **pos, SORT_POSITION **store_position,
table_map *allowed_tables,
bool stop_on_eq_ref)
{
THD *thd= join->thd;
POSITION *sort_position= join->next_sort_position;
SORT_POSITION *sort_end= *store_position;
JOIN_TAB *s;
table_map found_tables= 0;
bool found_eq_ref= 0;
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
DBUG_ENTER("get_plans_for_tables");
s= *pos;
do
{
table_map real_table_bit= s->table->map;
if ((*allowed_tables & real_table_bit) &&
!(remaining_tables & s->dependent))
{
#ifdef DBUG_ASSERT_EXISTS
DBUG_ASSERT(!check_interleaving_with_nj(s));
restore_prev_nj_state(s); // Revert effect of check_... call
#endif
sort_end->join_tab= pos;
sort_end->position= sort_position;
Json_writer_object wrapper(thd);
/* Find the best access method from 's' to the current partial plan */
best_access_path(join, s, remaining_tables, join->positions, idx,
disable_jbuf, record_count,
sort_position, sort_position + 1);
found_tables|= s->table->map;
sort_end++;
sort_position+= 2;
if (unlikely(stop_on_eq_ref) && sort_position[-2].type == JT_EQ_REF)
{
/* Found an eq_ref tables. Use this, ignoring the other tables */
found_eq_ref= 1;
if (found_tables == s->table->map)
break; // First table
/* Store the found eq_ref table first in store_position */
sort_position-= 2;
*allowed_tables= s->table->map;
(*store_position)->join_tab= pos;
(*store_position)->position= sort_position;
(*store_position)++;
join->next_sort_position[0]= sort_position[0];
join->next_sort_position[1]= sort_position[1];
join->next_sort_position+= 2;
DBUG_RETURN(1);
}
}
else
{
/* Verify that 'allowed_current_tables' was calculated correctly */
DBUG_ASSERT((remaining_tables & s->dependent) ||
!(remaining_tables & real_table_bit) ||
!(*allowed_tables & real_table_bit) ||
check_interleaving_with_nj(s));
}
} while ((s= *++pos));
*allowed_tables= found_tables;
*store_position= sort_end;
join->next_sort_position= sort_position;
DBUG_RETURN(found_eq_ref);
}
/**
Find a good, possibly optimal, query execution plan (QEP) by a possibly
exhaustive search.
@@ -10047,7 +10204,8 @@ best_extension_by_limited_search(JOIN *join,
double read_time,
uint search_depth,
uint prune_level,
uint use_cond_selectivity)
uint use_cond_selectivity,
table_map *processed_eq_ref_tables)
{
THD *thd= join->thd;
/*
@@ -10057,12 +10215,11 @@ best_extension_by_limited_search(JOIN *join,
JOIN_TAB *s;
double best_record_count= DBL_MAX;
double best_read_time= DBL_MAX;
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
enum_best_search best_res;
uint tables_left= join->table_count - idx, found_tables;
uint accepted_tables __attribute__((unused));
table_map found_eq_ref_tables= 0, used_eq_ref_table= 0;
table_map allowed_tables, allowed_current_tables;
POSITION *sort_position= join->next_sort_position;
SORT_POSITION *sort= (SORT_POSITION*) alloca(sizeof(SORT_POSITION)*tables_left);
SORT_POSITION *sort_end;
DBUG_ENTER("best_extension_by_limited_search");
@@ -10104,54 +10261,53 @@ best_extension_by_limited_search(JOIN *join,
}
DBUG_ASSERT(allowed_tables & remaining_tables);
sort_end= sort;
{
Json_writer_object trace_one_table(thd);
JOIN_TAB **best_ref= join->best_ref + idx;
if (unlikely(thd->trace_started()))
trace_plan_prefix(join, idx, remaining_tables);
Json_writer_array arr(thd, "get_costs_for_tables");
if (idx > join->const_tables && prune_level >= 2 &&
join->positions[idx-1].type == JT_EQ_REF &&
(join->eq_ref_tables & allowed_current_tables))
{
/* Previous table was an EQ REF table, only add other possible EQ_REF
tables to the chain, stop after first one is found.
*/
table_map table_map= join->eq_ref_tables & allowed_current_tables;
if (get_costs_for_tables(join, remaining_tables, idx, record_count,
&trace_one_table, best_ref, &sort_end,
&table_map, 1))
used_eq_ref_table= (*sort->join_tab)->table->map;
else
{
/* We didn't find another EQ_REF table, add remaining tables */
if ((table_map= allowed_current_tables & ~table_map))
get_costs_for_tables(join, remaining_tables, idx, record_count,
&trace_one_table, best_ref, &sort_end, &table_map,
0);
}
}
else
{
table_map table_map= allowed_current_tables;
get_costs_for_tables(join, remaining_tables, idx, record_count,
&trace_one_table, best_ref, &sort_end, &table_map,
0);
}
found_tables= (uint) (sort_end - sort);
DBUG_ASSERT(found_tables > 0);
/*
Sort tables in ascending order of generated row combinations
*/
sort_end= sort;
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{
table_map real_table_bit= s->table->map;
if ((allowed_current_tables & real_table_bit) &&
!(remaining_tables & s->dependent))
{
#ifdef DBUG_ASSERT_EXISTS
DBUG_ASSERT(!check_interleaving_with_nj(s));
restore_prev_nj_state(s); // Revert effect of check_... call
#endif
sort_end->join_tab= pos;
sort_end->position= sort_position;
if (unlikely(thd->trace_started()))
trace_one_table.add_table_name(s);
/* Find the best access method from 's' to the current partial plan */
best_access_path(join, s, remaining_tables, join->positions, idx,
disable_jbuf, record_count,
sort_position, sort_position + 1);
sort_end++;
sort_position+= 2;
}
else
{
/* Verify that 'allowed_current_tables' was calculated correctly */
DBUG_ASSERT((remaining_tables & s->dependent) ||
!(remaining_tables & real_table_bit) ||
!(allowed_tables & real_table_bit) ||
check_interleaving_with_nj(s));
}
}
found_tables= sort_end - sort;
DBUG_ASSERT(found_tables > 0);
if (found_tables > 1)
my_qsort(sort, found_tables, sizeof(SORT_POSITION),
(qsort_cmp) sort_positions);
}
join->next_sort_position+= found_tables*2;
DBUG_ASSERT(join->next_sort_position <=
join->sort_positions + join->sort_space);
@@ -10159,7 +10315,8 @@ best_extension_by_limited_search(JOIN *join,
for (SORT_POSITION *pos= sort ; pos < sort_end ; pos++)
{
s= *pos->join_tab;
if (!check_interleaving_with_nj(s))
if (!(found_eq_ref_tables & s->table->map) &&
!check_interleaving_with_nj(s))
{
table_map real_table_bit= s->table->map;
double current_record_count, current_read_time;
@@ -10214,7 +10371,7 @@ best_extension_by_limited_search(JOIN *join,
Prune some less promising partial plans. This heuristic may miss
the optimal QEPs, thus it results in a non-exhaustive search.
*/
if (prune_level == 1)
if (prune_level >= 1)
{
if (best_record_count > current_record_count ||
best_read_time > current_read_time ||
@@ -10288,7 +10445,8 @@ best_extension_by_limited_search(JOIN *join,
current_read_time,
search_depth - 1,
prune_level,
use_cond_selectivity);
use_cond_selectivity,
&found_eq_ref_tables);
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos->join_tab);
if ((int) best_res < (int) SEARCH_OK)
@@ -10336,6 +10494,7 @@ best_extension_by_limited_search(JOIN *join,
restore_prev_sj_state(remaining_tables, s, idx);
if (best_res == SEARCH_FOUND_EDGE)
{
if (pos+1 < sort_end) // If not last table
trace_one_table.add("pruned_by_hanging_leaf", true);
goto end;
}
@@ -10346,6 +10505,10 @@ best_extension_by_limited_search(JOIN *join,
end:
join->next_sort_position-= found_tables*2;
if (used_eq_ref_table)
*processed_eq_ref_tables|= used_eq_ref_table | found_eq_ref_tables;
else
*processed_eq_ref_tables= 0;
DBUG_RETURN(best_res);
}
@@ -29048,7 +29211,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
/* added_keyuse contents is copied, and it is no longer needed. */
delete_dynamic(&added_keyuse);
if (sort_and_filter_keyuse(thd, &keyuse, true))
if (sort_and_filter_keyuse(this, &keyuse, true))
return REOPT_ERROR;
optimize_keyuse(this, &keyuse);

View File

@@ -1261,6 +1261,8 @@ public:
table_map outer_join;
/* Bitmap of tables used in the select list items */
table_map select_list_used_tables;
/* Tables that have a possiblity to use EQ_ref */
table_map eq_ref_tables;
table_map allowed_top_level_tables;
ha_rows send_records,found_records,join_examined_rows, accepted_rows;
@@ -2432,7 +2434,7 @@ void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist)
double get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size);
double get_tmp_table_write_cost(THD *thd, double row_count, uint row_size);
void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
bool sort_and_filter_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse,
bool skip_unprefixed_keyparts);
struct st_cond_statistic

View File

@@ -2736,9 +2736,10 @@ static Sys_var_ulong Sys_optimizer_prune_level(
"Controls the heuristic(s) applied during query optimization to prune "
"less-promising partial plans from the optimizer search space. "
"Meaning: 0 - do not apply any heuristic, thus perform exhaustive "
"search; 1 - prune plans based on number of retrieved rows",
"search: 1 - prune plans based on cost and number of retrieved rows "
"eq_ref: 2 - prune also if we find an eq_ref chain",
SESSION_VAR(optimizer_prune_level), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, 1), DEFAULT(1), BLOCK_SIZE(1));
VALID_RANGE(0, 2), DEFAULT(2), BLOCK_SIZE(1));
static Sys_var_ulong Sys_optimizer_selectivity_sampling_limit(
"optimizer_selectivity_sampling_limit",