Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions src/include/duckdb/optimizer/join_order/join_relation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,46 +14,47 @@

namespace duckdb {

//! Set of relations, used in the join graph.
struct JoinRelationSet {
JoinRelationSet(unsafe_unique_array<idx_t> relations, idx_t count) : relations(std::move(relations)), count(count) {
JoinRelationSet() {
}
JoinRelationSet(unsafe_unique_array<idx_t> &relations_, idx_t count) {
for (idx_t i = 0; i < count; i++) {
relations[relations_[i]] = true;
}
}
static void EnumerateRelations(std::bitset<12> relations, const std::function<void(idx_t relation)> &callback);

string ToString() const;

unsafe_unique_array<idx_t> relations;
idx_t count;
idx_t Count() const;
idx_t NextNeighbor(idx_t i);
std::bitset<12> relations;

static bool IsSubset(JoinRelationSet &super, JoinRelationSet &sub);
JoinRelationSet Copy() const;
};

//! The JoinRelationTree is a structure holding all the created JoinRelationSet objects and allowing fast lookup on to
//! them
class JoinRelationSetManager {
public:
//! Contains a node with a JoinRelationSet and child relations
// FIXME: this structure is inefficient, could use a bitmap for lookup instead (todo: profile)
struct JoinRelationTreeNode {
unique_ptr<JoinRelationSet> relation;
unordered_map<idx_t, unique_ptr<JoinRelationTreeNode>> children;
};

public:
//! Create or get a JoinRelationSet from a single node with the given index
JoinRelationSet &GetJoinRelation(idx_t index);
reference<JoinRelationSet> GetJoinRelation(idx_t index);
//! Create or get a JoinRelationSet from a set of relation bindings
JoinRelationSet &GetJoinRelation(const unordered_set<idx_t> &bindings);
reference<JoinRelationSet> GetJoinRelation(const unordered_set<idx_t> &bindings);
//! Create or get a JoinRelationSet from a (sorted, duplicate-free!) list of relations
JoinRelationSet &GetJoinRelation(unsafe_unique_array<idx_t> relations, idx_t count);
reference<JoinRelationSet> GetJoinRelation(unsafe_unique_array<idx_t> relations, idx_t count);
//! Create or get a JoinRelationSet from another JoinRelation Set
reference<JoinRelationSet> GetJoinRelation(unique_ptr<JoinRelationSet> set);
//! Union two sets of relations together and create a new relation set
JoinRelationSet &Union(JoinRelationSet &left, JoinRelationSet &right);
reference<JoinRelationSet> Union(JoinRelationSet &left, JoinRelationSet &right);
// //! Create the set difference of left \ right (i.e. all elements in left that are not in right)
// JoinRelationSet *Difference(JoinRelationSet *left, JoinRelationSet *right);
string ToString() const;
void Print();

private:
JoinRelationTreeNode root;
unordered_map<std::bitset<12>, unique_ptr<JoinRelationSet>> active_relation_sets;
};

} // namespace duckdb
4 changes: 4 additions & 0 deletions src/include/duckdb/optimizer/join_order/query_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ struct NeighborInfo {
class QueryGraphEdges {
public:
//! Contains a node with info about neighboring relations and child edge infos
//! The root is a top level QueryEdge with no neighbors, then each child represents a single
//! relation node. Neighbors with these single nodes are in the neighbors vector.
//! If the edge is complex (like a+b = c), then the children structure is used to capture
//! the presence of [a, b].
struct QueryEdge {
vector<unique_ptr<NeighborInfo>> neighbors;
unordered_map<idx_t, unique_ptr<QueryEdge>> children;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class QueryGraphManager {
//! A map to store the optimal join plan found for a specific JoinRelationSet*
optional_ptr<const reference_map_t<JoinRelationSet, unique_ptr<DPJoinNode>>> plans;

private:
// private:
vector<reference<LogicalOperator>> filter_operators;

//! Filter information including the column_bindings that join filters
Expand Down
24 changes: 12 additions & 12 deletions src/optimizer/join_order/cardinality_estimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ bool CardinalityEstimator::EmptyFilter(FilterInfo &filter_info) {
}

void CardinalityEstimator::AddRelationTdom(FilterInfo &filter_info) {
D_ASSERT(filter_info.set.get().count >= 1);
D_ASSERT(filter_info.set.get().Count() >= 1);
for (const RelationsToTDom &r2tdom : relations_to_tdoms) {
auto &i_set = r2tdom.equivalent_relations;
if (i_set.find(filter_info.left_binding) != i_set.end()) {
Expand All @@ -37,7 +37,7 @@ void CardinalityEstimator::AddRelationTdom(FilterInfo &filter_info) {
}

bool CardinalityEstimator::SingleColumnFilter(duckdb::FilterInfo &filter_info) {
if (filter_info.left_set && filter_info.right_set && filter_info.set.get().count > 1) {
if (filter_info.left_set && filter_info.right_set && filter_info.set.get().Count() > 1) {
// Both set and are from different relations
return false;
}
Expand Down Expand Up @@ -111,8 +111,8 @@ void CardinalityEstimator::InitEquivalentRelations(const vector<unique_ptr<Filte
} else if (EmptyFilter(*filter)) {
continue;
}
D_ASSERT(filter->left_set->count >= 1);
D_ASSERT(filter->right_set->count >= 1);
D_ASSERT(filter->left_set->Count() >= 1);
D_ASSERT(filter->right_set->Count() >= 1);

auto matching_equivalent_sets = DetermineMatchingEquivalentSets(filter.get());
AddToEquivalenceSets(filter.get(), matching_equivalent_sets);
Expand All @@ -128,9 +128,9 @@ void CardinalityEstimator::RemoveEmptyTotalDomains() {

double CardinalityEstimator::GetNumerator(JoinRelationSet &set) {
double numerator = 1;
for (idx_t i = 0; i < set.count; i++) {
auto &single_node_set = set_manager.GetJoinRelation(set.relations[i]);
auto card_helper = relation_set_2_cardinality[single_node_set.ToString()];
for (idx_t i = 0; i < set.Count(); i++) {
auto single_node_set = set_manager.GetJoinRelation(set.relations[i]);
auto card_helper = relation_set_2_cardinality[single_node_set.get().ToString()];
numerator *= card_helper.cardinality_before_filters == 0 ? 1 : card_helper.cardinality_before_filters;
}
return numerator;
Expand Down Expand Up @@ -333,15 +333,15 @@ DenomInfo CardinalityEstimator::GetDenominator(JoinRelationSet &set) {
continue;
}
left_subgraph->numerator_relations = &UpdateNumeratorRelations(*left_subgraph, right_subgraph, edge);
left_subgraph->relations = &set_manager.Union(*left_subgraph->relations, *right_subgraph.relations);
left_subgraph->relations = set_manager.Union(*left_subgraph->relations, *right_subgraph.relations).get();
left_subgraph->denom = CalculateUpdatedDenom(*left_subgraph, right_subgraph, edge);
} else if (subgraph_connections.size() == 2) {
// The two subgraphs in the subgraph_connections can be merged by this edge.
D_ASSERT(subgraph_connections.at(0) < subgraph_connections.at(1));
auto subgraph_to_merge_into = &subgraphs.at(subgraph_connections.at(0));
auto subgraph_to_delete = &subgraphs.at(subgraph_connections.at(1));
subgraph_to_merge_into->relations =
&set_manager.Union(*subgraph_to_merge_into->relations, *subgraph_to_delete->relations);
set_manager.Union(*subgraph_to_merge_into->relations, *subgraph_to_delete->relations).get();
subgraph_to_merge_into->numerator_relations =
&UpdateNumeratorRelations(*subgraph_to_merge_into, *subgraph_to_delete, edge);
subgraph_to_merge_into->denom = CalculateUpdatedDenom(*subgraph_to_merge_into, *subgraph_to_delete, edge);
Expand All @@ -361,10 +361,10 @@ DenomInfo CardinalityEstimator::GetDenominator(JoinRelationSet &set) {
auto final_subgraph = subgraphs.at(0);
for (auto merge_with = subgraphs.begin() + 1; merge_with != subgraphs.end(); merge_with++) {
D_ASSERT(final_subgraph.relations && merge_with->relations);
final_subgraph.relations = &set_manager.Union(*final_subgraph.relations, *merge_with->relations);
final_subgraph.relations = set_manager.Union(*final_subgraph.relations, *merge_with->relations).get();
D_ASSERT(final_subgraph.numerator_relations && merge_with->numerator_relations);
final_subgraph.numerator_relations =
&set_manager.Union(*final_subgraph.numerator_relations, *merge_with->numerator_relations);
set_manager.Union(*final_subgraph.numerator_relations, *merge_with->numerator_relations).get();
final_subgraph.denom *= merge_with->denom;
}
}
Expand Down Expand Up @@ -431,7 +431,7 @@ void CardinalityEstimator::InitCardinalityEstimatorProps(optional_ptr<JoinRelati
}

void CardinalityEstimator::UpdateTotalDomains(optional_ptr<JoinRelationSet> set, RelationStats &stats) {
D_ASSERT(set->count == 1);
D_ASSERT(set->Count() == 1);
auto relation_id = set->relations[0];
//! Initialize the distinct count for all columns used in joins with the current relation.
// D_ASSERT(stats.column_distinct_count.size() >= 1);
Expand Down
2 changes: 1 addition & 1 deletion src/optimizer/join_order/cost_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CostModel::CostModel(QueryGraphManager &query_graph_manager)
}

double CostModel::ComputeCost(DPJoinNode &left, DPJoinNode &right) {
auto &combination = query_graph_manager.set_manager.Union(left.set, right.set);
auto combination = query_graph_manager.set_manager.Union(left.set, right.set);
auto join_card = cardinality_estimator.EstimateCardinalityWithSet<double>(combination);
auto join_cost = join_card;
return join_cost + left.cost + right.cost;
Expand Down
Loading
Loading