mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Post-merge post-merge fix (new error codes for fparser).
BitKeeper/etc/ignore: auto-union BitKeeper/etc/logging_ok: auto-union libmysqld/Makefile.am: Auto merged mysql-test/r/func_group.result: Auto merged mysql-test/r/subselect.result: Auto merged sql/Makefile.am: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/set_var.cc: Auto merged sql/sql_class.h: Auto merged sql/share/czech/errmsg.txt: Auto merged sql/share/danish/errmsg.txt: Auto merged sql/share/dutch/errmsg.txt: Auto merged sql/share/english/errmsg.txt: Auto merged sql/share/estonian/errmsg.txt: Auto merged sql/share/french/errmsg.txt: Auto merged sql/share/german/errmsg.txt: Auto merged sql/share/greek/errmsg.txt: Auto merged sql/share/hungarian/errmsg.txt: Auto merged sql/share/italian/errmsg.txt: Auto merged sql/share/japanese/errmsg.txt: Auto merged sql/share/korean/errmsg.txt: Auto merged sql/share/norwegian-ny/errmsg.txt: Auto merged sql/share/norwegian/errmsg.txt: Auto merged sql/share/polish/errmsg.txt: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_test.cc: Auto merged sql/structs.h: Auto merged sql/share/portuguese/errmsg.txt: Auto merged sql/share/romanian/errmsg.txt: Auto merged sql/share/russian/errmsg.txt: Auto merged sql/share/serbian/errmsg.txt: Auto merged sql/share/slovak/errmsg.txt: Auto merged sql/share/spanish/errmsg.txt: Auto merged sql/share/swedish/errmsg.txt: Auto merged sql/share/ukrainian/errmsg.txt: Auto merged
This commit is contained in:
@ -386,6 +386,7 @@ libmysqld/opt_ft.cc
|
||||
libmysqld/opt_range.cc
|
||||
libmysqld/opt_sum.cc
|
||||
libmysqld/pack.c
|
||||
libmysqld/parse_file.cc
|
||||
libmysqld/password.c
|
||||
libmysqld/procedure.cc
|
||||
libmysqld/protocol.cc
|
||||
|
@ -161,6 +161,7 @@ tim@sand.box
|
||||
tim@threads.polyesthetic.msg
|
||||
tim@white.box
|
||||
tim@work.mysql.com
|
||||
timour@mysql.com
|
||||
tom@basil-firewall.home.com
|
||||
tomas@mc05.(none)
|
||||
tonu@hundin.mysql.fi
|
||||
|
@ -121,6 +121,13 @@ extern int NEAR my_errno; /* Last error in mysys */
|
||||
#define MY_ERRNO_EDOM 33
|
||||
#define MY_ERRNO_ERANGE 34
|
||||
|
||||
/* Bits for get_date timeflag */
|
||||
#define GETDATE_DATE_TIME 1
|
||||
#define GETDATE_SHORT_DATE 2
|
||||
#define GETDATE_HHMMSSTIME 4
|
||||
#define GETDATE_GMT 8
|
||||
#define GETDATE_FIXEDLENGTH 16
|
||||
|
||||
/* defines when allocating data */
|
||||
#ifdef SAFEMALLOC
|
||||
#define my_malloc(SZ,FLAG) _mymalloc((SZ), __FILE__, __LINE__, FLAG )
|
||||
|
@ -349,4 +349,9 @@
|
||||
#define ER_SP_VARCOND_AFTER_CURSHNDLR 1330
|
||||
#define ER_SP_CURSOR_AFTER_HANDLER 1331
|
||||
#define ER_SP_CASE_NOT_FOUND 1332
|
||||
#define ER_ERROR_MESSAGES 333
|
||||
#define ER_FPARSER_TOO_BIG_FILE 1333
|
||||
#define ER_FPARSER_BAD_HEADER 1334
|
||||
#define ER_FPARSER_EOF_IN_COMMENT 1335
|
||||
#define ER_FPARSER_ERROR_IN_PARAMETER 1336
|
||||
#define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1337
|
||||
#define ER_ERROR_MESSAGES 338
|
||||
|
@ -58,7 +58,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
|
||||
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
|
||||
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
|
||||
spatial.cc gstream.cc sql_help.cc protocol_cursor.cc \
|
||||
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc
|
||||
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
|
||||
parse_file.cc
|
||||
|
||||
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
|
||||
libmysqld_a_SOURCES=
|
||||
|
@ -388,8 +388,8 @@ SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID;
|
||||
email shipcode
|
||||
test1@testdomain.com Z001
|
||||
test2@testdomain.com Z001
|
||||
test3@testdomain.com Z001
|
||||
test2@testdomain.com R002
|
||||
test3@testdomain.com Z001
|
||||
SELECT DISTINCTROW email FROM t1 ORDER BY dateentered DESC;
|
||||
email
|
||||
test1@testdomain.com
|
||||
|
@ -183,12 +183,12 @@ insert into t2 values('BBB', 20, 1.0);
|
||||
select t1.a1, t1.a2, t2.a1, t2.a2 from t1,t2;
|
||||
a1 a2 a1 a2
|
||||
10 aaa AAA 10
|
||||
10 NULL AAA 10
|
||||
10 bbb AAA 10
|
||||
20 zzz AAA 10
|
||||
10 aaa BBB 20
|
||||
10 NULL AAA 10
|
||||
10 NULL BBB 20
|
||||
10 bbb AAA 10
|
||||
10 bbb BBB 20
|
||||
20 zzz AAA 10
|
||||
20 zzz BBB 20
|
||||
select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9;
|
||||
max(t1.a1) max(t2.a1)
|
||||
|
657
mysql-test/r/greedy_optimizer.result
Normal file
657
mysql-test/r/greedy_optimizer.result
Normal file
@ -0,0 +1,657 @@
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7;
|
||||
create table t1 (
|
||||
c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer,
|
||||
primary key (c11)
|
||||
);
|
||||
create table t2 (
|
||||
c21 integer,c22 integer,c23 integer,c24 integer,c25 integer,c26 integer,
|
||||
);
|
||||
create table t3 (
|
||||
c31 integer,c32 integer,c33 integer,c34 integer,c35 integer,c36 integer,
|
||||
primary key (c31)
|
||||
);
|
||||
create table t4 (
|
||||
c41 integer,c42 integer,c43 integer,c44 integer,c45 integer,c46 integer
|
||||
);
|
||||
create table t5 (
|
||||
c51 integer,c52 integer,c53 integer,c54 integer,c55 integer,c56 integer,
|
||||
primary key (c51)
|
||||
);
|
||||
create table t6 (
|
||||
c61 integer,c62 integer,c63 integer,c64 integer,c65 integer,c66 integer
|
||||
);
|
||||
create table t7 (
|
||||
c71 integer,c72 integer,c73 integer,c74 integer,c75 integer,c76 integer,
|
||||
primary key (c71)
|
||||
);
|
||||
insert into t1 values (1,2,3,4,5,6);
|
||||
insert into t1 values (2,2,3,4,5,6);
|
||||
insert into t1 values (3,2,3,4,5,6);
|
||||
insert into t2 values (1,2,3,4,5,6);
|
||||
insert into t2 values (2,2,3,4,5,6);
|
||||
insert into t2 values (3,2,3,4,5,6);
|
||||
insert into t2 values (4,2,3,4,5,6);
|
||||
insert into t2 values (5,2,3,4,5,6);
|
||||
insert into t2 values (6,2,3,4,5,6);
|
||||
insert into t3 values (1,2,3,4,5,6);
|
||||
insert into t3 values (2,2,3,4,5,6);
|
||||
insert into t3 values (3,2,3,4,5,6);
|
||||
insert into t3 values (4,2,3,4,5,6);
|
||||
insert into t3 values (5,2,3,4,5,6);
|
||||
insert into t3 values (6,2,3,4,5,6);
|
||||
insert into t3 values (7,2,3,4,5,6);
|
||||
insert into t3 values (8,2,3,4,5,6);
|
||||
insert into t3 values (9,2,3,4,5,6);
|
||||
insert into t4 values (1,2,3,4,5,6);
|
||||
insert into t4 values (2,2,3,4,5,6);
|
||||
insert into t4 values (3,2,3,4,5,6);
|
||||
insert into t4 values (4,2,3,4,5,6);
|
||||
insert into t4 values (5,2,3,4,5,6);
|
||||
insert into t4 values (6,2,3,4,5,6);
|
||||
insert into t4 values (7,2,3,4,5,6);
|
||||
insert into t4 values (8,2,3,4,5,6);
|
||||
insert into t4 values (9,2,3,4,5,6);
|
||||
insert into t4 values (10,2,3,4,5,6);
|
||||
insert into t4 values (11,2,3,4,5,6);
|
||||
insert into t4 values (12,2,3,4,5,6);
|
||||
insert into t5 values (1,2,3,4,5,6);
|
||||
insert into t5 values (2,2,3,4,5,6);
|
||||
insert into t5 values (3,2,3,4,5,6);
|
||||
insert into t5 values (4,2,3,4,5,6);
|
||||
insert into t5 values (5,2,3,4,5,6);
|
||||
insert into t5 values (6,2,3,4,5,6);
|
||||
insert into t5 values (7,2,3,4,5,6);
|
||||
insert into t5 values (8,2,3,4,5,6);
|
||||
insert into t5 values (9,2,3,4,5,6);
|
||||
insert into t5 values (10,2,3,4,5,6);
|
||||
insert into t5 values (11,2,3,4,5,6);
|
||||
insert into t5 values (12,2,3,4,5,6);
|
||||
insert into t5 values (13,2,3,4,5,6);
|
||||
insert into t5 values (14,2,3,4,5,6);
|
||||
insert into t5 values (15,2,3,4,5,6);
|
||||
insert into t6 values (1,2,3,4,5,6);
|
||||
insert into t6 values (2,2,3,4,5,6);
|
||||
insert into t6 values (3,2,3,4,5,6);
|
||||
insert into t6 values (4,2,3,4,5,6);
|
||||
insert into t6 values (5,2,3,4,5,6);
|
||||
insert into t6 values (6,2,3,4,5,6);
|
||||
insert into t6 values (7,2,3,4,5,6);
|
||||
insert into t6 values (8,2,3,4,5,6);
|
||||
insert into t6 values (9,2,3,4,5,6);
|
||||
insert into t6 values (10,2,3,4,5,6);
|
||||
insert into t6 values (11,2,3,4,5,6);
|
||||
insert into t6 values (12,2,3,4,5,6);
|
||||
insert into t6 values (13,2,3,4,5,6);
|
||||
insert into t6 values (14,2,3,4,5,6);
|
||||
insert into t6 values (15,2,3,4,5,6);
|
||||
insert into t6 values (16,2,3,4,5,6);
|
||||
insert into t6 values (17,2,3,4,5,6);
|
||||
insert into t6 values (18,2,3,4,5,6);
|
||||
insert into t7 values (1,2,3,4,5,6);
|
||||
insert into t7 values (2,2,3,4,5,6);
|
||||
insert into t7 values (3,2,3,4,5,6);
|
||||
insert into t7 values (4,2,3,4,5,6);
|
||||
insert into t7 values (5,2,3,4,5,6);
|
||||
insert into t7 values (6,2,3,4,5,6);
|
||||
insert into t7 values (7,2,3,4,5,6);
|
||||
insert into t7 values (8,2,3,4,5,6);
|
||||
insert into t7 values (9,2,3,4,5,6);
|
||||
insert into t7 values (10,2,3,4,5,6);
|
||||
insert into t7 values (11,2,3,4,5,6);
|
||||
insert into t7 values (12,2,3,4,5,6);
|
||||
insert into t7 values (13,2,3,4,5,6);
|
||||
insert into t7 values (14,2,3,4,5,6);
|
||||
insert into t7 values (15,2,3,4,5,6);
|
||||
insert into t7 values (16,2,3,4,5,6);
|
||||
insert into t7 values (17,2,3,4,5,6);
|
||||
insert into t7 values (18,2,3,4,5,6);
|
||||
insert into t7 values (19,2,3,4,5,6);
|
||||
insert into t7 values (20,2,3,4,5,6);
|
||||
insert into t7 values (21,2,3,4,5,6);
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
62
|
||||
select @@heuristic;
|
||||
@@heuristic
|
||||
1
|
||||
set plan_search_depth=63;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
63
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
set heuristic=0;
|
||||
select @@heuristic;
|
||||
@@heuristic
|
||||
0
|
||||
set plan_search_depth=0;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
0
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
set plan_search_depth=1;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
1
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
set plan_search_depth=62;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
62
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 274.419727
|
||||
set heuristic=1;
|
||||
select @@heuristic;
|
||||
@@heuristic
|
||||
1
|
||||
set plan_search_depth=0;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
0
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
set plan_search_depth=1;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
1
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
set plan_search_depth=62;
|
||||
select @@plan_search_depth;
|
||||
@@plan_search_depth
|
||||
62
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 821.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
|
||||
1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
|
||||
1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
|
||||
1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
|
||||
1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
|
||||
show status like 'Last_query_cost';
|
||||
Variable_name Value
|
||||
Last_query_cost 794.838037
|
||||
drop table t1,t2,t3,t4,t5,t6,t7;
|
@ -1393,8 +1393,8 @@ companynr companynr
|
||||
41 40
|
||||
explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using temporary
|
||||
1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using where; Using index
|
||||
1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
|
||||
select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008;
|
||||
fld1 companynr fld3 period
|
||||
038008 37 reporters 1008
|
||||
@ -2314,8 +2314,8 @@ left join t4 on id3 = id4 where id2 = 1 or id4 = 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t3 system NULL NULL NULL NULL 0 const row not found
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 1
|
||||
1 SIMPLE t4 ALL id4 NULL NULL NULL 1 Using where
|
||||
1 SIMPLE t4 ALL id4 NULL NULL NULL 1
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 1 Using where
|
||||
select * from t1 left join t2 on id1 = id2 left join t3 on id1 = id3
|
||||
left join t4 on id3 = id4 where id2 = 1 or id4 = 1;
|
||||
id1 id2 id3 id4 id44
|
||||
|
@ -1348,8 +1348,8 @@ a
|
||||
explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
|
||||
2 DEPENDENT SUBQUERY t1 ref a a 5 func 1001 Using where; Using index
|
||||
2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index
|
||||
2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using index
|
||||
2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 1000 Using where; Using index
|
||||
Warnings:
|
||||
Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(select 1 AS `Not_used` from test.t1 join test.t3 where ((test.t1.b = test.t3.a) and (<cache>(test.t2.a) = test.t1.a))))
|
||||
insert into t1 values (3,31);
|
||||
|
313
mysql-test/t/greedy_optimizer.test
Normal file
313
mysql-test/t/greedy_optimizer.test
Normal file
@ -0,0 +1,313 @@
|
||||
#
|
||||
# A simple test of the greedy query optimization algorithm and the switches that
|
||||
# control the optimizationprocess.
|
||||
#
|
||||
|
||||
#
|
||||
# Schema
|
||||
#
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7;
|
||||
--enable_warnings
|
||||
|
||||
create table t1 (
|
||||
c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer,
|
||||
primary key (c11)
|
||||
);
|
||||
create table t2 (
|
||||
c21 integer,c22 integer,c23 integer,c24 integer,c25 integer,c26 integer,
|
||||
);
|
||||
create table t3 (
|
||||
c31 integer,c32 integer,c33 integer,c34 integer,c35 integer,c36 integer,
|
||||
primary key (c31)
|
||||
);
|
||||
create table t4 (
|
||||
c41 integer,c42 integer,c43 integer,c44 integer,c45 integer,c46 integer
|
||||
);
|
||||
create table t5 (
|
||||
c51 integer,c52 integer,c53 integer,c54 integer,c55 integer,c56 integer,
|
||||
primary key (c51)
|
||||
);
|
||||
create table t6 (
|
||||
c61 integer,c62 integer,c63 integer,c64 integer,c65 integer,c66 integer
|
||||
);
|
||||
create table t7 (
|
||||
c71 integer,c72 integer,c73 integer,c74 integer,c75 integer,c76 integer,
|
||||
primary key (c71)
|
||||
);
|
||||
|
||||
#
|
||||
# Data
|
||||
# cardinality(Ti) = cardinality(T(i-1)) + 3
|
||||
#
|
||||
insert into t1 values (1,2,3,4,5,6);
|
||||
insert into t1 values (2,2,3,4,5,6);
|
||||
insert into t1 values (3,2,3,4,5,6);
|
||||
|
||||
insert into t2 values (1,2,3,4,5,6);
|
||||
insert into t2 values (2,2,3,4,5,6);
|
||||
insert into t2 values (3,2,3,4,5,6);
|
||||
insert into t2 values (4,2,3,4,5,6);
|
||||
insert into t2 values (5,2,3,4,5,6);
|
||||
insert into t2 values (6,2,3,4,5,6);
|
||||
|
||||
insert into t3 values (1,2,3,4,5,6);
|
||||
insert into t3 values (2,2,3,4,5,6);
|
||||
insert into t3 values (3,2,3,4,5,6);
|
||||
insert into t3 values (4,2,3,4,5,6);
|
||||
insert into t3 values (5,2,3,4,5,6);
|
||||
insert into t3 values (6,2,3,4,5,6);
|
||||
insert into t3 values (7,2,3,4,5,6);
|
||||
insert into t3 values (8,2,3,4,5,6);
|
||||
insert into t3 values (9,2,3,4,5,6);
|
||||
|
||||
insert into t4 values (1,2,3,4,5,6);
|
||||
insert into t4 values (2,2,3,4,5,6);
|
||||
insert into t4 values (3,2,3,4,5,6);
|
||||
insert into t4 values (4,2,3,4,5,6);
|
||||
insert into t4 values (5,2,3,4,5,6);
|
||||
insert into t4 values (6,2,3,4,5,6);
|
||||
insert into t4 values (7,2,3,4,5,6);
|
||||
insert into t4 values (8,2,3,4,5,6);
|
||||
insert into t4 values (9,2,3,4,5,6);
|
||||
insert into t4 values (10,2,3,4,5,6);
|
||||
insert into t4 values (11,2,3,4,5,6);
|
||||
insert into t4 values (12,2,3,4,5,6);
|
||||
|
||||
insert into t5 values (1,2,3,4,5,6);
|
||||
insert into t5 values (2,2,3,4,5,6);
|
||||
insert into t5 values (3,2,3,4,5,6);
|
||||
insert into t5 values (4,2,3,4,5,6);
|
||||
insert into t5 values (5,2,3,4,5,6);
|
||||
insert into t5 values (6,2,3,4,5,6);
|
||||
insert into t5 values (7,2,3,4,5,6);
|
||||
insert into t5 values (8,2,3,4,5,6);
|
||||
insert into t5 values (9,2,3,4,5,6);
|
||||
insert into t5 values (10,2,3,4,5,6);
|
||||
insert into t5 values (11,2,3,4,5,6);
|
||||
insert into t5 values (12,2,3,4,5,6);
|
||||
insert into t5 values (13,2,3,4,5,6);
|
||||
insert into t5 values (14,2,3,4,5,6);
|
||||
insert into t5 values (15,2,3,4,5,6);
|
||||
|
||||
insert into t6 values (1,2,3,4,5,6);
|
||||
insert into t6 values (2,2,3,4,5,6);
|
||||
insert into t6 values (3,2,3,4,5,6);
|
||||
insert into t6 values (4,2,3,4,5,6);
|
||||
insert into t6 values (5,2,3,4,5,6);
|
||||
insert into t6 values (6,2,3,4,5,6);
|
||||
insert into t6 values (7,2,3,4,5,6);
|
||||
insert into t6 values (8,2,3,4,5,6);
|
||||
insert into t6 values (9,2,3,4,5,6);
|
||||
insert into t6 values (10,2,3,4,5,6);
|
||||
insert into t6 values (11,2,3,4,5,6);
|
||||
insert into t6 values (12,2,3,4,5,6);
|
||||
insert into t6 values (13,2,3,4,5,6);
|
||||
insert into t6 values (14,2,3,4,5,6);
|
||||
insert into t6 values (15,2,3,4,5,6);
|
||||
insert into t6 values (16,2,3,4,5,6);
|
||||
insert into t6 values (17,2,3,4,5,6);
|
||||
insert into t6 values (18,2,3,4,5,6);
|
||||
|
||||
insert into t7 values (1,2,3,4,5,6);
|
||||
insert into t7 values (2,2,3,4,5,6);
|
||||
insert into t7 values (3,2,3,4,5,6);
|
||||
insert into t7 values (4,2,3,4,5,6);
|
||||
insert into t7 values (5,2,3,4,5,6);
|
||||
insert into t7 values (6,2,3,4,5,6);
|
||||
insert into t7 values (7,2,3,4,5,6);
|
||||
insert into t7 values (8,2,3,4,5,6);
|
||||
insert into t7 values (9,2,3,4,5,6);
|
||||
insert into t7 values (10,2,3,4,5,6);
|
||||
insert into t7 values (11,2,3,4,5,6);
|
||||
insert into t7 values (12,2,3,4,5,6);
|
||||
insert into t7 values (13,2,3,4,5,6);
|
||||
insert into t7 values (14,2,3,4,5,6);
|
||||
insert into t7 values (15,2,3,4,5,6);
|
||||
insert into t7 values (16,2,3,4,5,6);
|
||||
insert into t7 values (17,2,3,4,5,6);
|
||||
insert into t7 values (18,2,3,4,5,6);
|
||||
insert into t7 values (19,2,3,4,5,6);
|
||||
insert into t7 values (20,2,3,4,5,6);
|
||||
insert into t7 values (21,2,3,4,5,6);
|
||||
|
||||
#
|
||||
# The actual test begins here
|
||||
#
|
||||
|
||||
# Check the default values for the optimizer paramters
|
||||
|
||||
select @@plan_search_depth;
|
||||
select @@heuristic;
|
||||
|
||||
-- This value swithes back to the old implementation of 'find_best()'
|
||||
-- set plan_search_depth=63; - old (independent of the heuristic)
|
||||
--
|
||||
-- These are the values for the parameters that control the greedy optimizer
|
||||
-- (total 6 combinations - 3 for plan_search_depth, 2 for heuristic):
|
||||
--
|
||||
-- set plan_search_depth=0; - automatic
|
||||
-- set plan_search_depth=1; - min
|
||||
-- set plan_search_depth=62; - max (default)
|
||||
--
|
||||
-- set heuristic=0 - exhaustive;
|
||||
-- set heuristic=1 - heuristic; -- default
|
||||
|
||||
|
||||
#
|
||||
# Compile several queries with all combinations of the query
|
||||
# optimizer parameters. Each test query has two variants, where
|
||||
# in the second variant the tables in the FROM clause are in
|
||||
# inverse order to the tables in the first variant.
|
||||
# Due to pre-sorting of tables before compilation, there should
|
||||
# be no difference in the plans for each two such query variants.
|
||||
#
|
||||
|
||||
# First, for reference compile the test queries with the 'old' optimization
|
||||
# procedure 'find_best'. Notice that 'find_best' does not depend on the
|
||||
# choice of heuristic.
|
||||
|
||||
set plan_search_depth=63;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
|
||||
# Test the new optimization procedures
|
||||
|
||||
set heuristic=0;
|
||||
select @@heuristic;
|
||||
|
||||
set plan_search_depth=0;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
set plan_search_depth=1;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
set plan_search_depth=62;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
|
||||
set heuristic=1;
|
||||
select @@heuristic;
|
||||
|
||||
set plan_search_depth=0;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
set plan_search_depth=1;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
set plan_search_depth=62;
|
||||
select @@plan_search_depth;
|
||||
|
||||
-- 6-table join, chain
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, star
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
|
||||
show status like 'Last_query_cost';
|
||||
-- 6-table join, clique
|
||||
explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
|
||||
show status like 'Last_query_cost';
|
||||
|
||||
drop table t1,t2,t3,t4,t5,t6,t7;
|
@ -19,11 +19,20 @@
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
If flag & 1 Return date and time
|
||||
If flag & 2 Return short date format YYMMDD
|
||||
if flag & 4 Return time in HHMMDD format.
|
||||
*/
|
||||
/*
|
||||
get date as string
|
||||
|
||||
SYNOPSIS
|
||||
get_date()
|
||||
to - string where date will be written
|
||||
flag - format of date:
|
||||
If flag & GETDATE_TIME Return date and time
|
||||
If flag & GETDATE_SHORT_DATE Return short date format YYMMDD
|
||||
If flag & GETDATE_HHMMSSTIME Return time in HHMMDD format.
|
||||
If flag & GETDATE_GMT Date/time in GMT
|
||||
If flag & GETDATE_FIXEDLENGTH Return fixed length date/time
|
||||
date - for conversion
|
||||
*/
|
||||
|
||||
|
||||
void get_date(register my_string to, int flag, time_t date)
|
||||
@ -36,27 +45,36 @@ void get_date(register my_string to, int flag, time_t date)
|
||||
|
||||
skr=date ? (time_t) date : time((time_t*) 0);
|
||||
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
|
||||
localtime_r(&skr,&tm_tmp);
|
||||
if (flag & GETDATE_GMT)
|
||||
localtime_r(&skr,&tm_tmp);
|
||||
else
|
||||
gmtime_r(&skr,&tm_tmp);
|
||||
start_time= &tm_tmp;
|
||||
#else
|
||||
start_time=localtime(&skr);
|
||||
if (flag & GETDATE_GMT)
|
||||
start_time= localtime(&skr);
|
||||
else
|
||||
gmtime(&skr,&tm_tmp);
|
||||
#endif
|
||||
if (flag & 2)
|
||||
if (flag & GETDATE_SHORT_DATE)
|
||||
sprintf(to,"%02d%02d%02d",
|
||||
start_time->tm_year % 100,
|
||||
start_time->tm_mon+1,
|
||||
start_time->tm_mday);
|
||||
else
|
||||
sprintf(to,"%d-%02d-%02d",
|
||||
sprintf(to, ((flag & GETDATE_FIXEDLENGTH) ?
|
||||
"%4d-%02d-%02d" : "%d-%02d-%02d"),
|
||||
start_time->tm_year+1900,
|
||||
start_time->tm_mon+1,
|
||||
start_time->tm_mday);
|
||||
if (flag & 1)
|
||||
sprintf(strend(to)," %2d:%02d:%02d",
|
||||
if (flag & GETDATE_DATE_TIME)
|
||||
sprintf(strend(to),
|
||||
((flag & GETDATE_FIXEDLENGTH) ?
|
||||
" %02d:%02d:%02d" : " %2d:%02d:%02d"),
|
||||
start_time->tm_hour,
|
||||
start_time->tm_min,
|
||||
start_time->tm_sec);
|
||||
else if (flag & 4)
|
||||
else if (flag & GETDATE_HHMMSSTIME)
|
||||
sprintf(strend(to),"%02d%02d%02d",
|
||||
start_time->tm_hour,
|
||||
start_time->tm_min,
|
||||
|
@ -59,7 +59,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
||||
stacktrace.h sql_sort.h sql_cache.h set_var.h \
|
||||
spatial.h gstream.h client_settings.h \
|
||||
examples/ha_example.h \
|
||||
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h
|
||||
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
|
||||
parse_file.h
|
||||
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
|
||||
@ -91,7 +92,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
||||
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
|
||||
examples/ha_example.cc \
|
||||
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
|
||||
sp_cache.cc
|
||||
sp_cache.cc parse_file.cc
|
||||
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||
|
||||
|
@ -375,6 +375,7 @@ inline THD *_current_thd(void)
|
||||
#include "sql_list.h"
|
||||
#include "sql_map.h"
|
||||
#include "handler.h"
|
||||
#include "parse_file.h"
|
||||
#include "table.h"
|
||||
#include "field.h" /* Field definitions */
|
||||
#include "protocol.h"
|
||||
@ -787,6 +788,8 @@ extern "C" pthread_handler_decl(handle_manager, arg);
|
||||
void print_where(COND *cond,const char *info);
|
||||
void print_cached_tables(void);
|
||||
void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
|
||||
void print_plan(JOIN* join, double read_time, double record_count,
|
||||
uint idx, const char *info);
|
||||
#endif
|
||||
void mysql_print_status(THD *thd);
|
||||
/* key.cc */
|
||||
@ -854,6 +857,7 @@ extern char language[LIBLEN],reg_ext[FN_EXTLEN];
|
||||
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
|
||||
extern char pidfile_name[FN_REFLEN], time_zone[30], *opt_init_file;
|
||||
extern char log_error_file[FN_REFLEN];
|
||||
extern double last_query_cost;
|
||||
extern double log_10[32];
|
||||
extern ulonglong log_10_int[20];
|
||||
extern ulonglong keybuff_size;
|
||||
|
@ -312,6 +312,7 @@ ulong expire_logs_days = 0;
|
||||
ulong rpl_recovery_rank=0;
|
||||
ulong my_bind_addr; /* the address we bind to */
|
||||
volatile ulong cached_thread_count= 0;
|
||||
double last_query_cost= -1; /* -1 denotes that no query was compiled yet */
|
||||
|
||||
double log_10[32]; /* 10 potences */
|
||||
ulonglong log_10_int[20]=
|
||||
@ -3775,7 +3776,9 @@ enum options_mysqld
|
||||
OPT_DATE_FORMAT,
|
||||
OPT_TIME_FORMAT,
|
||||
OPT_DATETIME_FORMAT,
|
||||
OPT_LOG_QUERIES_NOT_USING_INDEXES
|
||||
OPT_LOG_QUERIES_NOT_USING_INDEXES,
|
||||
OPT_PLAN_SEARCH_DEPTH,
|
||||
OPT_HEURISTIC
|
||||
};
|
||||
|
||||
|
||||
@ -4400,6 +4403,11 @@ log and this option does nothing anymore.",
|
||||
"Use stopwords from this file instead of built-in list.",
|
||||
(gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR,
|
||||
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"heuristic", OPT_HEURISTIC,
|
||||
"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 rows and read time.",
|
||||
(gptr*) &global_system_variables.heuristic,
|
||||
(gptr*) &max_system_variables.heuristic,
|
||||
0, GET_ULONG, OPT_ARG, 1, 0, 1, 0, 1, 0},
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
{"innodb_mirrored_log_groups", OPT_INNODB_MIRRORED_LOG_GROUPS,
|
||||
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
|
||||
@ -4640,6 +4648,11 @@ The minimum value for this variable is 4096.",
|
||||
"If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.",
|
||||
(gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,
|
||||
REQUIRED_ARG, 0, 0, OS_FILE_LIMIT, 0, 1, 0},
|
||||
{"plan_search_depth", OPT_PLAN_SEARCH_DEPTH,
|
||||
"Maximum depth of search performed by the query optimizer. Values larger than the number of relations in a query result in better query plans, but take longer to compile a query. Smaller values than the number of tables in a relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to MAX_TABLES+2, the optimizer will switch to the original find_best (used for testing/comparison).",
|
||||
(gptr*) &global_system_variables.plan_search_depth,
|
||||
(gptr*) &max_system_variables.plan_search_depth,
|
||||
0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0},
|
||||
{"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE,
|
||||
"The size of the buffer that is allocated when preloading indexes",
|
||||
(gptr*) &global_system_variables.preload_buff_size,
|
||||
@ -4930,6 +4943,7 @@ struct show_var_st status_vars[]= {
|
||||
SHOW_KEY_CACHE_LONG},
|
||||
{"Key_writes", (char*) &dflt_key_cache_var.global_cache_write,
|
||||
SHOW_KEY_CACHE_LONG},
|
||||
{"Last_query_cost", (char*) &last_query_cost, SHOW_DOUBLE},
|
||||
{"Max_used_connections", (char*) &max_used_connections, SHOW_LONG},
|
||||
{"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST},
|
||||
{"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST},
|
||||
|
785
sql/parse_file.cc
Normal file
785
sql/parse_file.cc
Normal file
@ -0,0 +1,785 @@
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
// Text .frm files management routines
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include <errno.h>
|
||||
#include <m_ctype.h>
|
||||
#include <my_sys.h>
|
||||
#include <my_dir.h>
|
||||
|
||||
|
||||
/*
|
||||
write string with escaping
|
||||
|
||||
SYNOPSIS
|
||||
write_escaped_string()
|
||||
file - IO_CACHE for record
|
||||
val_s - string for writing
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
static my_bool
|
||||
write_escaped_string(IO_CACHE *file, LEX_STRING *val_s)
|
||||
{
|
||||
char *eos= val_s->str + val_s->length;
|
||||
char *ptr= val_s->str;
|
||||
|
||||
for (; ptr < eos; ptr++)
|
||||
{
|
||||
/*
|
||||
Should be in sync with read_escaped_string() and
|
||||
parse_quated_escaped_string()
|
||||
*/
|
||||
switch(*ptr) {
|
||||
case '\\': // escape character
|
||||
if (my_b_write(file, "\\\\", 2))
|
||||
return TRUE;
|
||||
break;
|
||||
case '\n': // parameter value delimiter
|
||||
if (my_b_write(file, "\\n", 2))
|
||||
return TRUE;
|
||||
break;
|
||||
case '\0': // problem for some string processing utilites
|
||||
if (my_b_write(file, "\\0", 2))
|
||||
return TRUE;
|
||||
break;
|
||||
case 26: // problem for windows utilites (Ctrl-Z)
|
||||
if (my_b_write(file, "\\z", 2))
|
||||
return TRUE;
|
||||
break;
|
||||
case '\'': // list of string delimiter
|
||||
if (my_b_write(file, "\\\'", 2))
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
if (my_b_write(file, ptr, 1))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
write parameter value to IO_CACHE
|
||||
|
||||
SYNOPSIS
|
||||
write_parameter()
|
||||
file pointer to IO_CACHE structure for writing
|
||||
base pointer to data structure
|
||||
parameter pointer to parameter descriptor
|
||||
old_version for returning back old version number value
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
static my_bool
|
||||
write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
|
||||
ulonglong *old_version)
|
||||
{
|
||||
char num_buf[20]; // buffer for numeric operations
|
||||
// string for numeric operations
|
||||
String num(num_buf, sizeof(num_buf), &my_charset_bin);
|
||||
DBUG_ENTER("write_parameter");
|
||||
|
||||
switch (parameter->type) {
|
||||
case FILE_OPTIONS_STRING:
|
||||
{
|
||||
LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
|
||||
if (my_b_write(file, val_s->str, val_s->length))
|
||||
DBUG_RETURN(TRUE);
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_ESTRING:
|
||||
{
|
||||
if (write_escaped_string(file, (LEX_STRING *)(base + parameter->offset)))
|
||||
DBUG_RETURN(TRUE);
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_ULONGLONG:
|
||||
{
|
||||
num.set(*((ulonglong *)(base + parameter->offset)), &my_charset_bin);
|
||||
if (my_b_write(file, num.ptr(), num.length()))
|
||||
DBUG_RETURN(TRUE);
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_REV:
|
||||
{
|
||||
ulonglong *val_i= (ulonglong *)(base + parameter->offset);
|
||||
*old_version= (*val_i)++;
|
||||
num.set(*val_i, &my_charset_bin);
|
||||
if (my_b_write(file, num.ptr(), num.length()))
|
||||
DBUG_RETURN(TRUE);
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_TIMESTAMP:
|
||||
{
|
||||
/* string have to be allocated already */
|
||||
LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
|
||||
time_t tm= time(NULL);
|
||||
|
||||
get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH,
|
||||
tm);
|
||||
val_s->length= PARSE_FILE_TIMESTAMPLENGTH;
|
||||
if (my_b_write(file, val_s->str, PARSE_FILE_TIMESTAMPLENGTH))
|
||||
DBUG_RETURN(TRUE);
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_STRLIST:
|
||||
{
|
||||
List_iterator_fast<LEX_STRING> it(*((List<LEX_STRING>*)
|
||||
(base + parameter->offset)));
|
||||
bool first= 1;
|
||||
LEX_STRING *str;
|
||||
while ((str= it++))
|
||||
{
|
||||
num.set((ulonglong)str->length, &my_charset_bin);
|
||||
// ',' after string to detect list continuation
|
||||
if ((!first && my_b_write(file, " ", 1)) ||
|
||||
my_b_write(file, "\'", 1) ||
|
||||
my_b_write(file, str->str, str->length) ||
|
||||
my_b_write(file, "\'", 1))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
first= 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBUG_ASSERT(0); // never should happened
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
write new .frm
|
||||
|
||||
SYNOPSIS
|
||||
sql_create_definition_file()
|
||||
dir directory where put .frm
|
||||
file .frm file name
|
||||
type .frm type string (VIEW, TABLE)
|
||||
base base address for parameter reading (structure like
|
||||
TABLE)
|
||||
parameters parameters description
|
||||
max_versions number of versions to save
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
my_bool
|
||||
sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
|
||||
const LEX_STRING *type,
|
||||
gptr base, File_option *parameters,
|
||||
uint max_versions)
|
||||
{
|
||||
File handler;
|
||||
IO_CACHE file;
|
||||
char path[FN_REFLEN+1]; // +1 to put temporary file name for sure
|
||||
ulonglong old_version= ULONGLONG_MAX;
|
||||
int path_end;
|
||||
DBUG_ENTER("sql_create_definition_file");
|
||||
DBUG_PRINT("enter", ("Dir: %s, file: %s, base 0x%lx",
|
||||
dir->str, file_name->str, (ulong) base));
|
||||
|
||||
fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME);
|
||||
path_end= strlen(path);
|
||||
|
||||
// temporary file name
|
||||
path[path_end]='~';
|
||||
path[path_end+1]= '\0';
|
||||
if ((handler= my_create(path, CREATE_MODE, O_RDWR | O_TRUNC,
|
||||
MYF(MY_WME))) <= 0)
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
if (init_io_cache(&file, handler, 0, SEQ_READ_APPEND, 0L, 0, MYF(MY_WME)))
|
||||
goto err_w_file;
|
||||
|
||||
// write header (file signature)
|
||||
if (my_b_write(&file, "TYPE=", 5) ||
|
||||
my_b_write(&file, type->str, type->length) ||
|
||||
my_b_write(&file, "\n", 1))
|
||||
goto err_w_file;
|
||||
|
||||
// write parameters to temporary file
|
||||
for (File_option *param= parameters; param->name.str; param++)
|
||||
{
|
||||
if (my_b_write(&file, param->name.str, param->name.length) ||
|
||||
my_b_write(&file, "=", 1) ||
|
||||
write_parameter(&file, base, param, &old_version) ||
|
||||
my_b_write(&file, "\n", 1))
|
||||
goto err_w_cache;
|
||||
}
|
||||
|
||||
if (end_io_cache(&file))
|
||||
goto err_w_file;
|
||||
|
||||
if (my_close(handler, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
// archive copies management
|
||||
path[path_end]='\0';
|
||||
if (!access(path, F_OK))
|
||||
{
|
||||
if (old_version != ULONGLONG_MAX && max_versions != 0)
|
||||
{
|
||||
// save buckup
|
||||
char path_arc[FN_REFLEN];
|
||||
// backup old version
|
||||
char path_to[FN_REFLEN];
|
||||
|
||||
// check archive directory existence
|
||||
fn_format(path_arc, "arc", dir->str, "", MY_UNPACK_FILENAME);
|
||||
if (access(path_arc, F_OK))
|
||||
{
|
||||
if (my_mkdir(path_arc, 0777, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lld",
|
||||
path_arc, file_name->str, old_version);
|
||||
if (my_rename(path, path_to, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
// remove very old version
|
||||
if (old_version > max_versions)
|
||||
{
|
||||
my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lld",
|
||||
path_arc, file_name->str,
|
||||
old_version - max_versions);
|
||||
if (!access(path_arc, F_OK) && my_delete(path_to, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (my_delete(path, MYF(MY_WME))) // no backups
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// rename temporary file
|
||||
char path_to[FN_REFLEN];
|
||||
memcpy(path_to, path, path_end+1);
|
||||
path[path_end]='~';
|
||||
if (my_rename(path, path_to, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
err_w_cache:
|
||||
end_io_cache(&file);
|
||||
err_w_file:
|
||||
my_close(handler, MYF(MY_WME));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Prepare frm to parse (read to memory)
|
||||
|
||||
SYNOPSIS
|
||||
sql_parse_prepare()
|
||||
file_name - path & filename to .frm file
|
||||
mem_root - MEM_ROOT for buffer allocation
|
||||
bad_format_errors - send errors on bad content
|
||||
|
||||
RETURN
|
||||
0 - error
|
||||
parser object
|
||||
|
||||
NOTE
|
||||
returned pointer + 1 will be type of .frm
|
||||
*/
|
||||
|
||||
File_parser *
|
||||
sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
|
||||
bool bad_format_errors)
|
||||
{
|
||||
MY_STAT stat_info;
|
||||
uint len;
|
||||
char *end, *sign;
|
||||
File_parser *parser;
|
||||
File file;
|
||||
DBUG_ENTER("sql__parse_prepare");
|
||||
|
||||
if (!my_stat(file_name->str, &stat_info, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (stat_info.st_size > INT_MAX-1)
|
||||
{
|
||||
my_error(ER_FPARSER_TOO_BIG_FILE, MYF(0), file_name->str);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (!(parser= new(mem_root) File_parser))
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (!(parser->buff= alloc_root(mem_root, stat_info.st_size+1)))
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if ((file= my_open(file_name->str, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if ((len= my_read(file, parser->buff, stat_info.st_size, MYF(MY_WME))) ==
|
||||
MY_FILE_ERROR)
|
||||
{
|
||||
my_close(file, MYF(MY_WME));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (my_close(file, MYF(MY_WME)))
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
end= parser->end= parser->buff + len;
|
||||
*end= '\0'; // barriaer for more simple parsing
|
||||
|
||||
// 7 = 5 (TYPE=) + 1 (leter at least of type name) + 1 ('\n')
|
||||
if (len < 7 ||
|
||||
parser->buff[0] != 'T' ||
|
||||
parser->buff[1] != 'Y' ||
|
||||
parser->buff[2] != 'P' ||
|
||||
parser->buff[3] != 'E' ||
|
||||
parser->buff[4] != '=')
|
||||
goto frm_error;
|
||||
|
||||
// skip signature;
|
||||
parser->file_type.str= sign= parser->buff + 5;
|
||||
while (*sign >= 'A' && *sign <= 'Z' && sign < end)
|
||||
sign++;
|
||||
if (*sign != '\n')
|
||||
goto frm_error;
|
||||
parser->file_type.length= sign - parser->file_type.str;
|
||||
// EOS for file signature just for safety
|
||||
*sign= '\0';
|
||||
|
||||
parser->start= sign + 1;
|
||||
parser->content_ok= 1;
|
||||
|
||||
DBUG_RETURN(parser);
|
||||
|
||||
frm_error:
|
||||
if (bad_format_errors)
|
||||
{
|
||||
my_error(ER_FPARSER_BAD_HEADER, MYF(0), file_name->str);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else
|
||||
DBUG_RETURN(parser); // upper level have to check parser->ok()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
parse LEX_STRING
|
||||
|
||||
SYNOPSIS
|
||||
parse_string()
|
||||
ptr - pointer on string beginning
|
||||
end - pointer on symbol after parsed string end (still owned
|
||||
by buffer and can be accessed
|
||||
mem_root - MEM_ROOT for parameter allocation
|
||||
str - pointer on string, where results should be stored
|
||||
|
||||
RETURN
|
||||
0 - error
|
||||
# - pointer on symbol after string
|
||||
*/
|
||||
|
||||
static char *
|
||||
parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
|
||||
{
|
||||
// get string length
|
||||
char *eol= strchr(ptr, '\n');
|
||||
|
||||
if (eol >= end)
|
||||
return 0;
|
||||
|
||||
str->length= eol - ptr;
|
||||
|
||||
if (!(str->str= alloc_root(mem_root, str->length+1)))
|
||||
return 0;
|
||||
|
||||
memcpy(str->str, ptr, str->length);
|
||||
str->str[str->length]= '\0'; // just for safety
|
||||
return eol+1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
read escaped string from ptr to eol in already allocated str
|
||||
|
||||
SYNOPSIS
|
||||
parse_escaped_string()
|
||||
ptr - pointer on string beginning
|
||||
eol - pointer on character after end of string
|
||||
str - target string
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
my_bool
|
||||
read_escaped_string(char *ptr, char *eol, LEX_STRING *str)
|
||||
{
|
||||
char *write_pos= str->str;
|
||||
|
||||
for(; ptr < eol; ptr++, write_pos++)
|
||||
{
|
||||
char c= *ptr;
|
||||
if (c == '\\')
|
||||
{
|
||||
ptr++;
|
||||
if (ptr >= eol)
|
||||
return TRUE;
|
||||
/*
|
||||
Should be in sync with write_escaped_string() and
|
||||
parse_quated_escaped_string()
|
||||
*/
|
||||
switch(*ptr) {
|
||||
case '\\':
|
||||
*write_pos= '\\';
|
||||
break;
|
||||
case 'n':
|
||||
*write_pos= '\n';
|
||||
break;
|
||||
case '0':
|
||||
*write_pos= '\0';
|
||||
break;
|
||||
case 'z':
|
||||
*write_pos= 26;
|
||||
break;
|
||||
case '\'':
|
||||
*write_pos= '\'';
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
*write_pos= c;
|
||||
}
|
||||
str->str[str->length= write_pos-str->str]= '\0'; // just for safety
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
parse \n delimited escaped string
|
||||
|
||||
SYNOPSIS
|
||||
parse_escaped_string()
|
||||
ptr - pointer on string beginning
|
||||
end - pointer on symbol after parsed string end (still owned
|
||||
by buffer and can be accessed
|
||||
mem_root - MEM_ROOT for parameter allocation
|
||||
str - pointer on string, where results should be stored
|
||||
|
||||
RETURN
|
||||
0 - error
|
||||
# - pointer on symbol after string
|
||||
*/
|
||||
|
||||
static char *
|
||||
parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
|
||||
{
|
||||
char *eol= strchr(ptr, '\n');
|
||||
|
||||
if (eol == 0 || eol >= end ||
|
||||
!(str->str= alloc_root(mem_root, (eol - ptr) + 1)) ||
|
||||
read_escaped_string(ptr, eol, str))
|
||||
return 0;
|
||||
|
||||
return eol+1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
parse '' delimited escaped string
|
||||
|
||||
SYNOPSIS
|
||||
parse_escaped_string()
|
||||
ptr - pointer on string beginning
|
||||
end - pointer on symbol after parsed string end (still owned
|
||||
by buffer and can be accessed
|
||||
mem_root - MEM_ROOT for parameter allocation
|
||||
str - pointer on string, where results should be stored
|
||||
|
||||
RETURN
|
||||
0 - error
|
||||
# - pointer on symbol after string
|
||||
*/
|
||||
|
||||
static char *
|
||||
parse_quated_escaped_string(char *ptr, char *end,
|
||||
MEM_ROOT *mem_root, LEX_STRING *str)
|
||||
{
|
||||
char *eol;
|
||||
uint result_len= 0;
|
||||
bool escaped= 0;
|
||||
|
||||
// starting '
|
||||
if (*(ptr++) != '\'')
|
||||
return 0;
|
||||
|
||||
// find ending '
|
||||
for (eol= ptr; (*eol != '\'' || escaped) && eol < end; eol++)
|
||||
{
|
||||
if (!(escaped= (*eol == '\\' && !escaped)))
|
||||
result_len++;
|
||||
}
|
||||
|
||||
// process string
|
||||
if (eol >= end ||
|
||||
!(str->str= alloc_root(mem_root, result_len + 1)) ||
|
||||
read_escaped_string(ptr, eol, str))
|
||||
return 0;
|
||||
|
||||
return eol+1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
parse parameters
|
||||
|
||||
SYNOPSIS
|
||||
File_parser::parse()
|
||||
base base address for parameter writing (structure like
|
||||
TABLE)
|
||||
mem_root MEM_ROOT for parameters allocation
|
||||
parameters parameters description
|
||||
required number of required parameters in above list
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
my_bool
|
||||
File_parser::parse(gptr base, MEM_ROOT *mem_root,
|
||||
struct File_option *parameters, uint required)
|
||||
{
|
||||
uint first_param= 0, found= 0;
|
||||
register char *ptr= start;
|
||||
char *eol;
|
||||
LEX_STRING *str;
|
||||
MEM_ROOT *sql_mem;
|
||||
List<LEX_STRING> *list;
|
||||
bool change_mem;
|
||||
DBUG_ENTER("File_parser::parse");
|
||||
|
||||
while (ptr < end && found < required)
|
||||
{
|
||||
char *line= ptr;
|
||||
if (*ptr == '#')
|
||||
{
|
||||
// it is comment
|
||||
if (!(ptr= strchr(ptr, '\n')))
|
||||
{
|
||||
my_error(ER_FPARSER_EOF_IN_COMMENT, MYF(0), line);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
File_option *parameter= parameters+first_param,
|
||||
*parameters_end= parameters+required;
|
||||
int len= 0;
|
||||
for(; parameter < parameters_end; parameter++)
|
||||
{
|
||||
len= parameter->name.length;
|
||||
// check length
|
||||
if (len < (end-ptr) && ptr[len] != '=')
|
||||
continue;
|
||||
// check keyword
|
||||
if (memcmp(parameter->name.str, ptr, len) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (parameter < parameters_end)
|
||||
{
|
||||
found++;
|
||||
/*
|
||||
if we found first parameter, start search from next parameter
|
||||
next time.
|
||||
(this small optimisation should work, because they should be
|
||||
written in same order)
|
||||
*/
|
||||
if (parameter == parameters+first_param)
|
||||
first_param++;
|
||||
|
||||
// get value
|
||||
ptr+= (len+1);
|
||||
switch (parameter->type) {
|
||||
case FILE_OPTIONS_STRING:
|
||||
{
|
||||
if (!(ptr= parse_string(ptr, end, mem_root,
|
||||
(LEX_STRING *)(base +
|
||||
parameter->offset))))
|
||||
{
|
||||
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
||||
parameter->name.str, line);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_ESTRING:
|
||||
{
|
||||
if (!(ptr= parse_escaped_string(ptr, end, mem_root,
|
||||
(LEX_STRING *)
|
||||
(base + parameter->offset))))
|
||||
{
|
||||
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
||||
parameter->name.str, line);
|
||||
DBUG_RETURN(TRUE);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_ULONGLONG:
|
||||
case FILE_OPTIONS_REV:
|
||||
if (!(eol= strchr(ptr, '\n')))
|
||||
{
|
||||
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
||||
parameter->name.str, line);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
*eol= '\0';
|
||||
*((ulonglong*)(base + parameter->offset))= atoll(ptr);
|
||||
*eol= '\n';
|
||||
ptr= eol+1;
|
||||
break;
|
||||
case FILE_OPTIONS_TIMESTAMP:
|
||||
{
|
||||
/* string have to be allocated already */
|
||||
LEX_STRING *val= (LEX_STRING *)(base + parameter->offset);
|
||||
/* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */
|
||||
if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n')
|
||||
{
|
||||
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
||||
parameter->name.str, line);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH);
|
||||
val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0';
|
||||
ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1);
|
||||
break;
|
||||
}
|
||||
case FILE_OPTIONS_STRLIST:
|
||||
{
|
||||
/*
|
||||
TODO: remove play with mem_root, when List will be able
|
||||
to store MEM_ROOT* pointer for list elements allocation
|
||||
*/
|
||||
sql_mem= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
|
||||
list= (List<LEX_STRING>*)(base + parameter->offset);
|
||||
if ((change_mem= (sql_mem != mem_root)))
|
||||
{
|
||||
change_mem= 1;
|
||||
my_pthread_setspecific_ptr(THR_MALLOC, mem_root);
|
||||
}
|
||||
|
||||
list->empty();
|
||||
// list parsing
|
||||
while (ptr < end)
|
||||
{
|
||||
if (!(str= (LEX_STRING*)alloc_root(mem_root,
|
||||
sizeof(LEX_STRING))) ||
|
||||
list->push_back(str))
|
||||
goto list_err;
|
||||
if(!(ptr= parse_quated_escaped_string(ptr, end, mem_root, str)))
|
||||
goto list_err_w_message;
|
||||
switch (*ptr) {
|
||||
case '\n':
|
||||
goto end_of_list;
|
||||
case ' ':
|
||||
// we cant go over buffer bounds, because we have \0 at the end
|
||||
ptr++;
|
||||
break;
|
||||
default:
|
||||
goto list_err_w_message;
|
||||
}
|
||||
}
|
||||
end_of_list:
|
||||
if (*(ptr++) != '\n')
|
||||
goto list_err;
|
||||
|
||||
if (change_mem)
|
||||
my_pthread_setspecific_ptr(THR_MALLOC, sql_mem);
|
||||
break;
|
||||
|
||||
list_err_w_message:
|
||||
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
||||
parameter->name.str, line);
|
||||
list_err:
|
||||
if (change_mem)
|
||||
my_pthread_setspecific_ptr(THR_MALLOC, sql_mem);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
default:
|
||||
DBUG_ASSERT(0); // never should happened
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip unknown parameter
|
||||
if (!(ptr= strchr(ptr, '\n')))
|
||||
{
|
||||
my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0),
|
||||
line);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
68
sql/parse_file.h
Normal file
68
sql/parse_file.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* -*- C++ -*- */
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef _PARSE_FILE_H_
|
||||
#define _PARSE_FILE_H_
|
||||
|
||||
#define PARSE_FILE_TIMESTAMPLENGTH 19
|
||||
|
||||
typedef enum {
|
||||
FILE_OPTIONS_STRING, /* String (LEX_STRING) */
|
||||
FILE_OPTIONS_ESTRING, /* Escaped string (LEX_STRING) */
|
||||
FILE_OPTIONS_ULONGLONG, /* ulonglong parapeter (ulonglong) */
|
||||
FILE_OPTIONS_REV, /* Revision version number (ulonglong) */
|
||||
FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be
|
||||
allocated with length 20 (19+1) */
|
||||
FILE_OPTIONS_STRLIST /* list of strings (List<char*>) */
|
||||
} file_opt_type;
|
||||
|
||||
struct File_option
|
||||
{
|
||||
const LEX_STRING name; /* Name of the option */
|
||||
int offset; /* offset to base address of value */
|
||||
enum file_opt_type type; /* Option type */
|
||||
};
|
||||
|
||||
class File_parser;
|
||||
File_parser *sql_parse_prepare(const LEX_STRING *file_name,
|
||||
MEM_ROOT *mem_root);
|
||||
|
||||
my_bool
|
||||
sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
|
||||
const LEX_STRING *type,
|
||||
gptr base, File_option *parameters, uint versions);
|
||||
|
||||
class File_parser: public Sql_alloc
|
||||
{
|
||||
char *buff, *start, *end;
|
||||
LEX_STRING file_type;
|
||||
my_bool content_ok;
|
||||
public:
|
||||
File_parser() :buff(0), start(0), end(0), content_ok(0)
|
||||
{ file_type.str= 0; file_type.length= 0; }
|
||||
|
||||
my_bool ok() { return content_ok; }
|
||||
LEX_STRING *type() { return &file_type; }
|
||||
my_bool parse(gptr base, MEM_ROOT *mem_root,
|
||||
struct File_option *parameters, uint required);
|
||||
|
||||
friend File_parser *sql_parse_prepare(const LEX_STRING *file_name,
|
||||
MEM_ROOT *mem_root,
|
||||
bool bad_format_errors);
|
||||
};
|
||||
|
||||
#endif /* _PARSE_FILE_H_ */
|
@ -160,6 +160,7 @@ sys_var_str sys_ft_boolean_syntax("ft_boolean_syntax",
|
||||
sys_update_ftb_syntax,
|
||||
sys_default_ftb_syntax,
|
||||
ft_boolean_syntax);
|
||||
sys_var_thd_ulong sys_heuristic("heuristic", &SV::heuristic);
|
||||
sys_var_str sys_init_connect("init_connect", 0,
|
||||
sys_update_init_connect,
|
||||
sys_default_init_connect,0);
|
||||
@ -262,6 +263,8 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
|
||||
0, fix_net_retry_count);
|
||||
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
|
||||
sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords);
|
||||
sys_var_thd_ulong sys_plan_search_depth("plan_search_depth",
|
||||
&SV::plan_search_depth);
|
||||
sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
|
||||
&SV::preload_buff_size);
|
||||
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
|
||||
@ -488,6 +491,7 @@ sys_var *sys_variables[]=
|
||||
&sys_ft_boolean_syntax,
|
||||
&sys_foreign_key_checks,
|
||||
&sys_group_concat_max_len,
|
||||
&sys_heuristic,
|
||||
&sys_identity,
|
||||
&sys_init_connect,
|
||||
&sys_init_slave,
|
||||
@ -536,6 +540,7 @@ sys_var *sys_variables[]=
|
||||
&sys_net_write_timeout,
|
||||
&sys_new_mode,
|
||||
&sys_old_passwords,
|
||||
&sys_plan_search_depth,
|
||||
&sys_preload_buff_size,
|
||||
&sys_pseudo_thread_id,
|
||||
&sys_query_alloc_block_size,
|
||||
@ -812,6 +817,8 @@ struct show_var_st init_vars[]= {
|
||||
{"version_compile_machine", (char*) MACHINE_TYPE, SHOW_CHAR},
|
||||
{sys_os.name, (char*) &sys_os, SHOW_SYS},
|
||||
{sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS},
|
||||
{sys_heuristic.name, (char*) &sys_heuristic, SHOW_SYS},
|
||||
{sys_plan_search_depth.name,(char*) &sys_plan_search_depth, SHOW_SYS},
|
||||
{NullS, NullS, SHOW_LONG}
|
||||
};
|
||||
|
||||
|
@ -345,3 +345,8 @@ character-set=latin2
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -339,3 +339,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -347,3 +347,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -336,3 +336,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -341,3 +341,8 @@ character-set=latin7
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -336,3 +336,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -348,3 +348,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -336,3 +336,8 @@ character-set=greek
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -338,3 +338,8 @@ character-set=latin2
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -336,3 +336,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -338,3 +338,8 @@ character-set=ujis
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -336,3 +336,8 @@ character-set=euckr
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -338,3 +338,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -338,3 +338,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -340,3 +340,8 @@ character-set=latin2
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -337,3 +337,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -340,3 +340,8 @@ character-set=latin2
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -338,3 +338,8 @@ character-set=koi8r
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> '%-.64s'"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> '%-.64s'"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s'"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s' (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: '%-.64s')"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s'"
|
||||
|
@ -330,3 +330,8 @@ character-set=cp1250
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -344,3 +344,8 @@ character-set=latin2
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -338,3 +338,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -336,3 +336,8 @@ character-set=latin1
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"Configuration file '%-.64s' is too big"
|
||||
"Malformed file type header in file '%-.64s'"
|
||||
"Unexpected end of file during parsing comment '%-.64s'"
|
||||
"Error during parsing parameter '%-.64s' (line: '%-.64s')"
|
||||
"Unexpected end of file during skipping unknown parameter '%-.64s'"
|
||||
|
@ -341,3 +341,8 @@ character-set=koi8u
|
||||
"Variable or condition declaration after cursor or handler declaration"
|
||||
"Cursor declaration after handler declaration"
|
||||
"Case not found for CASE statement"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>Ʀ<EFBFBD><C6A6><EFBFBD><EFBFBD>æ<EFBFBD><C3A6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> '%-.64s'"
|
||||
"<22><>צ<EFBFBD><D7A6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20> <20><><EFBFBD>̦ '%-.64s'"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD>Ħ<EFBFBD><C4A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ˦<><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҧ '%-.64s'"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD>Ц<EFBFBD><D0A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Φ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s' (<28><><EFBFBD><EFBFBD><EFBFBD>: '%-.64s')"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD>Ħ<EFBFBD><C4A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ˦<><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD>¦ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>צ<EFBFBD><D7A6><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s'"
|
||||
|
@ -392,6 +392,8 @@ struct system_variables
|
||||
ulong table_type;
|
||||
ulong tmp_table_size;
|
||||
ulong tx_isolation;
|
||||
ulong heuristic;
|
||||
ulong plan_search_depth;
|
||||
/* Determines which non-standard SQL behaviour should be enabled */
|
||||
ulong sql_mode;
|
||||
ulong default_week_format;
|
||||
|
@ -48,7 +48,25 @@ static int sort_keyuse(KEYUSE *a,KEYUSE *b);
|
||||
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
|
||||
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
||||
table_map used_tables);
|
||||
static void find_best_combination(JOIN *join,table_map rest_tables);
|
||||
static void choose_plan(JOIN *join,table_map join_tables);
|
||||
|
||||
static void best_access_path(JOIN *join, JOIN_TAB *s, THD *thd,
|
||||
table_map remaining_tables, uint idx,
|
||||
double record_count, double read_time);
|
||||
static void optimize_straight_join(JOIN *join, table_map join_tables);
|
||||
static void greedy_search(JOIN *join, table_map remaining_tables,
|
||||
uint depth, uint heuristic);
|
||||
static void best_extension_by_limited_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint idx, double record_count,
|
||||
double read_time, uint depth,
|
||||
uint heuristic);
|
||||
static uint determine_search_depth(JOIN* join);
|
||||
static int join_tab_cmp(const void* ptr1, const void* ptr2);
|
||||
/*
|
||||
TODO: 'find_best' is here only temporarily until 'greedy_search' is
|
||||
tested and approved.
|
||||
*/
|
||||
static void find_best(JOIN *join,table_map rest_tables,uint index,
|
||||
double record_count,double read_time);
|
||||
static uint cache_record_length(JOIN *join,uint index);
|
||||
@ -2002,7 +2020,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
if (join->const_tables != join->tables)
|
||||
{
|
||||
optimize_keyuse(join, keyuse_array);
|
||||
find_best_combination(join,all_table_map & ~join->const_table_map);
|
||||
choose_plan(join, all_table_map & ~join->const_table_map);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2579,7 +2597,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
||||
}
|
||||
|
||||
/*
|
||||
Update some values in keyuse for faster find_best_combination() loop
|
||||
Update some values in keyuse for faster choose_plan() loop
|
||||
*/
|
||||
|
||||
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
|
||||
@ -2647,16 +2665,952 @@ set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find the best access path for an extension of a partial execution plan and
|
||||
add this path to the plan.
|
||||
|
||||
SYNOPSIS
|
||||
best_access_path()
|
||||
join pointer to the structure providing all context info
|
||||
for the query
|
||||
s the table to be joined by the function
|
||||
thd thread for the connection that submitted the query
|
||||
remaining_tables set of tables not included into the partial plan yet
|
||||
idx the length of the partial plan
|
||||
record_count estimate for the number of records returned by the partial
|
||||
plan
|
||||
read_time the cost of the partial plan
|
||||
|
||||
DESCRIPTION
|
||||
The function finds the best access path to table 's' from the passed
|
||||
partial plan where an access path is the general term for any means to
|
||||
access the data in 's'. An access path may use either an index or a scan,
|
||||
whichever is cheaper. The input partial plan is passed via the array
|
||||
'join->positions' of length 'idx'. The chosen access method for 's' and its
|
||||
cost are stored in 'join->positions[idx]'.
|
||||
|
||||
RETURN
|
||||
None
|
||||
*/
|
||||
|
||||
static void
|
||||
find_best_combination(JOIN *join, table_map rest_tables)
|
||||
best_access_path(JOIN *join,
|
||||
JOIN_TAB *s,
|
||||
THD *thd,
|
||||
table_map remaining_tables,
|
||||
uint idx,
|
||||
double record_count,
|
||||
double read_time)
|
||||
{
|
||||
DBUG_ENTER("find_best_combination");
|
||||
join->best_read=DBL_MAX;
|
||||
find_best(join,rest_tables, join->const_tables,1.0,0.0);
|
||||
KEYUSE *best_key= 0;
|
||||
uint best_max_key_part= 0;
|
||||
my_bool found_constraint= 0;
|
||||
double best= DBL_MAX;
|
||||
double best_time= DBL_MAX;
|
||||
double records= DBL_MAX;
|
||||
double tmp;
|
||||
ha_rows rec;
|
||||
|
||||
DBUG_ENTER("best_access_path");
|
||||
|
||||
if (s->keyuse)
|
||||
{ /* Use key if possible */
|
||||
TABLE *table= s->table;
|
||||
KEYUSE *keyuse,*start_key=0;
|
||||
double best_records= DBL_MAX;
|
||||
uint max_key_part=0;
|
||||
|
||||
/* Test how we can use keys */
|
||||
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
|
||||
for (keyuse=s->keyuse ; keyuse->table == table ;)
|
||||
{
|
||||
key_part_map found_part= 0;
|
||||
table_map found_ref= 0;
|
||||
uint found_ref_or_null= 0;
|
||||
uint key= keyuse->key;
|
||||
KEY *keyinfo= table->key_info+key;
|
||||
bool ft_key= (keyuse->keypart == FT_KEYPART);
|
||||
|
||||
/* Calculate how many key segments of the current key we can use */
|
||||
start_key= keyuse;
|
||||
do
|
||||
{ /* for each keypart */
|
||||
uint keypart= keyuse->keypart;
|
||||
uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL;
|
||||
do
|
||||
{
|
||||
if (!(remaining_tables & keyuse->used_tables) &&
|
||||
!(found_ref_or_null & keyuse->optimize))
|
||||
{
|
||||
found_part|= keyuse->keypart_map;
|
||||
found_ref|= keyuse->used_tables;
|
||||
if (rec > keyuse->ref_table_rows)
|
||||
rec= keyuse->ref_table_rows;
|
||||
found_part_ref_or_null&= keyuse->optimize;
|
||||
}
|
||||
keyuse++;
|
||||
found_ref_or_null|= found_part_ref_or_null;
|
||||
} while (keyuse->table == table && keyuse->key == key &&
|
||||
keyuse->keypart == keypart);
|
||||
} while (keyuse->table == table && keyuse->key == key);
|
||||
|
||||
/*
|
||||
Assume that that each key matches a proportional part of table.
|
||||
*/
|
||||
if (!found_part && !ft_key)
|
||||
continue; // Nothing usable found
|
||||
|
||||
if (rec < MATCHING_ROWS_IN_OTHER_TABLE)
|
||||
rec= MATCHING_ROWS_IN_OTHER_TABLE; // Fix for small tables
|
||||
|
||||
/*
|
||||
ft-keys require special treatment
|
||||
*/
|
||||
if (ft_key)
|
||||
{
|
||||
/*
|
||||
Really, there should be records=0.0 (yes!)
|
||||
but 1.0 would be probably safer
|
||||
*/
|
||||
tmp= prev_record_reads(join, found_ref);
|
||||
records= 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_constraint= 1;
|
||||
/*
|
||||
Check if we found full key
|
||||
*/
|
||||
if (found_part == PREV_BITS(uint,keyinfo->key_parts) &&
|
||||
!found_ref_or_null)
|
||||
{ /* use eq key */
|
||||
max_key_part= (uint) ~0;
|
||||
if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
|
||||
{
|
||||
tmp = prev_record_reads(join, found_ref);
|
||||
records=1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!found_ref)
|
||||
{ /* We found a const key */
|
||||
if (table->quick_keys.is_set(key))
|
||||
records= (double) table->quick_rows[key];
|
||||
else
|
||||
{
|
||||
/* quick_range couldn't use key! */
|
||||
records= (double) s->records/rec;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(records=keyinfo->rec_per_key[keyinfo->key_parts-1]))
|
||||
{ /* Prefer longer keys */
|
||||
records=
|
||||
((double) s->records / (double) rec *
|
||||
(1.0 +
|
||||
((double) (table->max_key_length-keyinfo->key_length) /
|
||||
(double) table->max_key_length)));
|
||||
if (records < 2.0)
|
||||
records=2.0; /* Can't be as good as a unique */
|
||||
}
|
||||
}
|
||||
/* Limit the number of matched rows */
|
||||
tmp = records;
|
||||
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
|
||||
if (table->used_keys.is_set(key))
|
||||
{
|
||||
/* we can use only index tree */
|
||||
uint keys_per_block= table->file->block_size/2/
|
||||
(keyinfo->key_length+table->file->ref_length)+1;
|
||||
tmp = record_count*(tmp+keys_per_block-1)/keys_per_block;
|
||||
}
|
||||
else
|
||||
tmp = record_count*min(tmp,s->worst_seeks);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Use as much key-parts as possible and a uniq key is better
|
||||
than a not unique key
|
||||
Set tmp to (previous record count) * (records / combination)
|
||||
*/
|
||||
if ((found_part & 1) &&
|
||||
(!(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX) ||
|
||||
found_part == PREV_BITS(uint,keyinfo->key_parts)))
|
||||
{
|
||||
max_key_part=max_part_bit(found_part);
|
||||
/*
|
||||
Check if quick_range could determinate how many rows we
|
||||
will match
|
||||
*/
|
||||
if (table->quick_keys.is_set(key) &&
|
||||
table->quick_key_parts[key] == max_key_part)
|
||||
tmp= records= (double) table->quick_rows[key];
|
||||
else
|
||||
{
|
||||
/* Check if we have statistic about the distribution */
|
||||
if ((records = keyinfo->rec_per_key[max_key_part-1]))
|
||||
tmp = records;
|
||||
else
|
||||
{
|
||||
/*
|
||||
Assume that the first key part matches 1% of the file
|
||||
and that the hole key matches 10 (duplicates) or 1
|
||||
(unique) records.
|
||||
Assume also that more key matches proportionally more
|
||||
records
|
||||
This gives the formula:
|
||||
records = (x * (b-a) + a*c-b)/(c-1)
|
||||
|
||||
b = records matched by whole key
|
||||
a = records matched by first key part (10% of all records?)
|
||||
c = number of key parts in key
|
||||
x = used key parts (1 <= x <= c)
|
||||
*/
|
||||
double rec_per_key;
|
||||
if (!(rec_per_key=(double)
|
||||
keyinfo->rec_per_key[keyinfo->key_parts-1]))
|
||||
rec_per_key=(double) s->records/rec+1;
|
||||
|
||||
if (!s->records)
|
||||
tmp = 0;
|
||||
else if (rec_per_key/(double) s->records >= 0.01)
|
||||
tmp = rec_per_key;
|
||||
else
|
||||
{
|
||||
double a=s->records*0.01;
|
||||
tmp = (max_key_part * (rec_per_key - a) +
|
||||
a*keyinfo->key_parts - rec_per_key)/
|
||||
(keyinfo->key_parts-1);
|
||||
set_if_bigger(tmp,1.0);
|
||||
}
|
||||
records = (ulong) tmp;
|
||||
}
|
||||
/*
|
||||
If quick_select was used on a part of this key, we know
|
||||
the maximum number of rows that the key can match.
|
||||
*/
|
||||
if (table->quick_keys.is_set(key) &&
|
||||
table->quick_key_parts[key] <= max_key_part &&
|
||||
records > (double) table->quick_rows[key])
|
||||
tmp= records= (double) table->quick_rows[key];
|
||||
else if (found_ref_or_null)
|
||||
{
|
||||
/* We need to do two key searches to find key */
|
||||
tmp *= 2.0;
|
||||
records *= 2.0;
|
||||
}
|
||||
}
|
||||
/* Limit the number of matched rows */
|
||||
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
|
||||
if (table->used_keys.is_set(key))
|
||||
{
|
||||
/* we can use only index tree */
|
||||
uint keys_per_block= table->file->block_size/2/
|
||||
(keyinfo->key_length+table->file->ref_length)+1;
|
||||
tmp = record_count*(tmp+keys_per_block-1)/keys_per_block;
|
||||
}
|
||||
else
|
||||
tmp = record_count*min(tmp,s->worst_seeks);
|
||||
}
|
||||
else
|
||||
tmp = best_time; // Do nothing
|
||||
}
|
||||
} /* not ft_key */
|
||||
if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
|
||||
{
|
||||
best_time= tmp + records/(double) TIME_FOR_COMPARE;
|
||||
best= tmp;
|
||||
best_records= records;
|
||||
best_key= start_key;
|
||||
best_max_key_part= max_key_part;
|
||||
}
|
||||
}
|
||||
records= best_records;
|
||||
}
|
||||
|
||||
/*
|
||||
Don't test table scan if it can't be better.
|
||||
Prefer key lookup if we would use the same key for scanning.
|
||||
|
||||
Don't do a table scan on InnoDB tables, if we can read the used
|
||||
parts of the row from any of the used index.
|
||||
This is because table scans uses index and we would not win
|
||||
anything by using a table scan.
|
||||
*/
|
||||
if ((records >= s->found_records || best > s->read_time) &&
|
||||
!(s->quick && best_key && s->quick->index == best_key->key &&
|
||||
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
|
||||
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
|
||||
! s->table->used_keys.is_clear_all() && best_key) &&
|
||||
!(s->table->force_index && best_key))
|
||||
{ // Check full join
|
||||
ha_rows rnd_records= s->found_records;
|
||||
/*
|
||||
If there is a restriction on the table, assume that 25% of the
|
||||
rows can be skipped on next part.
|
||||
This is to force tables that this table depends on before this
|
||||
table
|
||||
*/
|
||||
if (found_constraint)
|
||||
rnd_records-= rnd_records/4;
|
||||
|
||||
/*
|
||||
Range optimizer never proposes a RANGE if it isn't better
|
||||
than FULL: so if RANGE is present, it's always preferred to FULL.
|
||||
Here we estimate its cost.
|
||||
*/
|
||||
if (s->quick)
|
||||
{
|
||||
/*
|
||||
For each record we:
|
||||
- read record range through 'quick'
|
||||
- skip rows which does not satisfy WHERE constraints
|
||||
*/
|
||||
tmp= record_count *
|
||||
(s->quick->read_time +
|
||||
(s->found_records - rnd_records)/(double) TIME_FOR_COMPARE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Estimate cost of reading table. */
|
||||
tmp= s->table->file->scan_time();
|
||||
if (s->on_expr) // Can't use join cache
|
||||
{
|
||||
/*
|
||||
For each record we have to:
|
||||
- read the whole table record
|
||||
- skip rows which does not satisfy join condition
|
||||
*/
|
||||
tmp= record_count *
|
||||
(tmp +
|
||||
(s->records - rnd_records)/(double) TIME_FOR_COMPARE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We read the table as many times as join buffer becomes full. */
|
||||
tmp*= (1.0 + floor((double) cache_record_length(join,idx) *
|
||||
record_count /
|
||||
(double) thd->variables.join_buff_size));
|
||||
/*
|
||||
We don't make full cartesian product between rows in the scanned
|
||||
table and existing records because we skip all rows from the
|
||||
scanned table, which does not satisfy join condition when
|
||||
we read the table (see flush_cached_records for details). Here we
|
||||
take into account cost to read and skip these records.
|
||||
*/
|
||||
tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We estimate the cost of evaluating WHERE clause for found records
|
||||
as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus
|
||||
tmp give us total cost of using TABLE SCAN
|
||||
*/
|
||||
if (best == DBL_MAX ||
|
||||
(tmp + record_count/(double) TIME_FOR_COMPARE*rnd_records <
|
||||
best + record_count/(double) TIME_FOR_COMPARE*records))
|
||||
{
|
||||
/*
|
||||
If the table has a range (s->quick is set) make_join_select()
|
||||
will ensure that this will be used
|
||||
*/
|
||||
best= tmp;
|
||||
records= rows2double(rnd_records);
|
||||
best_key= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the cost information for the current partial plan */
|
||||
join->positions[idx].records_read= records;
|
||||
join->positions[idx].read_time= best;
|
||||
join->positions[idx].key= best_key;
|
||||
join->positions[idx].table= s;
|
||||
|
||||
if (!best_key &&
|
||||
idx == join->const_tables &&
|
||||
s->table == join->sort_by_table &&
|
||||
join->unit->select_limit_cnt >= records)
|
||||
join->sort_by_table= (TABLE*) 1; // Must use temporary table
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Selects and invokes a search strategy for an optimal query plan.
|
||||
|
||||
SYNOPSIS
|
||||
choose_plan()
|
||||
join pointer to the structure providing all context info for
|
||||
the query
|
||||
join_tables set of the tables in the query
|
||||
|
||||
DESCRIPTION
|
||||
The function checks user-configurable parameters that control the search
|
||||
strategy for an optimal plan, selects the search method and then invokes
|
||||
it. Each specific optimization procedure stores the final optimal plan in
|
||||
the array 'join->best_positions', and the cost of the plan in
|
||||
'join->best_read'.
|
||||
|
||||
RETURN
|
||||
None
|
||||
*/
|
||||
|
||||
static void
|
||||
choose_plan(JOIN *join, table_map join_tables)
|
||||
{
|
||||
uint search_depth= join->thd->variables.plan_search_depth;
|
||||
uint heuristic= join->thd->variables.heuristic;
|
||||
|
||||
DBUG_ENTER("choose_plan");
|
||||
|
||||
if (join->select_options & SELECT_STRAIGHT_JOIN)
|
||||
{
|
||||
optimize_straight_join(join, join_tables);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Heuristic: pre-sort all access plans with respect to the number of
|
||||
records accessed.
|
||||
*/
|
||||
qsort(join->best_ref + join->const_tables, join->tables - join->const_tables,
|
||||
sizeof(JOIN_TAB*), join_tab_cmp);
|
||||
|
||||
if (search_depth == MAX_TABLES+2)
|
||||
{ /*
|
||||
TODO: 'MAX_TABLES+2' denotes the old implementation of find_best before
|
||||
the greedy version. Will be removed when greedy_search is approved.
|
||||
*/
|
||||
join->best_read= DBL_MAX;
|
||||
find_best(join, join_tables, join->const_tables, 1.0, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (search_depth == 0)
|
||||
/* Automatically determine a reasonable value for 'search_depth' */
|
||||
search_depth= determine_search_depth(join);
|
||||
greedy_search(join, join_tables, search_depth, heuristic);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the cost of this query into a user variable */
|
||||
last_query_cost= join->best_read;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compare two JOIN_TAB objects based on the number of accessed records.
|
||||
|
||||
SYNOPSIS
|
||||
join_tab_cmp()
|
||||
ptr1 pointer to first JOIN_TAB object
|
||||
ptr2 pointer to second JOIN_TAB object
|
||||
|
||||
RETURN
|
||||
1 if first is bigger
|
||||
-1 if second is bigger
|
||||
0 if equal
|
||||
*/
|
||||
|
||||
static int
|
||||
join_tab_cmp(const void* ptr1, const void* ptr2)
|
||||
{
|
||||
JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
|
||||
JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
|
||||
if (jt1->found_records > jt2->found_records)
|
||||
return 1;
|
||||
else if (jt1->found_records < jt2->found_records)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Heuristic procedure to automatically guess a reasonable degree of
|
||||
exhaustiveness for the greedy search procedure.
|
||||
|
||||
SYNOPSIS
|
||||
determine_search_depth()
|
||||
join pointer to the structure providing all context info for the query
|
||||
|
||||
DESCRIPTION
|
||||
The procedure estimates the optimization time and selects a search depth
|
||||
big enough to result in a near-optimal QEP, that doesn't take too long to
|
||||
find. If the number of tables in the query exceeds some constant, then
|
||||
search_depth is set to this constant.
|
||||
|
||||
NOTES
|
||||
This is an extremely simplistic implementation that serves as a stub for a
|
||||
more advanced analysis of the join. Ideally the search depth should be
|
||||
determined by learning from previous query optimizations, because it will
|
||||
depend on the CPU power (and other factors).
|
||||
|
||||
RETURN
|
||||
A positive integer that specifies the search depth (and thus the
|
||||
exhaustiveness) of the depth-first search algorithm used by
|
||||
'greedy_search'.
|
||||
*/
|
||||
|
||||
static uint
|
||||
determine_search_depth(JOIN *join)
|
||||
{
|
||||
uint table_count= join->tables - join->const_tables;
|
||||
uint search_depth;
|
||||
/* TODO: this value should be determined dynamically, based on statistics: */
|
||||
uint max_tables_for_exhaustive_opt= 7;
|
||||
|
||||
if (table_count <= max_tables_for_exhaustive_opt)
|
||||
search_depth= table_count+1; // use exhaustive for small number of tables
|
||||
else
|
||||
/*
|
||||
TODO: this value could be determined by some mapping of the form:
|
||||
depth : table_count -> [max_tables_for_exhaustive_opt..MAX_EXHAUSTIVE]
|
||||
*/
|
||||
search_depth= max_tables_for_exhaustive_opt; // use greedy search
|
||||
|
||||
return search_depth;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Select the best ways to access the tables in a query without reordering them.
|
||||
|
||||
SYNOPSIS
|
||||
optimize_straight_join()
|
||||
join pointer to the structure providing all context info for
|
||||
the query
|
||||
join_tables set of the tables in the query
|
||||
|
||||
DESCRIPTION
|
||||
Find the best access paths for each query table and compute their costs
|
||||
according to their order in the array 'join->best_ref' (thus without
|
||||
reordering the join tables). The function calls sequentially
|
||||
'best_access_path' for each table in the query to select the best table
|
||||
access method. The final optimal plan is stored in the array
|
||||
'join->best_positions', and the corresponding cost in 'join->best_read'.
|
||||
|
||||
NOTES
|
||||
This function can be applied to:
|
||||
- queries with STRAIGHT_JOIN
|
||||
- internally to compute the cost of an arbitrary QEP
|
||||
Thus 'optimize_straight_join' can be used at any stage of the query
|
||||
optimization process to finalize a QEP as it is.
|
||||
|
||||
RETURN
|
||||
None
|
||||
*/
|
||||
|
||||
static void
|
||||
optimize_straight_join(JOIN *join, table_map join_tables)
|
||||
{
|
||||
JOIN_TAB *s;
|
||||
uint idx= join->const_tables;
|
||||
double record_count= 1.0;
|
||||
double read_time= 0.0;
|
||||
|
||||
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
|
||||
{
|
||||
/* Find the best access method from 's' to the current partial plan */
|
||||
best_access_path(join, s, join->thd, join_tables, idx, record_count, read_time);
|
||||
/* compute the cost of the new plan extended with 's' */
|
||||
record_count*= join->positions[idx].records_read;
|
||||
read_time+= join->positions[idx].read_time;
|
||||
join_tables&= ~(s->table->map);
|
||||
++idx;
|
||||
}
|
||||
|
||||
read_time+= record_count / (double) TIME_FOR_COMPARE;
|
||||
if (join->sort_by_table &&
|
||||
join->sort_by_table != join->positions[join->const_tables].table->table)
|
||||
read_time+= record_count; // We have to make a temp table
|
||||
memcpy((gptr) join->best_positions, (gptr) join->positions,
|
||||
sizeof(POSITION)*idx);
|
||||
join->best_read= read_time;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find a good, possibly optimal, query execution plan (QEP) by a greedy search.
|
||||
|
||||
SYNOPSIS
|
||||
join pointer to the structure providing all context info
|
||||
for the query
|
||||
remaining_tables set of tables not included into the partial plan yet
|
||||
search_depth controlls the exhaustiveness of the search
|
||||
heuristic the pruning heuristics that should be applied during
|
||||
search
|
||||
|
||||
DESCRIPTION
|
||||
The search procedure uses a hybrid greedy/exhaustive search with controlled
|
||||
exhaustiveness. The search is performed in N = card(remaining_tables)
|
||||
steps. Each step evaluates how promising is each of the unoptimized tables,
|
||||
selects the most promising table, and extends the current partial QEP with
|
||||
that table. Currenly the most 'promising' table is the one with least
|
||||
expensive extension.
|
||||
There are two extreme cases:
|
||||
1. When (card(remaining_tables) < search_depth), the estimate finds the best
|
||||
complete continuation of the partial QEP. This continuation can be
|
||||
used directly as a result of the search.
|
||||
2. When (search_depth == 1) the 'best_extension_by_limited_search'
|
||||
consideres the extension of the current QEP with each of the remaining
|
||||
unoptimized tables.
|
||||
All other cases are in-between these two extremes. Thus the parameter
|
||||
'search_depth' controlls the exhaustiveness of the search. The higher the
|
||||
value, the longer the optimizaton time and possibly the better the
|
||||
resulting plan. The lower the value, the fewer alternative plans are
|
||||
estimated, but the more likely to get a bad QEP.
|
||||
|
||||
All intermediate and final results of the procedure are stored in 'join':
|
||||
join->positions modified for every partial QEP that is explored
|
||||
join->best_positions modified for the current best complete QEP
|
||||
join->best_read modified for the current best complete QEP
|
||||
join->best_ref might be partially reordered
|
||||
The final optimal plan is stored in 'join->best_positions', and its
|
||||
corresponding cost in 'join->best_read'.
|
||||
|
||||
NOTES
|
||||
The following pseudocode describes the algorithm of 'greedy_search':
|
||||
|
||||
procedure greedy_search
|
||||
input: remaining_tables
|
||||
output: pplan;
|
||||
{
|
||||
pplan = <>;
|
||||
do {
|
||||
(t, a) = best_extension(pplan, remaining_tables);
|
||||
pplan = concat(pplan, (t, a));
|
||||
remaining_tables = remaining_tables - t;
|
||||
} while (remaining_tables != {})
|
||||
return pplan;
|
||||
}
|
||||
|
||||
where 'best_extension' is a placeholder for a procedure that selects the
|
||||
most "promising" of all tables in 'remaining_tables'.
|
||||
Currently this estimate is performed by calling
|
||||
'best_extension_by_limited_search' to evaluate all extensions of the
|
||||
current QEP of size 'search_depth', thus the complexity of 'greedy_search'
|
||||
mainly depends on that of 'best_extension_by_limited_search'.
|
||||
|
||||
If 'best_extension()' == 'best_extension_by_limited_search()', then the
|
||||
worst-case complexity of this algorithm is <=
|
||||
O(N*N^search_depth/search_depth). When serch_depth >= N, then the
|
||||
complexity of greedy_search is O(N!).
|
||||
|
||||
In the future, 'greedy_search' might be extended to support other
|
||||
implementations of 'best_extension', e.g. some simpler quadratic procedure.
|
||||
|
||||
RETURN
|
||||
None
|
||||
*/
|
||||
|
||||
static void
|
||||
greedy_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint search_depth,
|
||||
uint heuristic)
|
||||
{
|
||||
double record_count= 1.0;
|
||||
double read_time= 0.0;
|
||||
uint idx= join->const_tables; // index into 'join->best_ref'
|
||||
uint best_idx;
|
||||
uint rem_size; // cardinality of remaining_tables
|
||||
POSITION best_pos;
|
||||
JOIN_TAB *best_table; // the next plan node to be added to the curr QEP
|
||||
|
||||
DBUG_ENTER("greedy_search");
|
||||
|
||||
/* number of tables that remain to be optimized */
|
||||
rem_size= my_count_bits(remaining_tables);
|
||||
|
||||
do {
|
||||
/* Find the extension of the current QEP with the lowest cost */
|
||||
join->best_read= DBL_MAX;
|
||||
best_extension_by_limited_search(join, remaining_tables, idx, record_count,
|
||||
read_time, search_depth, heuristic);
|
||||
|
||||
if (rem_size <= search_depth)
|
||||
{
|
||||
/*
|
||||
'join->best_positions' contains a complete optimal extension of the
|
||||
current partial QEP.
|
||||
*/
|
||||
DBUG_EXECUTE("opt", print_plan(join, read_time, record_count,
|
||||
join->tables, "optimal"););
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* select the first table in the optimal extension as most promising */
|
||||
best_pos= join->best_positions[idx];
|
||||
best_table= best_pos.table;
|
||||
/*
|
||||
Each subsequent loop of 'best_extension_by_limited_search' uses
|
||||
'join->positions' for cost estimates, therefore we have to update its
|
||||
value.
|
||||
*/
|
||||
join->positions[idx]= best_pos;
|
||||
|
||||
/* find the position of 'best_table' in 'join->best_ref' */
|
||||
best_idx= idx;
|
||||
JOIN_TAB *pos= join->best_ref[best_idx];
|
||||
while (pos && best_table != pos)
|
||||
pos= join->best_ref[++best_idx];
|
||||
DBUG_ASSERT((pos != NULL)); // should always find 'best_table'
|
||||
/* move 'best_table' at the first free position in the array of joins */
|
||||
swap(JOIN_TAB*, join->best_ref[idx], join->best_ref[best_idx]);
|
||||
|
||||
/* compute the cost of the new plan extended with 'best_table' */
|
||||
record_count*= join->positions[idx].records_read;
|
||||
read_time+= join->positions[idx].read_time;
|
||||
|
||||
remaining_tables&= ~(best_table->table->map);
|
||||
--rem_size;
|
||||
++idx;
|
||||
|
||||
DBUG_EXECUTE("opt",
|
||||
print_plan(join, read_time, record_count, idx, "extended"););
|
||||
} while (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find a good, possibly optimal, query execution plan (QEP) by a possibly
|
||||
exhaustive search.
|
||||
|
||||
SYNOPSIS
|
||||
best_extension_by_limited_search()
|
||||
join pointer to the structure providing all context info for
|
||||
the query
|
||||
remaining_tables set of tables not included into the partial plan yet
|
||||
idx length of the partial QEP in 'join->positions';
|
||||
since a depth-first search is used, also corresponds to
|
||||
the current depth of the search tree;
|
||||
also an index in the array 'join->best_ref';
|
||||
record_count estimate for the number of records returned by the best
|
||||
partial plan
|
||||
read_time the cost of the best partial plan
|
||||
search_depth maximum depth of the recursion and thus size of the found
|
||||
optimal plan (0 < search_depth <= join->tables+1).
|
||||
heuristic pruning heuristics that should be applied during optimization
|
||||
(values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS)
|
||||
|
||||
DESCRIPTION
|
||||
The procedure searches for the optimal ordering of the query tables in set
|
||||
'remaining_tables' of size N, and the corresponding optimal access paths to each
|
||||
table. The choice of a table order and an access path for each table
|
||||
constitutes a query execution plan (QEP) that fully specifies how to
|
||||
execute the query.
|
||||
|
||||
The maximal size of the found plan is controlled by the parameter
|
||||
'search_depth'. When search_depth == N, the resulting plan is complete and
|
||||
can be used directly as a QEP. If search_depth < N, the found plan consists
|
||||
of only some of the query tables. Such "partial" optimal plans are useful
|
||||
only as input to query optimization procedures, and cannot be used directly
|
||||
to execute a query.
|
||||
|
||||
The algorithm begins with an empty partial plan stored in 'join->positions'
|
||||
and a set of N tables - 'remaining_tables'. Each step of the algorithm
|
||||
evaluates the cost of the partial plan extended by all access plans for
|
||||
each of the relations in 'remaining_tables', expands the current partial
|
||||
plan with the access plan that results in lowest cost of the expanded
|
||||
partial plan, and removes the corresponding relation from
|
||||
'remaining_tables'. The algorithm continues until it either constructs a
|
||||
complete optimal plan, or constructs an optimal plartial plan with size =
|
||||
search_depth.
|
||||
|
||||
The final optimal plan is stored in 'join->best_positions'. The
|
||||
corresponding cost of the optimal plan is in 'join->best_read'.
|
||||
|
||||
NOTES
|
||||
The procedure uses a recursive depth-first search where the depth of the
|
||||
recursion (and thus the exhaustiveness of the search) is controlled by the
|
||||
parameter 'search_depth'.
|
||||
|
||||
The pseudocode below describes the algorithm of
|
||||
'best_extension_by_limited_search'. The worst-case complexity of this
|
||||
algorithm is O(N*N^search_depth/search_depth). When serch_depth >= N, then
|
||||
the complexity of greedy_search is O(N!).
|
||||
|
||||
procedure best_extension_by_limited_search(
|
||||
pplan in, // in, partial plan of tables-joined-so-far
|
||||
pplan_cost, // in, cost of pplan
|
||||
remaining_tables, // in, set of tables not referenced in pplan
|
||||
best_plan_so_far, // in/out, best plan found so far
|
||||
best_plan_so_far_cost,// in/out, cost of best_plan_so_far
|
||||
search_depth) // in, maximum size of the plans being considered
|
||||
{
|
||||
for each table T from remaining_tables
|
||||
{
|
||||
// Calculate the cost of using table T as above
|
||||
cost = complex-series-of-calculations;
|
||||
|
||||
// Add the cost to the cost so far.
|
||||
pplan_cost+= cost;
|
||||
|
||||
if (pplan_cost >= best_plan_so_far_cost)
|
||||
// pplan_cost already too great, stop search
|
||||
continue;
|
||||
|
||||
pplan= expand pplan by best_access_method;
|
||||
remaining_tables= remaining_tables - table T;
|
||||
if (remaining_tables is not an empty set
|
||||
and
|
||||
search_depth > 1)
|
||||
{
|
||||
best_extension_by_limited_search(pplan, pplan_cost,
|
||||
remaining_tables,
|
||||
best_plan_so_far,
|
||||
best_plan_so_far_cost,
|
||||
search_depth - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
best_plan_so_far_cost= pplan_cost;
|
||||
best_plan_so_far= pplan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENTATION
|
||||
When 'best_extension_by_limited_search' is called for the first time,
|
||||
'join->best_read' must be set to the largest possible value (e.g. DBL_MAX).
|
||||
The actual implementation provides a way to optionally use pruning
|
||||
heuristics (controlled by the parameter 'heuristic') to reduce the search
|
||||
space by skipping some partial plans.
|
||||
The parameter 'search_depth' provides control over the recursion
|
||||
depth, and thus the size of the resulting optimal plan.
|
||||
|
||||
RETURN
|
||||
None
|
||||
*/
|
||||
|
||||
static void
|
||||
best_extension_by_limited_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint idx,
|
||||
double record_count,
|
||||
double read_time,
|
||||
uint search_depth,
|
||||
uint heuristic)
|
||||
{
|
||||
THD *thd= join->thd;
|
||||
if (thd->killed) // Abort
|
||||
return;
|
||||
|
||||
DBUG_ENTER("best_extension_by_limited_search");
|
||||
|
||||
/*
|
||||
'join' is a partial plan with lower cost than the best plan so far,
|
||||
so continue expanding it further with the tables in 'remaining_tables'.
|
||||
*/
|
||||
JOIN_TAB *s;
|
||||
double best_record_count= DBL_MAX;
|
||||
double best_read_time= DBL_MAX;
|
||||
|
||||
DBUG_EXECUTE("opt",
|
||||
print_plan(join, read_time, record_count, idx, "part_plan"););
|
||||
|
||||
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
|
||||
{
|
||||
table_map real_table_bit= s->table->map;
|
||||
if ((remaining_tables & real_table_bit) && !(remaining_tables & s->dependent))
|
||||
{
|
||||
double current_record_count, current_read_time;
|
||||
|
||||
/* Find the best access method from 's' to the current partial plan */
|
||||
best_access_path(join, s, thd, remaining_tables, idx, record_count, read_time);
|
||||
/* Compute the cost of extending the plan with 's' */
|
||||
current_record_count= record_count * join->positions[idx].records_read;
|
||||
current_read_time= read_time + join->positions[idx].read_time;
|
||||
|
||||
/* Expand only partial plans with lower cost than the best QEP so far */
|
||||
if ((current_read_time +
|
||||
current_record_count / (double) TIME_FOR_COMPARE) >= join->best_read)
|
||||
{
|
||||
DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx,
|
||||
"prune_by_cost"););
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Prune some less promising partial plans. This heuristic may miss
|
||||
the optimal QEPs, thus it results in a non-exhaustive search.
|
||||
*/
|
||||
if (heuristic == 1)
|
||||
{
|
||||
if (best_record_count > current_record_count ||
|
||||
best_read_time > current_read_time ||
|
||||
idx == join->const_tables && // 's' is the first table in the QEP
|
||||
s->table == join->sort_by_table)
|
||||
{
|
||||
if (best_record_count >= current_record_count &&
|
||||
best_read_time >= current_read_time &&
|
||||
/* TODO: What is the reasoning behind this condition? */
|
||||
(!(s->key_dependent & remaining_tables) ||
|
||||
join->positions[idx].records_read < 2.0))
|
||||
{
|
||||
best_record_count= current_record_count;
|
||||
best_read_time= current_read_time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx,
|
||||
"prune_by_heuristic"););
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) )
|
||||
{ /* Recursively expand the current partial plan */
|
||||
swap(JOIN_TAB*, join->best_ref[idx], *pos);
|
||||
best_extension_by_limited_search(join,
|
||||
remaining_tables & ~real_table_bit,
|
||||
idx + 1,
|
||||
current_record_count,
|
||||
current_read_time,
|
||||
search_depth - 1,
|
||||
heuristic);
|
||||
if (thd->killed)
|
||||
DBUG_VOID_RETURN;
|
||||
swap(JOIN_TAB*, join->best_ref[idx], *pos);
|
||||
}
|
||||
else
|
||||
{ /*
|
||||
'join' is either the best partial QEP with 'search_depth' relations,
|
||||
or the best complete QEP so far, whichever is smaller.
|
||||
*/
|
||||
current_read_time+= current_record_count / (double) TIME_FOR_COMPARE;
|
||||
if (join->sort_by_table &&
|
||||
join->sort_by_table != join->positions[join->const_tables].table->table)
|
||||
/* We have to make a temp table */
|
||||
current_read_time+= current_record_count;
|
||||
if ((search_depth == 1) || (current_read_time < join->best_read))
|
||||
{
|
||||
memcpy((gptr) join->best_positions, (gptr) join->positions,
|
||||
sizeof(POSITION) * (idx + 1));
|
||||
join->best_read= current_read_time;
|
||||
}
|
||||
DBUG_EXECUTE("opt",
|
||||
print_plan(join, current_read_time, current_record_count, idx, "full_plan"););
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
TODO: this function is here only temporarily until 'greedy_search' is
|
||||
tested and accepted.
|
||||
*/
|
||||
static void
|
||||
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
||||
double read_time)
|
||||
|
@ -116,6 +116,7 @@ typedef struct st_join_table {
|
||||
typedef struct st_position /* Used in find_best */
|
||||
{
|
||||
double records_read;
|
||||
double read_time;
|
||||
JOIN_TAB *table;
|
||||
KEYUSE *key;
|
||||
} POSITION;
|
||||
@ -133,8 +134,9 @@ typedef struct st_rollup
|
||||
class JOIN :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
JOIN_TAB *join_tab,**best_ref,**map2table;
|
||||
JOIN_TAB *join_tab_save; //saved join_tab for subquery reexecution
|
||||
JOIN_TAB *join_tab,**best_ref;
|
||||
JOIN_TAB **map2table; // mapping between table indexes and JOIN_TABs
|
||||
JOIN_TAB *join_tab_save; // saved join_tab for subquery reexecution
|
||||
TABLE **table,**all_tables,*sort_by_table;
|
||||
uint tables,const_tables;
|
||||
uint send_group_parts;
|
||||
|
@ -1845,6 +1845,11 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
|
||||
end= strend(pos);
|
||||
break;
|
||||
}
|
||||
case SHOW_DOUBLE:
|
||||
{
|
||||
end= buff + sprintf(buff, "%f", *(double*) value);
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_OPENSSL
|
||||
/* First group - functions relying on CTX */
|
||||
case SHOW_SSL_CTX_SESS_ACCEPT:
|
||||
|
@ -232,6 +232,102 @@ TEST_join(JOIN *join)
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Print the current state during query optimization.
|
||||
|
||||
SYNOPSIS
|
||||
print_plan()
|
||||
join pointer to the structure providing all context info for
|
||||
the query
|
||||
read_time the cost of the best partial plan
|
||||
record_count estimate for the number of records returned by the best
|
||||
partial plan
|
||||
idx length of the partial QEP in 'join->positions';
|
||||
also an index in the array 'join->best_ref';
|
||||
info comment string to appear above the printout
|
||||
|
||||
DESCRIPTION
|
||||
This function prints to the log file DBUG_FILE the members of 'join' that
|
||||
are used during query optimization (join->positions, join->best_positions,
|
||||
and join->best_ref) and few other related variables (read_time,
|
||||
record_count).
|
||||
Useful to trace query optimizer functions.
|
||||
|
||||
RETURN
|
||||
None
|
||||
*/
|
||||
|
||||
void
|
||||
print_plan(JOIN* join, double read_time, double record_count,
|
||||
uint idx, const char *info)
|
||||
{
|
||||
uint i;
|
||||
POSITION pos;
|
||||
JOIN_TAB *join_table;
|
||||
JOIN_TAB **plan_nodes;
|
||||
TABLE* table;
|
||||
|
||||
if (info == 0)
|
||||
info= "";
|
||||
|
||||
DBUG_LOCK_FILE;
|
||||
if (join->best_read == DBL_MAX)
|
||||
{
|
||||
fprintf(DBUG_FILE,"%s; idx:%u, best: DBL_MAX, current:%g\n",
|
||||
info, idx, read_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(DBUG_FILE,"%s; idx: %u, best: %g, current: %g\n",
|
||||
info, idx, join->best_read, read_time);
|
||||
}
|
||||
|
||||
/* Print the tables in JOIN->positions */
|
||||
fputs(" POSITIONS: ", DBUG_FILE);
|
||||
for (i= 0; i < idx ; i++)
|
||||
{
|
||||
pos = join->positions[i];
|
||||
table= pos.table->table;
|
||||
if (table)
|
||||
fputs(table->real_name, DBUG_FILE);
|
||||
fputc(' ', DBUG_FILE);
|
||||
}
|
||||
fputc('\n', DBUG_FILE);
|
||||
|
||||
/*
|
||||
Print the tables in JOIN->best_positions only if at least one complete plan
|
||||
has been found. An indicator for this is the value of 'join->best_read'.
|
||||
*/
|
||||
fputs("BEST_POSITIONS: ", DBUG_FILE);
|
||||
if (join->best_read < DBL_MAX)
|
||||
{
|
||||
for (i= 0; i < idx ; i++)
|
||||
{
|
||||
pos= join->best_positions[i];
|
||||
table= pos.table->table;
|
||||
if (table)
|
||||
fputs(table->real_name, DBUG_FILE);
|
||||
fputc(' ', DBUG_FILE);
|
||||
}
|
||||
}
|
||||
fputc('\n', DBUG_FILE);
|
||||
|
||||
/* Print the tables in JOIN->best_ref */
|
||||
fputs(" BEST_REF: ", DBUG_FILE);
|
||||
for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++)
|
||||
{
|
||||
join_table= (*plan_nodes);
|
||||
fputs(join_table->table->real_name, DBUG_FILE);
|
||||
fprintf(DBUG_FILE, "(%u,%u,%u)",
|
||||
join_table->found_records, join_table->records, join_table->read_time);
|
||||
fputc(' ', DBUG_FILE);
|
||||
}
|
||||
fputc('\n', DBUG_FILE);
|
||||
|
||||
DBUG_UNLOCK_FILE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct st_debug_lock
|
||||
|
@ -167,8 +167,8 @@ typedef struct st_known_date_time_format {
|
||||
enum SHOW_TYPE
|
||||
{
|
||||
SHOW_UNDEF,
|
||||
SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_BOOL,
|
||||
SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION,
|
||||
SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_DOUBLE,
|
||||
SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION,
|
||||
SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS,
|
||||
#ifdef HAVE_OPENSSL
|
||||
SHOW_SSL_CTX_SESS_ACCEPT, SHOW_SSL_CTX_SESS_ACCEPT_GOOD,
|
||||
|
Reference in New Issue
Block a user