summaryrefslogtreecommitdiff
path: root/sql/sql_select.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.h')
-rw-r--r--sql/sql_select.h290
1 files changed, 208 insertions, 82 deletions
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 54138712da4..d955d569ced 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -2,7 +2,7 @@
#define SQL_SELECT_INCLUDED
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab.
+ Copyright (c) 2008, 2015, MariaDB
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
@@ -29,33 +29,10 @@
#endif
#include "procedure.h"
-#include <myisam.h>
#include "sql_array.h" /* Array */
#include "records.h" /* READ_RECORD */
#include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */
-
-#if defined(WITH_ARIA_STORAGE_ENGINE)
-#include <maria.h>
-#endif
-#if defined(USE_ARIA_FOR_TMP_TABLES)
-#define TMP_ENGINE_HTON maria_hton
-inline uint tmp_table_max_key_length() {
- return maria_max_key_length();
-}
-
-inline uint tmp_table_max_key_parts() {
- return maria_max_key_segments();
-}
-#else
-#define TMP_ENGINE_HTON myisam_hton
-inline uint tmp_table_max_key_length() {
- return MI_MAX_KEY_LENGTH;
-}
-inline uint tmp_table_max_key_parts() {
- return MI_MAX_KEY_SEG;
-}
-#endif
/* Values in optimize */
#define KEY_OPTIMIZE_EXISTS 1
#define KEY_OPTIMIZE_REF_OR_NULL 2
@@ -114,6 +91,13 @@ typedef struct st_table_ref
uchar *key_buff; ///< value to look for with key
uchar *key_buff2; ///< key_buff+key_length
store_key **key_copy; //
+
+ /*
+ Bitmap of key parts which refer to constants. key_copy only has copiers for
+ non-const key parts.
+ */
+ key_part_map const_ref_part_map;
+
Item **items; ///< val()'s for each keypart
/*
Array of pointers to trigger variables. Some/all of the pointers may be
@@ -204,12 +188,17 @@ int rr_sequential(READ_RECORD *info);
int rr_sequential_and_unpack(READ_RECORD *info);
+#include "sql_explain.h"
+
+/**************************************************************************************
+ * New EXPLAIN structures END
+ *************************************************************************************/
+
class JOIN_CACHE;
class SJ_TMP_TABLE;
class JOIN_TAB_RANGE;
typedef struct st_join_table {
- st_join_table() {} /* Remove gcc warning */
TABLE *table;
KEYUSE *keyuse; /**< pointer to first used key */
KEY *hj_key; /**< descriptor of the used best hash join key
@@ -258,7 +247,11 @@ typedef struct st_join_table {
JOIN_TAB_RANGE *bush_children;
/* Special content for EXPLAIN 'Extra' column or NULL if none */
- const char *info;
+ enum explain_extra_tag info;
+
+ Table_access_tracker *tracker;
+
+ Table_access_tracker *jbuf_tracker;
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info.
@@ -295,8 +288,11 @@ typedef struct st_join_table {
*/
double read_time;
- /* psergey-todo: make the below have type double, like POSITION::records_read? */
- ha_rows records_read;
+ /* Copy of POSITION::records_read, set by get_best_combination() */
+ double records_read;
+
+ /* The selectivity of the conditions that can be pushed to the table */
+ double cond_selectivity;
/* Startup cost for execution */
double startup_cost;
@@ -364,7 +360,12 @@ typedef struct st_join_table {
SJ_TMP_TABLE *check_weed_out_table;
/* for EXPLAIN only: */
SJ_TMP_TABLE *first_weedout_table;
-
+
+ /**
+ reference to saved plan and execution statistics
+ */
+ Explain_table_access *explain_plan;
+
/*
If set, means we should stop join enumeration after we've got the first
match and return to the specified join tab. May point to
@@ -529,7 +530,22 @@ typedef struct st_join_table {
ha_rows get_examined_rows();
bool preread_init();
- bool is_sjm_nest() { return test(bush_children); }
+ bool is_sjm_nest() { return MY_TEST(bush_children); }
+
+ /*
+ If this join_tab reads a non-merged semi-join (also called jtbm), return
+ the select's number. Otherwise, return 0.
+ */
+ int get_non_merged_semijoin_select() const
+ {
+ Item_in_subselect *subq;
+ if (table->pos_in_table_list &&
+ (subq= table->pos_in_table_list->jtbm_subselect))
+ {
+ return subq->unit->first_select()->select_number;
+ }
+ return 0; /* Not a merged semi-join */
+ }
bool access_from_tables_is_allowed(table_map used_tables,
table_map sjm_lookup_tables)
@@ -542,6 +558,12 @@ typedef struct st_join_table {
bool keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, KEYUSE *keyuse);
+ void remove_redundant_bnl_scan_conds();
+
+ void save_explain_data(Explain_table_access *eta, table_map prefix_tables,
+ bool distinct, struct st_join_table *first_top_tab);
+
+ void update_explain_data(uint idx);
} JOIN_TAB;
@@ -723,8 +745,7 @@ public:
struct st_position *pos,
struct st_position *loose_scan_pos);
friend bool get_best_combination(JOIN *join);
- friend int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
- uint no_jbuf_after);
+ friend int setup_semijoin_loosescan(JOIN *join);
friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
};
@@ -746,7 +767,7 @@ public:
void set_empty()
{
sjm_scan_need_tables= 0;
- LINT_INIT(sjm_scan_last_inner);
+ LINT_INIT_STRUCT(sjm_scan_last_inner);
is_used= FALSE;
}
void set_from_prev(struct st_position *prev);
@@ -769,7 +790,7 @@ public:
Information about a position of table within a join order. Used in join
optimization.
*/
-typedef struct st_position :public Sql_alloc
+typedef struct st_position
{
/* The table that's put into join order */
JOIN_TAB *table;
@@ -781,6 +802,9 @@ typedef struct st_position :public Sql_alloc
*/
double records_read;
+ /* The selectivity of the pushed down conditions */
+ double cond_selectivity;
+
/*
Cost accessing the table in course of the entire complete join execution,
i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times
@@ -789,7 +813,7 @@ typedef struct st_position :public Sql_alloc
double read_time;
/* Cumulative cost and record count for the join prefix */
- COST_VECT prefix_cost;
+ Cost_estimate prefix_cost;
double prefix_record_count;
/*
@@ -860,6 +884,7 @@ public:
JOIN_TAB *end;
};
+class Pushdown_query;
class JOIN :public Sql_alloc
{
@@ -889,6 +914,7 @@ protected:
{
keyuse.elements= 0;
keyuse.buffer= NULL;
+ keyuse.malloc_flags= 0;
best_positions= 0; /* To detect errors */
error= my_multi_malloc(MYF(MY_WME),
&best_positions,
@@ -913,7 +939,7 @@ protected:
enum enum_reopt_result {
REOPT_NEW_PLAN, /* there is a new reoptimized plan */
REOPT_OLD_PLAN, /* no new improved plan can be found, use the old one */
- REOPT_ERROR, /* an irrecovarable error occured during reoptimization */
+ REOPT_ERROR, /* an irrecovarable error occurred during reoptimization */
REOPT_NONE /* not yet reoptimized */
};
@@ -951,7 +977,7 @@ public:
*/
JOIN_TAB *table_access_tabs;
uint top_table_access_tabs_count;
-
+
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
@@ -986,7 +1012,19 @@ public:
*/
uint top_join_tab_count;
uint send_group_parts;
- bool group; /**< If query contains GROUP BY clause */
+ /*
+ This counts how many times do_select() was invoked for this JOIN.
+ It's used to restrict Pushdown_query::execute() only to the first
+ do_select() invocation.
+ */
+ uint do_select_call_count;
+ /*
+ True if the query has GROUP BY.
+ (that is, if group_by != NULL. when DISTINCT is converted into GROUP BY, it
+ will set this, too. It is not clear why we need a separate var from
+ group_list)
+ */
+ bool group;
bool need_distinct;
/**
@@ -1025,8 +1063,24 @@ public:
table_map outer_join;
/* Bitmap of tables used in the select list items */
table_map select_list_used_tables;
- ha_rows send_records, found_records, examined_rows,
- row_limit, select_limit, duplicate_rows;
+ ha_rows send_records,found_records,join_examined_rows;
+
+ /*
+ LIMIT for the JOIN operation. When not using aggregation or DISITNCT, this
+ is the same as select's LIMIT clause specifies.
+ Note that this doesn't take sql_calc_found_rows into account.
+ */
+ ha_rows row_limit;
+
+ /*
+ How many output rows should be produced after GROUP BY.
+ (if sql_calc_found_rows is used, LIMIT is ignored)
+ */
+ ha_rows select_limit;
+ /*
+ Number of duplicate rows found in UNION.
+ */
+ ha_rows duplicate_rows;
/**
Used to fetch no more than given amount of rows per one
fetch operation of server side cursor.
@@ -1035,11 +1089,17 @@ public:
- fetch_limit= HA_POS_ERROR if there is no cursor.
- when we open a cursor, we set fetch_limit to 0,
- on each fetch iteration we add num_rows to fetch to fetch_limit
+ NOTE: currently always HA_POS_ERROR.
*/
ha_rows fetch_limit;
+
/* Finally picked QEP. This is result of join optimization */
POSITION *best_positions;
+ Pushdown_query *pushdown_query;
+ JOIN_TAB *original_join_tab;
+ uint original_table_count;
+
/******* Join optimization state members start *******/
/*
pointer - we're doing optimization for a semi-join materialization nest.
@@ -1084,7 +1144,7 @@ public:
reexecutions. This value is equal to the multiplication of all
join->positions[i].records_read of a JOIN.
*/
- double record_count;
+ double join_record_count;
List<Item> *fields;
List<Cached_item> group_fields, group_fields_cache;
TABLE *tmp_table;
@@ -1129,6 +1189,12 @@ public:
restore_no_rows_in_result() in ::reinit()
*/
bool no_rows_in_result_called;
+
+ /**
+ This is set if SQL_CALC_ROWS was calculated by filesort()
+ and should be taken from the appropriate JOIN_TAB
+ */
+ bool filesort_found_rows;
/**
Copy of this JOIN to be used with temporary tables.
@@ -1179,7 +1245,8 @@ public:
/** Is set if we have a GROUP BY and we have ORDER BY on a constant. */
bool skip_sort_order;
- bool need_tmp, hidden_group_fields;
+ bool need_tmp;
+ bool hidden_group_fields;
/* TRUE if there was full cleunap of the JOIN */
bool cleaned;
DYNAMIC_ARRAY keyuse;
@@ -1229,9 +1296,18 @@ public:
const char *zero_result_cause; ///< not 0 if exec must return zero result
bool union_part; ///< this subselect is part of union
- bool optimized; ///< flag to avoid double optimization in EXPLAIN
+
+ enum join_optimization_state { NOT_OPTIMIZED=0,
+ OPTIMIZATION_IN_PROGRESS=1,
+ OPTIMIZATION_DONE=2};
+ // state of JOIN optimization
+ enum join_optimization_state optimization_state;
bool initialized; ///< flag to avoid double init_execution calls
+ Explain_select *explain;
+
+ enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE, QEP_DELETED} have_query_plan;
+
/*
Additional WHERE and HAVING predicates to be considered for IN=>EXISTS
subquery transformation of a JOIN object.
@@ -1274,6 +1350,7 @@ public:
table_count= 0;
top_join_tab_count= 0;
const_tables= 0;
+ const_table_map= 0;
eliminated_tables= 0;
join_list= 0;
implicit_grouping= FALSE;
@@ -1283,7 +1360,7 @@ public:
duplicate_rows= send_records= 0;
found_records= 0;
fetch_limit= HA_POS_ERROR;
- examined_rows= 0;
+ join_examined_rows= 0;
exec_tmp_table1= 0;
exec_tmp_table2= 0;
sortorder= 0;
@@ -1298,7 +1375,7 @@ public:
lock= thd_arg->lock;
select_lex= 0; //for safety
tmp_join= 0;
- select_distinct= test(select_options & SELECT_DISTINCT);
+ select_distinct= MY_TEST(select_options & SELECT_DISTINCT);
no_order= 0;
simple_order= 0;
simple_group= 0;
@@ -1312,7 +1389,8 @@ public:
ref_pointer_array= items0= items1= items2= items3= 0;
ref_pointer_array_size= 0;
zero_result_cause= 0;
- optimized= 0;
+ optimization_state= JOIN::NOT_OPTIMIZED;
+ have_query_plan= QEP_NOT_PRESENT_YET;
initialized= 0;
cleaned= 0;
cond_equal= 0;
@@ -1321,6 +1399,11 @@ public:
group_optimized_away= 0;
no_rows_in_result_called= 0;
positions= best_positions= 0;
+ pushdown_query= 0;
+ original_join_tab= 0;
+ do_select_call_count= 0;
+
+ explain= NULL;
all_fields= fields_arg;
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
@@ -1339,6 +1422,7 @@ public:
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
sjm_scan_tables= 0;
+
/*
The following is needed because JOIN::cleanup(true) may be called for
joins for which JOIN::optimize was aborted with an error before a proper
@@ -1353,9 +1437,11 @@ public:
SELECT_LEX_UNIT *unit);
bool prepare_stage2();
int optimize();
+ int optimize_inner();
int reinit();
int init_execution();
void exec();
+ void exec_inner();
int destroy();
void restore_tmp();
bool alloc_func_list();
@@ -1401,7 +1487,7 @@ public:
having_value != Item::COND_FALSE);
}
bool empty_result() { return (zero_result_cause && !implicit_grouping); }
- bool change_result(select_result *result);
+ bool change_result(select_result *new_result, select_result *old_result);
bool is_top_level_join() const
{
return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 ||
@@ -1431,7 +1517,7 @@ public:
void set_allowed_join_cache_types();
bool is_allowed_hash_join_access()
{
- return test(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
+ return MY_TEST(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT;
}
/*
@@ -1450,7 +1536,7 @@ public:
return ((const_tables != table_count &&
((select_distinct || !simple_order || !simple_group) ||
(group_list && order) ||
- test(select_options & OPTION_BUFFER_RESULT))) ||
+ MY_TEST(select_options & OPTION_BUFFER_RESULT))) ||
(rollup.state != ROLLUP::STATE_NONE && select_distinct));
}
bool choose_subquery_plan(table_map join_tables);
@@ -1469,6 +1555,13 @@ public:
{
return (unit->item && unit->item->is_in_predicate());
}
+ void save_explain_data(Explain_query *output, bool can_overwrite,
+ bool need_tmp_table, bool need_order, bool distinct);
+ int save_explain_data_intern(Explain_query *output, bool need_tmp_table,
+ bool need_order, bool distinct,
+ const char *message);
+ JOIN_TAB *first_breadth_first_optimization_tab() { return table_access_tabs; }
+ JOIN_TAB *first_breadth_first_execution_tab() { return join_tab; }
private:
/**
TRUE if the query contains an aggregate function but has no GROUP
@@ -1482,7 +1575,7 @@ private:
enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS};
enum enum_with_const_tables { WITH_CONST_TABLES, WITHOUT_CONST_TABLES};
-JOIN_TAB *first_linear_tab(JOIN *join,
+JOIN_TAB *first_linear_tab(JOIN *join,
enum enum_with_bush_roots include_bush_roots,
enum enum_with_const_tables const_tbls);
JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab,
@@ -1509,8 +1602,8 @@ bool copy_funcs(Item **func_ptr, const THD *thd);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
Field* create_tmp_field_from_field(THD *thd, Field* org_field,
const char *name, TABLE *table,
- Item_field *item, uint convert_blob_length);
-
+ Item_field *item);
+
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
/* functions from opt_sum.cc */
@@ -1532,21 +1625,8 @@ public:
store_key(THD *thd, Field *field_arg, uchar *ptr, uchar *null, uint length)
:null_key(0), null_ptr(null), err(0)
{
- if (field_arg->type() == MYSQL_TYPE_BLOB
- || field_arg->type() == MYSQL_TYPE_GEOMETRY)
- {
- /*
- Key segments are always packed with a 2 byte length prefix.
- See mi_rkey for details.
- */
- to_field= new Field_varstring(ptr, length, 2, null, 1,
- Field::NONE, field_arg->field_name,
- field_arg->table->s, field_arg->charset());
- to_field->init(field_arg->table);
- }
- else
- to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
- ptr, null, 1);
+ to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
+ ptr, length, null, 1);
}
store_key(store_key &arg)
:Sql_alloc(), null_key(arg.null_key), to_field(arg.to_field),
@@ -1752,9 +1832,10 @@ bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
-COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
int get_quick_record(SQL_SELECT *select);
-SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
+SORT_FIELD *make_unireg_sortorder(THD *thd, JOIN *join,
+ table_map first_table_map,
+ ORDER *order, uint *length,
SORT_FIELD *sortorder);
int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List <Item> &all_fields, ORDER *order);
@@ -1782,12 +1863,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Field **def_field,
bool group, bool modify_item,
bool table_cant_handle_bit_fields,
- bool make_copy_field,
- uint convert_blob_length);
-bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
- ENGINE_COLUMNDEF *start_recinfo,
- ENGINE_COLUMNDEF **recinfo,
- ulonglong options, my_bool big_tables);
+ bool make_copy_field);
/*
General routine to change field->ptr of a NULL-terminated array of Field
@@ -1803,9 +1879,9 @@ int test_if_item_cache_changed(List<Cached_item> &list);
int join_init_read_record(JOIN_TAB *tab);
int join_read_record_no_init(JOIN_TAB *tab);
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key);
-inline Item * and_items(Item* cond, Item *item)
+inline Item * and_items(THD *thd, Item* cond, Item *item)
{
- return (cond? (new Item_cond_and(cond, item)) : item);
+ return (cond ? (new (thd->mem_root) Item_cond_and(thd, cond, item)) : item);
}
bool choose_plan(JOIN *join, table_map join_tables);
void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
@@ -1822,8 +1898,14 @@ inline bool optimizer_flag(THD *thd, uint flag)
return (thd->variables.optimizer_switch & flag);
}
+/*
+int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly,
+ SELECT_LEX *select_lex, uint8 select_options);
+*/
+
uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
- ha_rows limit, bool *need_sort, bool *reverse);
+ ha_rows limit, ha_rows *scanned_limit,
+ bool *need_sort, bool *reverse);
ORDER *simple_remove_const(ORDER *order, COND *where);
bool const_expression_in_where(COND *cond, Item *comp_item,
Field *comp_field= NULL,
@@ -1837,6 +1919,19 @@ void eliminate_tables(JOIN *join);
/* Index Condition Pushdown entry point function */
void push_index_cond(JOIN_TAB *tab, uint keyno);
+#define OPT_LINK_EQUAL_FIELDS 1
+
+/* EXPLAIN-related utility functions */
+int print_explain_message_line(select_result_sink *result,
+ uint8 options, bool is_analyze,
+ uint select_number,
+ const char *select_type,
+ ha_rows *rows,
+ const char *message);
+void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res);
+int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table,
+ key_map possible_keys);
+
/****************************************************************************
Temporary table support for SQL Runtime
***************************************************************************/
@@ -1853,17 +1948,48 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bool keep_row_order= FALSE);
void free_tmp_table(THD *thd, TABLE *entry);
bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
- ENGINE_COLUMNDEF *start_recinfo,
- ENGINE_COLUMNDEF **recinfo,
+ TMP_ENGINE_COLUMNDEF *start_recinfo,
+ TMP_ENGINE_COLUMNDEF **recinfo,
int error, bool ignore_last_dupp_key_error,
bool *is_duplicate);
bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
- ENGINE_COLUMNDEF *start_recinfo,
- ENGINE_COLUMNDEF **recinfo,
+ TMP_ENGINE_COLUMNDEF *start_recinfo,
+ TMP_ENGINE_COLUMNDEF **recinfo,
ulonglong options);
bool open_tmp_table(TABLE *table);
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
double prev_record_reads(POSITION *positions, uint idx, table_map found_ref);
void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist);
+struct st_cond_statistic
+{
+ Item *cond;
+ Field *field_arg;
+ ulong positive;
+};
+typedef struct st_cond_statistic COND_STATISTIC;
+
+ulong check_selectivity(THD *thd,
+ ulong rows_to_read,
+ TABLE *table,
+ List<COND_STATISTIC> *conds);
+
+class Pushdown_query: public Sql_alloc
+{
+public:
+ SELECT_LEX *select_lex;
+ bool store_data_in_temp_table;
+ group_by_handler *handler;
+ Item *having;
+
+ Pushdown_query(SELECT_LEX *select_lex_arg, group_by_handler *handler_arg)
+ : select_lex(select_lex_arg), store_data_in_temp_table(0),
+ handler(handler_arg), having(0) {}
+
+ ~Pushdown_query() { delete handler; }
+
+ /* Function that calls the above scan functions */
+ int execute(JOIN *join);
+};
+
#endif /* SQL_SELECT_INCLUDED */