MySQL 9.1.0
Source Code Documentation
anonymous_namespace{join_optimizer.cc}::CostingReceiver Class Reference

CostingReceiver contains the main join planning logic, selecting access paths based on cost. More...

Classes

struct  AccessPathSet
 Besides the access paths for a set of nodes (see m_access_paths), AccessPathSet contains information that is common between all access paths for that set. More...
 
struct  FindRangeScansResult
 Return type for FindRangeScans(). More...
 
struct  ProposeRefsResult
 Return value of ProposeRefs. More...
 

Public Member Functions

 CostingReceiver (THD *thd, Query_block *query_block, JoinHypergraph &graph, const LogicalOrderings *orderings, const Mem_root_array< SortAheadOrdering > *sort_ahead_orderings, const Mem_root_array< ActiveIndexInfo > *active_indexes, const Mem_root_array< SpatialDistanceScanInfo > *spatial_indexes, const Mem_root_array< FullTextIndexInfo > *fulltext_searches, NodeMap fulltext_tables, uint64_t sargable_fulltext_predicates, table_map update_delete_target_tables, table_map immediate_update_delete_candidates, bool need_rowid, SecondaryEngineFlags engine_flags, int subgraph_pair_limit, secondary_engine_modify_access_path_cost_t secondary_engine_cost_hook, secondary_engine_check_optimizer_request_t secondary_engine_planning_complexity_check_hook)
 
CostingReceiveroperator= (const CostingReceiver &)=delete
 
CostingReceiveroperator= (CostingReceiver &&)=default
 
 CostingReceiver (const CostingReceiver &)=delete
 
 CostingReceiver (CostingReceiver &&)=default
 
bool HasSeen (NodeMap subgraph) const
 
bool FoundSingleNode (int node_idx)
 
bool evaluate_secondary_engine_optimizer_state_request ()
 
bool FoundSubgraphPair (NodeMap left, NodeMap right, int edge_idx)
 
const AccessPathArray root_candidates ()
 
FunctionalDependencySet active_fds_at_root () const
 
size_t num_subplans () const
 
size_t num_access_paths () const
 
int subgraph_pair_limit () const
 
bool always_empty () const
 True if the result of the join is found to be always empty, typically because of an impossible WHERE clause. More...
 
AccessPathProposeAccessPath (AccessPath *path, AccessPathArray *existing_paths, OrderingSet obsolete_orderings, const char *description_for_trace) const
 
bool HasSecondaryEngineCostHook () const
 

Private Member Functions

string PrintSet (NodeMap x) const
 For trace use only. More...
 
string PrintSubgraphHeader (const JoinPredicate *edge, const AccessPath &join_path, NodeMap left, NodeMap right) const
 For trace use only. More...
 
bool SupportedEngineFlag (SecondaryEngineFlag flag) const
 Checks whether the given engine flag is active or not. More...
 
bool FindIndexRangeScans (int node_idx, bool *impossible, double *num_output_rows_after_filter, bool force_imerge, bool force_skip_scan, bool *found_forced_plan)
 
bool SetUpRangeScans (int node_idx, bool *impossible, double *num_output_rows_after_filter, RANGE_OPT_PARAM *param, SEL_TREE **tree, Mem_root_array< PossibleRangeScan > *possible_scans, Mem_root_array< PossibleIndexMerge > *index_merges, Mem_root_array< PossibleIndexSkipScan > *index_skip_scans, MutableOverflowBitset *all_predicates)
 
void ProposeRangeScans (int node_idx, double num_output_rows_after_filter, RANGE_OPT_PARAM *param, SEL_TREE *tree, Mem_root_array< PossibleRangeScan > *possible_scans, bool *found_range_scan)
 
void ProposeAllIndexMergeScans (int node_idx, double num_output_rows_after_filter, RANGE_OPT_PARAM *param, SEL_TREE *tree, const Mem_root_array< PossibleRangeScan > *possible_scans, const Mem_root_array< PossibleIndexMerge > *index_merges, bool *found_imerge)
 
void ProposeIndexMerge (TABLE *table, int node_idx, const SEL_IMERGE &imerge, int pred_idx, bool inexact, bool allow_clustered_primary_key_scan, int num_where_predicates, double num_output_rows_after_filter, RANGE_OPT_PARAM *param, bool *has_clustered_primary_key_scan, bool *found_imerge)
 
void ProposeRowIdOrderedUnion (TABLE *table, int node_idx, const SEL_IMERGE &imerge, int pred_idx, bool inexact, int num_where_predicates, double num_output_rows_after_filter, const RANGE_OPT_PARAM *param, const Mem_root_array< AccessPath * > &paths, bool *found_imerge)
 
void ProposeAllRowIdOrderedIntersectPlans (TABLE *table, int node_idx, SEL_TREE *tree, int num_where_predicates, const Mem_root_array< PossibleRORScan > &possible_ror_scans, double num_output_rows_after_filter, const RANGE_OPT_PARAM *param, bool *found_imerge)
 
void ProposeRowIdOrderedIntersect (TABLE *table, int node_idx, int num_where_predicates, const Mem_root_array< PossibleRORScan > &possible_ror_scans, const Mem_root_array< ROR_SCAN_INFO * > &ror_scans, ROR_SCAN_INFO *cpk_scan, double num_output_rows_after_filter, const RANGE_OPT_PARAM *param, OverflowBitset needed_fields, bool *found_imerge)
 
void ProposeAllSkipScans (int node_idx, double num_output_rows_after_filter, RANGE_OPT_PARAM *param, SEL_TREE *tree, Mem_root_array< PossibleIndexSkipScan > *index_skip_scans, MutableOverflowBitset *all_predicates, bool *found_skip_scan)
 
void ProposeIndexSkipScan (int node_idx, RANGE_OPT_PARAM *param, AccessPath *skip_scan_path, TABLE *table, OverflowBitset all_predicates, size_t num_where_predicates, size_t predicate_idx, double num_output_rows_after_filter, bool inexact)
 
void TraceAccessPaths (NodeMap nodes)
 
void ProposeAccessPathForBaseTable (int node_idx, double force_num_output_rows_after_filter, const char *description_for_trace, AccessPath *path)
 
void ProposeAccessPathForIndex (int node_idx, OverflowBitset applied_predicates, OverflowBitset subsumed_predicates, double force_num_output_rows_after_filter, const char *description_for_trace, AccessPath *path)
 
void ProposeAccessPathWithOrderings (NodeMap nodes, FunctionalDependencySet fd_set, OrderingSet obsolete_orderings, AccessPath *path, const char *description_for_trace)
 
AccessPathMakeMaterializePath (const AccessPath &path, TABLE *table) const
 Make a path that materializes 'table'. More...
 
bool ProposeTableScan (TABLE *table, int node_idx, double force_num_output_rows_after_filter)
 
bool ProposeIndexScan (TABLE *table, int node_idx, double force_num_output_rows_after_filter, unsigned key_idx, bool reverse, int ordering_idx)
 
FindRangeScansResult FindRangeScans (int node_idx, Table_ref *table_ref)
 Propose possible range scan access paths for a single node. More...
 
std::optional< ProposeRefsResultProposeRefs (const ActiveIndexInfo &order_info, int node_idx, double row_estimate)
 Propose REF access paths for a single node and particular index. More...
 
bool ProposeDistanceIndexScan (TABLE *table, int node_idx, double force_num_output_rows_after_filter, const SpatialDistanceScanInfo &order_info, int ordering_idx)
 
bool ProposeAllUniqueIndexLookupsWithConstantKey (int node_idx, bool *found)
 
bool RedundantThroughSargable (OverflowBitset redundant_against_sargable_predicates, const AccessPath *left_path, const AccessPath *right_path, NodeMap left, NodeMap right)
 
pair< bool, bool > AlreadyAppliedAsSargable (Item *condition, const AccessPath *left_path, const AccessPath *right_path)
 
bool ProposeAllFullTextIndexScans (TABLE *table, int node_idx, double force_num_output_rows_after_filter, bool *found_fulltext)
 
bool ProposeFullTextIndexScan (TABLE *table, int node_idx, Item_func_match *match, int predicate_idx, int ordering_idx, double force_num_output_rows_after_filter)
 
void ProposeNestedLoopJoin (NodeMap left, NodeMap right, AccessPath *left_path, AccessPath *right_path, const JoinPredicate *edge, bool rewrite_semi_to_inner, FunctionalDependencySet new_fd_set, OrderingSet new_obsolete_orderings, bool *wrote_trace)
 
bool AllowNestedLoopJoin (NodeMap left, NodeMap right, const AccessPath &left_path, const AccessPath &right_path, const JoinPredicate &edge) const
 
void ProposeHashJoin (NodeMap left, NodeMap right, AccessPath *left_path, AccessPath *right_path, const JoinPredicate *edge, FunctionalDependencySet new_fd_set, OrderingSet new_obsolete_orderings, bool rewrite_semi_to_inner, bool *wrote_trace)
 
bool AllowHashJoin (NodeMap left, NodeMap right, const AccessPath &left_path, const AccessPath &right_path, const JoinPredicate &edge) const
 
void ApplyPredicatesForBaseTable (int node_idx, OverflowBitset applied_predicates, OverflowBitset subsumed_predicates, bool materialize_subqueries, double force_num_output_rows_after_filter, AccessPath *path, FunctionalDependencySet *new_fd_set)
 
void ApplyDelayedPredicatesAfterJoin (NodeMap left, NodeMap right, const AccessPath *left_path, const AccessPath *right_path, int join_predicate_first, int join_predicate_last, bool materialize_subqueries, AccessPath *join_path, FunctionalDependencySet *new_fd_set)
 
double FindAlreadyAppliedSelectivity (const JoinPredicate *edge, const AccessPath *left_path, const AccessPath *right_path, NodeMap left, NodeMap right)
 
void CommitBitsetsToHeap (AccessPath *path) const
 
bool BitsetsAreCommitted (AccessPath *path) const
 

Private Attributes

THDm_thd
 
Query_blockm_query_block
 The query block we are planning. More...
 
mem_root_unordered_map< NodeMap, AccessPathSetm_access_paths
 For each subset of tables that are connected in the join hypergraph, keeps the current best access paths for producing said subset. More...
 
int m_num_seen_subgraph_pairs = 0
 How many subgraph pairs we've seen so far. More...
 
JoinHypergraphm_graph
 The graph we are running over. More...
 
bool has_clamped_multipart_eq_ref = false
 Whether we have applied clamping due to a multi-column EQ_REF at any point. More...
 
bool has_semijoin_with_possibly_clamped_child = false
 Whether we have a semijoin where the inner child is parameterized on the outer child, and the row estimate of the inner child is possibly clamped, for example because of some other semijoin. More...
 
const LogicalOrderingsm_orderings
 Keeps track of interesting orderings in this query block. More...
 
const Mem_root_array< SortAheadOrdering > * m_sort_ahead_orderings
 List of all orderings that are candidates for sort-ahead (because they are, or may eventually become, an interesting ordering). More...
 
const Mem_root_array< ActiveIndexInfo > * m_active_indexes
 List of all indexes that are active and that we can apply in this query. More...
 
const Mem_root_array< SpatialDistanceScanInfo > * m_spatial_indexes
 List of all active spatial indexes that we can apply in this query. More...
 
const Mem_root_array< FullTextIndexInfo > * m_fulltext_searches
 List of all active full-text indexes that we can apply in this query. More...
 
NodeMap m_fulltext_tables = 0
 A map of tables that are referenced by a MATCH function (those tables that have Table_ref::is_fulltext_searched() == true). More...
 
uint64_t m_sargable_fulltext_predicates = 0
 The set of WHERE predicates which are on a form that can be satisfied by a full-text index scan. More...
 
NodeMap m_update_delete_target_nodes = 0
 The target tables of an UPDATE or DELETE statement. More...
 
NodeMap m_immediate_update_delete_candidates = 0
 The set of tables that are candidates for immediate update or delete. More...
 
bool m_need_rowid
 Whether we will be needing row IDs from our tables, typically for a later sort. More...
 
SecondaryEngineFlags m_engine_flags
 The flags declared by the secondary engine. More...
 
int m_subgraph_pair_limit
 The maximum number of pairs of subgraphs we are willing to accept, or -1 if no limit. More...
 
secondary_engine_modify_access_path_cost_t m_secondary_engine_cost_hook
 Pointer to a function that modifies the cost estimates of an access path for execution in a secondary storage engine, or nullptr otherwise. More...
 
secondary_engine_check_optimizer_request_t m_secondary_engine_planning_complexity_check
 Pointer to a function that returns what state should hypergraph progress for optimization with secondary storage engine, or nullptr otherwise. More...
 
NodeMap forced_leftmost_table = 0
 A map of tables that can never be on the right side of any join, ie., they have to be leftmost in the tree. More...
 
MEM_ROOT m_overflow_bitset_mem_root
 A special MEM_ROOT for allocating OverflowBitsets that we might end up discarding, ie. More...
 
MEM_ROOT m_range_optimizer_mem_root
 A special MEM_ROOT for temporary data for the range optimizer. More...
 

Friends

class RefAccessBuilder
 

Detailed Description

CostingReceiver contains the main join planning logic, selecting access paths based on cost.

It receives subplans from DPhyp (see enumerate_subgraph.h), assigns them costs based on a cost model, and keeps the ones that are cheapest. In the end, this means it will be left with a root access path that gives the lowest total cost for joining the tables in the query block, ie., without ORDER BY etc.

Currently, besides the expected number of produced rows (which is the same no matter how we access the table) we keep only a single value per subplan (total cost), and thus also only a single best access path. In the future, we will have more dimensions to worry about, such as initial cost versus total cost (relevant for LIMIT), ordering properties, and so on. At that point, there is not necessarily a single “best” access path anymore, and we will need to keep multiple ones around, and test all of them as candidates when building larger subplans.

Constructor & Destructor Documentation

◆ CostingReceiver() [1/3]

anonymous_namespace{join_optimizer.cc}::CostingReceiver::CostingReceiver ( THD thd,
Query_block query_block,
JoinHypergraph graph,
const LogicalOrderings orderings,
const Mem_root_array< SortAheadOrdering > *  sort_ahead_orderings,
const Mem_root_array< ActiveIndexInfo > *  active_indexes,
const Mem_root_array< SpatialDistanceScanInfo > *  spatial_indexes,
const Mem_root_array< FullTextIndexInfo > *  fulltext_searches,
NodeMap  fulltext_tables,
uint64_t  sargable_fulltext_predicates,
table_map  update_delete_target_tables,
table_map  immediate_update_delete_candidates,
bool  need_rowid,
SecondaryEngineFlags  engine_flags,
int  subgraph_pair_limit,
secondary_engine_modify_access_path_cost_t  secondary_engine_cost_hook,
secondary_engine_check_optimizer_request_t  secondary_engine_planning_complexity_check_hook 
)
inline

◆ CostingReceiver() [2/3]

anonymous_namespace{join_optimizer.cc}::CostingReceiver::CostingReceiver ( const CostingReceiver )
delete

◆ CostingReceiver() [3/3]

anonymous_namespace{join_optimizer.cc}::CostingReceiver::CostingReceiver ( CostingReceiver &&  )
default

Member Function Documentation

◆ active_fds_at_root()

FunctionalDependencySet anonymous_namespace{join_optimizer.cc}::CostingReceiver::active_fds_at_root ( ) const
inline

◆ AllowHashJoin()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::AllowHashJoin ( NodeMap  left,
NodeMap  right,
const AccessPath left_path,
const AccessPath right_path,
const JoinPredicate edge 
) const
private

◆ AllowNestedLoopJoin()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::AllowNestedLoopJoin ( NodeMap  left,
NodeMap  right,
const AccessPath left_path,
const AccessPath right_path,
const JoinPredicate edge 
) const
private

◆ AlreadyAppliedAsSargable()

pair< bool, bool > anonymous_namespace{join_optimizer.cc}::CostingReceiver::AlreadyAppliedAsSargable ( Item condition,
const AccessPath left_path,
const AccessPath right_path 
)
inlineprivate

◆ always_empty()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::always_empty ( ) const
inline

True if the result of the join is found to be always empty, typically because of an impossible WHERE clause.

◆ ApplyDelayedPredicatesAfterJoin()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ApplyDelayedPredicatesAfterJoin ( NodeMap  left,
NodeMap  right,
const AccessPath left_path,
const AccessPath right_path,
int  join_predicate_first,
int  join_predicate_last,
bool  materialize_subqueries,
AccessPath join_path,
FunctionalDependencySet new_fd_set 
)
private

◆ ApplyPredicatesForBaseTable()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ApplyPredicatesForBaseTable ( int  node_idx,
OverflowBitset  applied_predicates,
OverflowBitset  subsumed_predicates,
bool  materialize_subqueries,
double  force_num_output_rows_after_filter,
AccessPath path,
FunctionalDependencySet new_fd_set 
)
private

◆ BitsetsAreCommitted()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::BitsetsAreCommitted ( AccessPath path) const
private

◆ CommitBitsetsToHeap()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::CommitBitsetsToHeap ( AccessPath path) const
private

◆ evaluate_secondary_engine_optimizer_state_request()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::evaluate_secondary_engine_optimizer_state_request ( )

◆ FindAlreadyAppliedSelectivity()

double anonymous_namespace{join_optimizer.cc}::CostingReceiver::FindAlreadyAppliedSelectivity ( const JoinPredicate edge,
const AccessPath left_path,
const AccessPath right_path,
NodeMap  left,
NodeMap  right 
)
private

◆ FindIndexRangeScans()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::FindIndexRangeScans ( int  node_idx,
bool *  impossible,
double *  num_output_rows_after_filter,
bool  force_imerge,
bool  force_skip_scan,
bool *  found_forced_plan 
)
private

◆ FindRangeScans()

CostingReceiver::FindRangeScansResult anonymous_namespace{join_optimizer.cc}::CostingReceiver::FindRangeScans ( int  node_idx,
Table_ref table_ref 
)
private

Propose possible range scan access paths for a single node.

Parameters
node_idxThe hypergraph node for which we need paths.
table_refThe table accessed by that node.
Returns
Status and row estimate.

◆ FoundSingleNode()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::FoundSingleNode ( int  node_idx)

◆ FoundSubgraphPair()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::FoundSubgraphPair ( NodeMap  left,
NodeMap  right,
int  edge_idx 
)

◆ HasSecondaryEngineCostHook()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::HasSecondaryEngineCostHook ( ) const
inline

◆ HasSeen()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::HasSeen ( NodeMap  subgraph) const
inline

◆ MakeMaterializePath()

AccessPath * anonymous_namespace{join_optimizer.cc}::CostingReceiver::MakeMaterializePath ( const AccessPath path,
TABLE table 
) const
private

Make a path that materializes 'table'.

Parameters
pathThe table access path for the materialized table.
tableThe table to materialize.
Returns
The path that materializes 'table'.

◆ num_access_paths()

size_t anonymous_namespace{join_optimizer.cc}::CostingReceiver::num_access_paths ( ) const
inline

◆ num_subplans()

size_t anonymous_namespace{join_optimizer.cc}::CostingReceiver::num_subplans ( ) const
inline

◆ operator=() [1/2]

CostingReceiver & anonymous_namespace{join_optimizer.cc}::CostingReceiver::operator= ( const CostingReceiver )
delete

◆ operator=() [2/2]

CostingReceiver & anonymous_namespace{join_optimizer.cc}::CostingReceiver::operator= ( CostingReceiver &&  )
default

◆ PrintSet()

string anonymous_namespace{join_optimizer.cc}::CostingReceiver::PrintSet ( NodeMap  x) const
inlineprivate

For trace use only.

◆ PrintSubgraphHeader()

string anonymous_namespace{join_optimizer.cc}::CostingReceiver::PrintSubgraphHeader ( const JoinPredicate edge,
const AccessPath join_path,
NodeMap  left,
NodeMap  right 
) const
private

For trace use only.

◆ ProposeAccessPath()

AccessPath * anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAccessPath ( AccessPath path,
AccessPathArray existing_paths,
OrderingSet  obsolete_orderings,
const char *  description_for_trace 
) const

◆ ProposeAccessPathForBaseTable()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAccessPathForBaseTable ( int  node_idx,
double  force_num_output_rows_after_filter,
const char *  description_for_trace,
AccessPath path 
)
private

◆ ProposeAccessPathForIndex()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAccessPathForIndex ( int  node_idx,
OverflowBitset  applied_predicates,
OverflowBitset  subsumed_predicates,
double  force_num_output_rows_after_filter,
const char *  description_for_trace,
AccessPath path 
)
private

◆ ProposeAccessPathWithOrderings()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAccessPathWithOrderings ( NodeMap  nodes,
FunctionalDependencySet  fd_set,
OrderingSet  obsolete_orderings,
AccessPath path,
const char *  description_for_trace 
)
private

◆ ProposeAllFullTextIndexScans()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAllFullTextIndexScans ( TABLE table,
int  node_idx,
double  force_num_output_rows_after_filter,
bool *  found_fulltext 
)
private

◆ ProposeAllIndexMergeScans()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAllIndexMergeScans ( int  node_idx,
double  num_output_rows_after_filter,
RANGE_OPT_PARAM param,
SEL_TREE tree,
const Mem_root_array< PossibleRangeScan > *  possible_scans,
const Mem_root_array< PossibleIndexMerge > *  index_merges,
bool *  found_imerge 
)
private

◆ ProposeAllRowIdOrderedIntersectPlans()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAllRowIdOrderedIntersectPlans ( TABLE table,
int  node_idx,
SEL_TREE tree,
int  num_where_predicates,
const Mem_root_array< PossibleRORScan > &  possible_ror_scans,
double  num_output_rows_after_filter,
const RANGE_OPT_PARAM param,
bool *  found_imerge 
)
private

◆ ProposeAllSkipScans()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAllSkipScans ( int  node_idx,
double  num_output_rows_after_filter,
RANGE_OPT_PARAM param,
SEL_TREE tree,
Mem_root_array< PossibleIndexSkipScan > *  index_skip_scans,
MutableOverflowBitset all_predicates,
bool *  found_skip_scan 
)
private

◆ ProposeAllUniqueIndexLookupsWithConstantKey()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeAllUniqueIndexLookupsWithConstantKey ( int  node_idx,
bool *  found 
)
private

◆ ProposeDistanceIndexScan()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeDistanceIndexScan ( TABLE table,
int  node_idx,
double  force_num_output_rows_after_filter,
const SpatialDistanceScanInfo order_info,
int  ordering_idx 
)
private

◆ ProposeFullTextIndexScan()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeFullTextIndexScan ( TABLE table,
int  node_idx,
Item_func_match match,
int  predicate_idx,
int  ordering_idx,
double  force_num_output_rows_after_filter 
)
private

◆ ProposeHashJoin()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeHashJoin ( NodeMap  left,
NodeMap  right,
AccessPath left_path,
AccessPath right_path,
const JoinPredicate edge,
FunctionalDependencySet  new_fd_set,
OrderingSet  new_obsolete_orderings,
bool  rewrite_semi_to_inner,
bool *  wrote_trace 
)
private

◆ ProposeIndexMerge()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeIndexMerge ( TABLE table,
int  node_idx,
const SEL_IMERGE imerge,
int  pred_idx,
bool  inexact,
bool  allow_clustered_primary_key_scan,
int  num_where_predicates,
double  num_output_rows_after_filter,
RANGE_OPT_PARAM param,
bool *  has_clustered_primary_key_scan,
bool *  found_imerge 
)
private

◆ ProposeIndexScan()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeIndexScan ( TABLE table,
int  node_idx,
double  force_num_output_rows_after_filter,
unsigned  key_idx,
bool  reverse,
int  ordering_idx 
)
private

◆ ProposeIndexSkipScan()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeIndexSkipScan ( int  node_idx,
RANGE_OPT_PARAM param,
AccessPath skip_scan_path,
TABLE table,
OverflowBitset  all_predicates,
size_t  num_where_predicates,
size_t  predicate_idx,
double  num_output_rows_after_filter,
bool  inexact 
)
private

◆ ProposeNestedLoopJoin()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeNestedLoopJoin ( NodeMap  left,
NodeMap  right,
AccessPath left_path,
AccessPath right_path,
const JoinPredicate edge,
bool  rewrite_semi_to_inner,
FunctionalDependencySet  new_fd_set,
OrderingSet  new_obsolete_orderings,
bool *  wrote_trace 
)
private

◆ ProposeRangeScans()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeRangeScans ( int  node_idx,
double  num_output_rows_after_filter,
RANGE_OPT_PARAM param,
SEL_TREE tree,
Mem_root_array< PossibleRangeScan > *  possible_scans,
bool *  found_range_scan 
)
private

◆ ProposeRefs()

std::optional< CostingReceiver::ProposeRefsResult > anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeRefs ( const ActiveIndexInfo order_info,
int  node_idx,
double  row_estimate 
)
private

Propose REF access paths for a single node and particular index.

Parameters
order_infoThe index.
node_idxThe hypergraph node.
row_estimateThe estimated number of result rows.
Returns
A ProposeRefsResult object if there was no error.

◆ ProposeRowIdOrderedIntersect()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeRowIdOrderedIntersect ( TABLE table,
int  node_idx,
int  num_where_predicates,
const Mem_root_array< PossibleRORScan > &  possible_ror_scans,
const Mem_root_array< ROR_SCAN_INFO * > &  ror_scans,
ROR_SCAN_INFO cpk_scan,
double  num_output_rows_after_filter,
const RANGE_OPT_PARAM param,
OverflowBitset  needed_fields,
bool *  found_imerge 
)
private

◆ ProposeRowIdOrderedUnion()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeRowIdOrderedUnion ( TABLE table,
int  node_idx,
const SEL_IMERGE imerge,
int  pred_idx,
bool  inexact,
int  num_where_predicates,
double  num_output_rows_after_filter,
const RANGE_OPT_PARAM param,
const Mem_root_array< AccessPath * > &  paths,
bool *  found_imerge 
)
private

◆ ProposeTableScan()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::ProposeTableScan ( TABLE table,
int  node_idx,
double  force_num_output_rows_after_filter 
)
private

◆ RedundantThroughSargable()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::RedundantThroughSargable ( OverflowBitset  redundant_against_sargable_predicates,
const AccessPath left_path,
const AccessPath right_path,
NodeMap  left,
NodeMap  right 
)
private

◆ root_candidates()

const AccessPathArray anonymous_namespace{join_optimizer.cc}::CostingReceiver::root_candidates ( )
inline

◆ SetUpRangeScans()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::SetUpRangeScans ( int  node_idx,
bool *  impossible,
double *  num_output_rows_after_filter,
RANGE_OPT_PARAM param,
SEL_TREE **  tree,
Mem_root_array< PossibleRangeScan > *  possible_scans,
Mem_root_array< PossibleIndexMerge > *  index_merges,
Mem_root_array< PossibleIndexSkipScan > *  index_skip_scans,
MutableOverflowBitset all_predicates 
)
private

◆ subgraph_pair_limit()

int anonymous_namespace{join_optimizer.cc}::CostingReceiver::subgraph_pair_limit ( ) const
inline

◆ SupportedEngineFlag()

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::SupportedEngineFlag ( SecondaryEngineFlag  flag) const
inlineprivate

Checks whether the given engine flag is active or not.

◆ TraceAccessPaths()

void anonymous_namespace{join_optimizer.cc}::CostingReceiver::TraceAccessPaths ( NodeMap  nodes)
private

Friends And Related Function Documentation

◆ RefAccessBuilder

friend class RefAccessBuilder
friend

Member Data Documentation

◆ forced_leftmost_table

NodeMap anonymous_namespace{join_optimizer.cc}::CostingReceiver::forced_leftmost_table = 0
private

A map of tables that can never be on the right side of any join, ie., they have to be leftmost in the tree.

This only affects recursive table references (ie., when WITH RECURSIVE is in use); they work by continuously tailing new records, which wouldn't work if we were to scan them multiple times or put them in a hash table. Naturally, there must be zero or one bit here; the common case is zero.

◆ has_clamped_multipart_eq_ref

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::has_clamped_multipart_eq_ref = false
private

Whether we have applied clamping due to a multi-column EQ_REF at any point.

There is a known issue (see bug #33550360) where this can cause row count estimates to be inconsistent between different access paths. Obviously, we should fix this bug by adjusting the selectivities (and we do for single-column indexes), but for multipart indexes, this is nontrivial. See the bug for details on some ideas, but the gist of it is that we probably will want a linear program to adjust multi-selectivities so that they are consistent, and not above 1/N (for N-row tables) if there are unique indexes on them.

The only reason why we collect this information, like JoinHypergraph::has_reordered_left_joins, is to be able to assert on inconsistent row counts between APs, excluding this (known) issue.

◆ has_semijoin_with_possibly_clamped_child

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::has_semijoin_with_possibly_clamped_child = false
private

Whether we have a semijoin where the inner child is parameterized on the outer child, and the row estimate of the inner child is possibly clamped, for example because of some other semijoin.

In this case, we may see inconsistent row count estimates between the ordinary semijoin plan and the rewrite_semi_to_inner plan, because it's hard to tell how much the already-applied-as-sargable selectivity affected the row count estimate of the child.

The only reason why we collect this information, is to be able to assert on inconsistent row counts between access paths, excluding this known issue.

◆ m_access_paths

mem_root_unordered_map<NodeMap, AccessPathSet> anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_access_paths
private

For each subset of tables that are connected in the join hypergraph, keeps the current best access paths for producing said subset.

There can be several that are best in different ways; see comments on ProposeAccessPath().

Also used for communicating connectivity information back to DPhyp (in HasSeen()); if there's an entry here, that subset will induce a connected subgraph of the join hypergraph.

◆ m_active_indexes

const Mem_root_array<ActiveIndexInfo>* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_active_indexes
private

List of all indexes that are active and that we can apply in this query.

Indexes can be useful in several ways: We can use them for ref access, for index-only scans, or to get interesting orderings.

◆ m_engine_flags

SecondaryEngineFlags anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_engine_flags
private

The flags declared by the secondary engine.

In particular, it describes what kind of access path types should not be created.

◆ m_fulltext_searches

const Mem_root_array<FullTextIndexInfo>* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_fulltext_searches
private

List of all active full-text indexes that we can apply in this query.

◆ m_fulltext_tables

NodeMap anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_fulltext_tables = 0
private

A map of tables that are referenced by a MATCH function (those tables that have Table_ref::is_fulltext_searched() == true).

It is used for preventing hash joins involving tables that are full-text searched.

◆ m_graph

JoinHypergraph* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_graph
private

The graph we are running over.

◆ m_immediate_update_delete_candidates

NodeMap anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_immediate_update_delete_candidates = 0
private

The set of tables that are candidates for immediate update or delete.

Immediate update/delete means that the rows from the table are deleted while reading the rows from the topmost iterator. (As opposed to buffered update/delete, where the row IDs are stored in temporary tables, and only updated or deleted after the topmost iterator has been read to the end.) The candidates are those target tables that are only referenced once in the query. The requirement for immediate deletion is that the deleted row will not have to be read again later. Currently, at most one of the candidate tables is chosen, and it is always the outermost table in the join tree.

◆ m_need_rowid

bool anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_need_rowid
private

Whether we will be needing row IDs from our tables, typically for a later sort.

If this happens, derived tables cannot use streaming, but need an actual materialization, since filesort expects to be able to go back and ask for a given row. (This is different from when we need row IDs for weedout, which doesn't preclude streaming. The hypergraph optimizer does not use weedout.)

◆ m_num_seen_subgraph_pairs

int anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_num_seen_subgraph_pairs = 0
private

How many subgraph pairs we've seen so far.

Used to give up if we end up allocating too many resources (prompting us to create a simpler join graph and try again).

◆ m_orderings

const LogicalOrderings* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_orderings
private

Keeps track of interesting orderings in this query block.

See LogicalOrderings for more information.

◆ m_overflow_bitset_mem_root

MEM_ROOT anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_overflow_bitset_mem_root
private

A special MEM_ROOT for allocating OverflowBitsets that we might end up discarding, ie.

for AccessPaths that do not yet live in m_access_paths. For any AccessPath that is to have a permanent life (ie., not be immediately discarded as inferior), the OverflowBitset must be taken out of this MEM_ROOT and onto the regular one, as it is cleared often. (This significantly reduces the amount of memory used in situations where lots of AccessPaths are produced and discarded. Of course, it only matters for queries with >= 64 predicates.)

The copying is using CommitBitsetsToHeap(). ProposeAccessPath() will automatically call CommitBitsetsToHeap() for accepted access paths, but it will not call it on any of their children. Thus, if you've added more than one AccessPath in the chain (e.g. if you add a join, then a sort of that join, and then propose the sort), you will need to make sure there are no stray bitsets left on this MEM_ROOT.

Because this can be a source of subtle bugs, you should be conservative about what bitsets you put here; really, only the ones you could be allocating many of (like joins) should be candidates.

◆ m_query_block

Query_block* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_query_block
private

The query block we are planning.

◆ m_range_optimizer_mem_root

MEM_ROOT anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_range_optimizer_mem_root
private

A special MEM_ROOT for temporary data for the range optimizer.

It can be discarded immediately after we've decided on the range scans for a given table (but we reuse its memory as long as there are more tables left to scan).

◆ m_sargable_fulltext_predicates

uint64_t anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_sargable_fulltext_predicates = 0
private

The set of WHERE predicates which are on a form that can be satisfied by a full-text index scan.

This includes calls to MATCH with no comparison operator, and predicates on the form MATCH > const or MATCH >= const (where const must be high enough to make the comparison return false for documents with zero score).

◆ m_secondary_engine_cost_hook

secondary_engine_modify_access_path_cost_t anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_secondary_engine_cost_hook
private

Pointer to a function that modifies the cost estimates of an access path for execution in a secondary storage engine, or nullptr otherwise.

◆ m_secondary_engine_planning_complexity_check

secondary_engine_check_optimizer_request_t anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_secondary_engine_planning_complexity_check
private

Pointer to a function that returns what state should hypergraph progress for optimization with secondary storage engine, or nullptr otherwise.

◆ m_sort_ahead_orderings

const Mem_root_array<SortAheadOrdering>* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_sort_ahead_orderings
private

List of all orderings that are candidates for sort-ahead (because they are, or may eventually become, an interesting ordering).

◆ m_spatial_indexes

const Mem_root_array<SpatialDistanceScanInfo>* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_spatial_indexes
private

List of all active spatial indexes that we can apply in this query.

◆ m_subgraph_pair_limit

int anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_subgraph_pair_limit
private

The maximum number of pairs of subgraphs we are willing to accept, or -1 if no limit.

If this limit gets hit, we stop traversing the graph and return an error; the caller will then have to modify the hypergraph (see GraphSimplifier) to make for a graph with fewer options, so that planning time will come under an acceptable limit.

◆ m_thd

THD* anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_thd
private

◆ m_update_delete_target_nodes

NodeMap anonymous_namespace{join_optimizer.cc}::CostingReceiver::m_update_delete_target_nodes = 0
private

The target tables of an UPDATE or DELETE statement.


The documentation for this class was generated from the following file: