Skip to content

Commit d39e6b2

Browse files
author
Ole John Aske
committed
Optimization of how parent operations are choosen in SPJ queries.
Patch introduce usage of fanout-statistics in optimization of how we select 'parent relations' for scan childs.
1 parent 6a361b5 commit d39e6b2

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

sql/abstract_query_plan.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,33 @@ namespace AQP
261261
return get_join_tab()->table;
262262
}
263263

264+
double Table_access::get_fanout() const
265+
{
266+
switch (get_access_type())
267+
{
268+
case AT_PRIMARY_KEY:
269+
case AT_UNIQUE_KEY:
270+
return 1.0;
271+
272+
case AT_ORDERED_INDEX_SCAN:
273+
DBUG_ASSERT(get_join_tab()->join->best_positions[m_tab_no].records_read>0.0);
274+
return get_join_tab()->join->best_positions[m_tab_no].records_read;
275+
276+
case AT_MULTI_PRIMARY_KEY:
277+
case AT_MULTI_UNIQUE_KEY:
278+
case AT_MULTI_MIXED:
279+
DBUG_ASSERT(get_join_tab()->join->best_positions[m_tab_no].records_read>0.0);
280+
return get_join_tab()->join->best_positions[m_tab_no].records_read;
281+
282+
case AT_TABLE_SCAN:
283+
DBUG_ASSERT(get_join_tab()->table->file->stats.records>0.0);
284+
return get_join_tab()->table->file->stats.records;
285+
286+
default:
287+
return 99999999.0;
288+
}
289+
}
290+
264291
/** Get the JOIN_TAB object that corresponds to this operation.*/
265292
const JOIN_TAB* Table_access::get_join_tab() const
266293
{

sql/abstract_query_plan.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ namespace AQP
205205

206206
st_table* get_table() const;
207207

208+
double get_fanout() const;
209+
208210
Item_equal* get_item_equal(const Item_field* field_item) const;
209211

210212
void dbug_print() const;

sql/ha_ndbcluster_push.cc

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,12 +1063,20 @@ ndb_pushed_builder_ctx::optimize_query_plan()
10631063
DBUG_ENTER("optimize_query_plan");
10641064
const uint root_no= m_join_root->get_access_no();
10651065

1066+
for (uint tab_no= root_no; tab_no<m_plan.get_access_count(); tab_no++)
1067+
{
1068+
if (m_join_scope.contain(tab_no))
1069+
{
1070+
m_tables[tab_no].m_fanout = m_plan.get_table_access(tab_no)->get_fanout();
1071+
m_tables[tab_no].m_child_fanout = 1.0;
1072+
}
1073+
}
1074+
10661075
// Find an optimal order for joining the tables
10671076
for (uint tab_no= m_plan.get_access_count()-1;
10681077
tab_no > root_no;
10691078
tab_no--)
10701079
{
1071-
struct pushed_tables &table= m_tables[tab_no];
10721080
if (!m_join_scope.contain(tab_no))
10731081
continue;
10741082

@@ -1078,6 +1086,7 @@ ndb_pushed_builder_ctx::optimize_query_plan()
10781086
* don't skip any dependent parents from our ancestors
10791087
* when selecting the actuall 'm_parent' to be used.
10801088
*/
1089+
pushed_tables &table= m_tables[tab_no];
10811090
if (!table.m_depend_parents.is_clear_all())
10821091
{
10831092
ndb_table_access_map const &dependency= table.m_depend_parents;
@@ -1115,12 +1124,40 @@ ndb_pushed_builder_ctx::optimize_query_plan()
11151124

11161125
/**
11171126
* In order to take advantage of the parallelism in the SPJ block;
1118-
* Choose the first possible parent candidate. Will result in the
1119-
* most 'bushy' query plan (aka: star-join)
1127+
* Initial parent candidate is the first possible among 'parents'.
1128+
* Will result in the most 'bushy' query plan (aka: star-join)
11201129
*/
11211130
parent_no= parents.first_table(root_no);
1131+
1132+
if (table.m_fanout*table.m_child_fanout > 1.0 ||
1133+
!ndbcluster_is_lookup_operation(m_plan.get_table_access(tab_no)->get_access_type()))
1134+
{
1135+
/**
1136+
* This is a index-scan or lookup with scan childs.
1137+
* Push optimization for index-scan execute:
1138+
*
1139+
* These are relative expensive operation which we try to avoid to
1140+
* execute whenever possible. By making them depending on parent
1141+
* operations with high selectivity, they will be eliminated when
1142+
* the parent returns no matching rows.
1143+
*
1144+
* -> Execute index-scan after any such parents
1145+
*/
1146+
for (uint candidate= parent_no+1; candidate<parents.length(); candidate++)
1147+
{
1148+
if (parents.contain(candidate))
1149+
{
1150+
if (m_tables[candidate].m_fanout > 1.0)
1151+
break;
1152+
1153+
parent_no= candidate; // Parent candidate is selective, eval after
1154+
}
1155+
}
1156+
}
1157+
11221158
DBUG_ASSERT(parent_no < tab_no);
11231159
table.m_parent= parent_no;
1160+
m_tables[parent_no].m_child_fanout*= table.m_fanout*table.m_child_fanout;
11241161

11251162
ndb_table_access_map dependency(table.m_depend_parents);
11261163
dependency.clear_bit(parent_no);
@@ -1134,7 +1171,7 @@ ndb_pushed_builder_ctx::optimize_query_plan()
11341171
{
11351172
if (m_join_scope.contain(tab_no))
11361173
{
1137-
struct pushed_tables &table= m_tables[tab_no];
1174+
pushed_tables &table= m_tables[tab_no];
11381175
const uint parent_no= table.m_parent;
11391176
table.m_ancestors= m_tables[parent_no].m_ancestors;
11401177
table.m_ancestors.add(parent_no);

sql/ha_ndbcluster_push.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ class ndb_pushed_builder_ctx
283283
m_depend_parents(),
284284
m_parent(MAX_TABLES),
285285
m_ancestors(),
286+
m_fanout(1.0),
287+
m_child_fanout(1.0),
286288
m_op(NULL)
287289
{}
288290

@@ -317,6 +319,16 @@ class ndb_pushed_builder_ctx
317319
*/
318320
ndb_table_access_map m_ancestors;
319321

322+
/**
323+
* The fanout of this table.
324+
*/
325+
double m_fanout;
326+
327+
/**
328+
* The (cross) product of all child fanouts.
329+
*/
330+
double m_child_fanout;
331+
320332
const NdbQueryOperationDef* m_op;
321333
} m_tables[MAX_TABLES];
322334

0 commit comments

Comments
 (0)