duckdb 0.8.2-dev2700.0 → 0.8.2-dev2809.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/icu/icu-makedate.cpp +12 -6
  3. package/src/duckdb/src/common/adbc/adbc.cpp +52 -21
  4. package/src/duckdb/src/common/adbc/driver_manager.cpp +12 -2
  5. package/src/duckdb/src/common/enum_util.cpp +5 -0
  6. package/src/duckdb/src/common/types/row/row_data_collection_scanner.cpp +35 -5
  7. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +283 -91
  8. package/src/duckdb/src/execution/operator/filter/physical_filter.cpp +1 -1
  9. package/src/duckdb/src/execution/operator/join/physical_comparison_join.cpp +1 -2
  10. package/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +1 -1
  11. package/src/duckdb/src/execution/physical_plan_generator.cpp +1 -6
  12. package/src/duckdb/src/execution/window_executor.cpp +10 -1
  13. package/src/duckdb/src/function/table/version/pragma_version.cpp +5 -2
  14. package/src/duckdb/src/include/duckdb/common/adbc/adbc.hpp +2 -0
  15. package/src/duckdb/src/include/duckdb/common/enums/pending_execution_result.hpp +1 -1
  16. package/src/duckdb/src/include/duckdb/common/types/row/row_data_collection_scanner.hpp +5 -1
  17. package/src/duckdb/src/include/duckdb/execution/physical_operator.hpp +0 -2
  18. package/src/duckdb/src/include/duckdb/main/pending_query_result.hpp +5 -0
  19. package/src/duckdb/src/include/duckdb/optimizer/join_order/cardinality_estimator.hpp +37 -63
  20. package/src/duckdb/src/include/duckdb/optimizer/join_order/cost_model.hpp +37 -0
  21. package/src/duckdb/src/include/duckdb/optimizer/join_order/join_node.hpp +14 -29
  22. package/src/duckdb/src/include/duckdb/optimizer/join_order/join_order_optimizer.hpp +7 -21
  23. package/src/duckdb/src/include/duckdb/optimizer/join_order/join_relation.hpp +0 -11
  24. package/src/duckdb/src/include/duckdb/optimizer/join_order/plan_enumerator.hpp +89 -0
  25. package/src/duckdb/src/include/duckdb/optimizer/join_order/query_graph.hpp +17 -31
  26. package/src/duckdb/src/include/duckdb/optimizer/join_order/query_graph_manager.hpp +113 -0
  27. package/src/duckdb/src/include/duckdb/optimizer/join_order/relation_manager.hpp +73 -0
  28. package/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp +73 -0
  29. package/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp +4 -1
  30. package/src/duckdb/src/include/duckdb/planner/logical_operator.hpp +0 -2
  31. package/src/duckdb/src/include/duckdb.h +11 -1
  32. package/src/duckdb/src/main/capi/pending-c.cpp +17 -0
  33. package/src/duckdb/src/main/pending_query_result.cpp +9 -1
  34. package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +79 -325
  35. package/src/duckdb/src/optimizer/join_order/cost_model.cpp +19 -0
  36. package/src/duckdb/src/optimizer/join_order/join_node.cpp +5 -37
  37. package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +48 -1078
  38. package/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp +552 -0
  39. package/src/duckdb/src/optimizer/join_order/query_graph.cpp +32 -29
  40. package/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp +409 -0
  41. package/src/duckdb/src/optimizer/join_order/relation_manager.cpp +356 -0
  42. package/src/duckdb/src/optimizer/join_order/relation_statistics_helper.cpp +351 -0
  43. package/src/duckdb/src/parallel/executor.cpp +6 -0
  44. package/src/duckdb/src/parallel/task_scheduler.cpp +7 -0
  45. package/src/duckdb/src/planner/binder/statement/bind_execute.cpp +1 -1
  46. package/src/duckdb/src/planner/operator/logical_get.cpp +4 -0
  47. package/src/duckdb/ub_src_optimizer_join_order.cpp +10 -0
@@ -0,0 +1,351 @@
1
+ #include "duckdb/optimizer/join_order/relation_statistics_helper.hpp"
2
+ #include "duckdb/planner/expression/list.hpp"
3
+ #include "duckdb/planner/operator/list.hpp"
4
+ #include "duckdb/planner/filter/conjunction_filter.hpp"
5
+ #include "duckdb/planner/expression_iterator.hpp"
6
+ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
7
+ #include "duckdb/function/table/table_scan.hpp"
8
+ #include "duckdb/planner/operator/logical_get.hpp"
9
+ #include "duckdb/storage/data_table.hpp"
10
+ #include "duckdb/planner/filter/constant_filter.hpp"
11
+
12
+ namespace duckdb {
13
+
14
+ static ExpressionBinding GetChildColumnBinding(Expression &expr) {
15
+ auto ret = ExpressionBinding();
16
+ switch (expr.expression_class) {
17
+ case ExpressionClass::BOUND_FUNCTION: {
18
+ // TODO: Other expression classes that can have 0 children?
19
+ auto &func = expr.Cast<BoundFunctionExpression>();
20
+ // no children some sort of gen_random_uuid() or equivalent.
21
+ if (func.children.empty()) {
22
+ ret.found_expression = true;
23
+ ret.expression_is_constant = true;
24
+ return ret;
25
+ }
26
+ break;
27
+ }
28
+ case ExpressionClass::BOUND_COLUMN_REF: {
29
+ ret.found_expression = true;
30
+ auto &new_col_ref = expr.Cast<BoundColumnRefExpression>();
31
+ ret.child_binding = ColumnBinding(new_col_ref.binding.table_index, new_col_ref.binding.column_index);
32
+ return ret;
33
+ }
34
+ case ExpressionClass::BOUND_LAMBDA_REF:
35
+ case ExpressionClass::BOUND_CONSTANT:
36
+ case ExpressionClass::BOUND_DEFAULT:
37
+ case ExpressionClass::BOUND_PARAMETER:
38
+ case ExpressionClass::BOUND_REF:
39
+ ret.found_expression = true;
40
+ ret.expression_is_constant = true;
41
+ return ret;
42
+ default:
43
+ break;
44
+ }
45
+ ExpressionIterator::EnumerateChildren(expr, [&](unique_ptr<Expression> &child) {
46
+ auto recursive_result = GetChildColumnBinding(*child);
47
+ if (recursive_result.found_expression) {
48
+ ret = recursive_result;
49
+ }
50
+ });
51
+ // we didn't find a Bound Column Ref
52
+ return ret;
53
+ }
54
+
55
+ RelationStats RelationStatisticsHelper::ExtractGetStats(LogicalGet &get, ClientContext &context) {
56
+ auto return_stats = RelationStats();
57
+
58
+ auto base_table_cardinality = get.EstimateCardinality(context);
59
+ auto cardinality_after_filters = base_table_cardinality;
60
+ unique_ptr<BaseStatistics> column_statistics;
61
+
62
+ auto table_thing = get.GetTable();
63
+ auto name = string("some table");
64
+ if (table_thing) {
65
+ name = table_thing->name;
66
+ return_stats.table_name = name;
67
+ }
68
+
69
+ // if we can get the catalog table, then our column statistics will be accurate
70
+ // parquet readers etc. will still return statistics, but they initialize distinct column
71
+ // counts to 0.
72
+ // TODO: fix this, some file formats can encode distinct counts, we don't want to rely on
73
+ // getting a catalog table to know that we can use statistics.
74
+ bool have_catalog_table_statistics = false;
75
+ if (get.GetTable()) {
76
+ have_catalog_table_statistics = true;
77
+ }
78
+
79
+ // first push back basic distinct counts for each column (if we have them).
80
+ for (idx_t i = 0; i < get.column_ids.size(); i++) {
81
+ bool have_distinct_count_stats = false;
82
+ if (get.function.statistics) {
83
+ column_statistics = get.function.statistics(context, get.bind_data.get(), get.column_ids[i]);
84
+ if (column_statistics && have_catalog_table_statistics) {
85
+ auto column_distinct_count = DistinctCount({column_statistics->GetDistinctCount(), true});
86
+ return_stats.column_distinct_count.push_back(column_distinct_count);
87
+ return_stats.column_names.push_back(name + "." + get.names.at(get.column_ids.at(i)));
88
+ have_distinct_count_stats = true;
89
+ }
90
+ }
91
+ if (!have_distinct_count_stats) {
92
+ // currently treating the cardinality as the distinct count.
93
+ // the cardinality estimator will update these distinct counts based
94
+ // on the extra columns that are joined on.
95
+ auto column_distinct_count = DistinctCount({cardinality_after_filters, false});
96
+ return_stats.column_distinct_count.push_back(column_distinct_count);
97
+ auto column_name = string("column");
98
+ if (get.column_ids.at(i) < get.names.size()) {
99
+ column_name = get.names.at(get.column_ids.at(i));
100
+ }
101
+ return_stats.column_names.push_back(get.GetName() + "." + column_name);
102
+ }
103
+ }
104
+
105
+ if (!get.table_filters.filters.empty()) {
106
+ column_statistics = nullptr;
107
+ for (auto &it : get.table_filters.filters) {
108
+ if (get.bind_data && get.function.name.compare("seq_scan") == 0) {
109
+ auto &table_scan_bind_data = get.bind_data->Cast<TableScanBindData>();
110
+ column_statistics = get.function.statistics(context, &table_scan_bind_data, it.first);
111
+ }
112
+
113
+ if (column_statistics && it.second->filter_type == TableFilterType::CONJUNCTION_AND) {
114
+ auto &filter = it.second->Cast<ConjunctionAndFilter>();
115
+ idx_t cardinality_with_and_filter = RelationStatisticsHelper::InspectConjunctionAND(
116
+ base_table_cardinality, it.first, filter, *column_statistics);
117
+ cardinality_after_filters = MinValue(cardinality_after_filters, cardinality_with_and_filter);
118
+ }
119
+ }
120
+ // if the above code didn't find an equality filter (i.e country_code = "[us]")
121
+ // and there are other table filters (i.e cost > 50), use default selectivity.
122
+ bool has_equality_filter = (cardinality_after_filters != base_table_cardinality);
123
+ if (!has_equality_filter && !get.table_filters.filters.empty()) {
124
+ cardinality_after_filters =
125
+ MaxValue<idx_t>(base_table_cardinality * RelationStatisticsHelper::DEFAULT_SELECTIVITY, 1);
126
+ }
127
+ if (base_table_cardinality == 0) {
128
+ cardinality_after_filters = 0;
129
+ }
130
+ }
131
+ return_stats.cardinality = cardinality_after_filters;
132
+ // update the estimated cardinality of the get as well.
133
+ // This is not updated during plan reconstruction.
134
+ get.estimated_cardinality = cardinality_after_filters;
135
+ get.has_estimated_cardinality = true;
136
+ D_ASSERT(base_table_cardinality >= cardinality_after_filters);
137
+ return_stats.stats_initialized = true;
138
+ return return_stats;
139
+ }
140
+
141
+ RelationStats RelationStatisticsHelper::ExtractDelimGetStats(LogicalDelimGet &delim_get, ClientContext &context) {
142
+ RelationStats stats;
143
+ stats.table_name = delim_get.GetName();
144
+ idx_t card = delim_get.EstimateCardinality(context);
145
+ stats.cardinality = card;
146
+ stats.stats_initialized = true;
147
+ for (auto &binding : delim_get.GetColumnBindings()) {
148
+ stats.column_distinct_count.push_back(DistinctCount({1, false}));
149
+ stats.column_names.push_back("column" + to_string(binding.column_index));
150
+ }
151
+ return stats;
152
+ }
153
+
154
+ RelationStats RelationStatisticsHelper::ExtractProjectionStats(LogicalProjection &proj, RelationStats &child_stats) {
155
+ auto proj_stats = RelationStats();
156
+ proj_stats.cardinality = child_stats.cardinality;
157
+ proj_stats.table_name = proj.GetName();
158
+ for (auto &expr : proj.expressions) {
159
+ proj_stats.column_names.push_back(expr->GetName());
160
+ auto res = GetChildColumnBinding(*expr);
161
+ D_ASSERT(res.found_expression);
162
+ if (res.expression_is_constant) {
163
+ proj_stats.column_distinct_count.push_back(DistinctCount({1, true}));
164
+ } else {
165
+ auto column_index = res.child_binding.column_index;
166
+ if (column_index >= child_stats.column_distinct_count.size() && expr->ToString() == "count_star()") {
167
+ // only one value for a count star
168
+ proj_stats.column_distinct_count.push_back(DistinctCount({1, true}));
169
+ } else {
170
+ // TODO: add this back in
171
+ // D_ASSERT(column_index < stats.column_distinct_count.size());
172
+ if (column_index < child_stats.column_distinct_count.size()) {
173
+ proj_stats.column_distinct_count.push_back(child_stats.column_distinct_count.at(column_index));
174
+ } else {
175
+ proj_stats.column_distinct_count.push_back(DistinctCount({proj_stats.cardinality, false}));
176
+ }
177
+ }
178
+ }
179
+ }
180
+ proj_stats.stats_initialized = true;
181
+ return proj_stats;
182
+ }
183
+
184
+ RelationStats RelationStatisticsHelper::ExtractDummyScanStats(LogicalDummyScan &dummy_scan, ClientContext &context) {
185
+ auto stats = RelationStats();
186
+ idx_t card = dummy_scan.EstimateCardinality(context);
187
+ stats.cardinality = card;
188
+ for (idx_t i = 0; i < dummy_scan.GetColumnBindings().size(); i++) {
189
+ stats.column_distinct_count.push_back(DistinctCount({card, false}));
190
+ stats.column_names.push_back("dummy_scan_column");
191
+ }
192
+ stats.stats_initialized = true;
193
+ stats.table_name = "dummy scan";
194
+ return stats;
195
+ }
196
+
197
+ void RelationStatisticsHelper::CopyRelationStats(RelationStats &to, const RelationStats &from) {
198
+ to.column_distinct_count = from.column_distinct_count;
199
+ to.column_names = from.column_names;
200
+ to.cardinality = from.cardinality;
201
+ to.table_name = from.table_name;
202
+ to.stats_initialized = from.stats_initialized;
203
+ }
204
+
205
+ RelationStats RelationStatisticsHelper::CombineStatsOfReorderableOperator(vector<ColumnBinding> &bindings,
206
+ vector<RelationStats> relation_stats) {
207
+ RelationStats stats;
208
+ idx_t max_card = 0;
209
+ for (auto &child_stats : relation_stats) {
210
+ for (idx_t i = 0; i < child_stats.column_distinct_count.size(); i++) {
211
+ stats.column_distinct_count.push_back(child_stats.column_distinct_count.at(i));
212
+ stats.column_names.push_back(child_stats.column_names.at(i));
213
+ }
214
+ stats.table_name += "joined with " + child_stats.table_name;
215
+ max_card = MaxValue(max_card, child_stats.cardinality);
216
+ }
217
+ stats.stats_initialized = true;
218
+ stats.cardinality = max_card;
219
+ return stats;
220
+ }
221
+
222
+ RelationStats RelationStatisticsHelper::CombineStatsOfNonReorderableOperator(LogicalOperator &op,
223
+ vector<RelationStats> child_stats) {
224
+ D_ASSERT(child_stats.size() == 2);
225
+ RelationStats ret;
226
+ idx_t child_1_card = child_stats[0].stats_initialized ? child_stats[0].cardinality : 0;
227
+ idx_t child_2_card = child_stats[1].stats_initialized ? child_stats[1].cardinality : 0;
228
+ ret.cardinality = MaxValue(child_1_card, child_2_card);
229
+ ret.stats_initialized = true;
230
+ ret.filter_strength = 1;
231
+ ret.table_name = child_stats[0].table_name + " joined with " + child_stats[1].table_name;
232
+ for (auto &stats : child_stats) {
233
+ // MARK joins are nonreorderable. They won't return initialized stats
234
+ // continue in this case.
235
+ if (!stats.stats_initialized) {
236
+ continue;
237
+ }
238
+ for (auto &distinct_count : stats.column_distinct_count) {
239
+ ret.column_distinct_count.push_back(distinct_count);
240
+ }
241
+ for (auto &column_name : stats.column_names) {
242
+ ret.column_names.push_back(column_name);
243
+ }
244
+ }
245
+ return ret;
246
+ }
247
+
248
+ RelationStats RelationStatisticsHelper::ExtractExpressionGetStats(LogicalExpressionGet &expression_get,
249
+ ClientContext &context) {
250
+ auto stats = RelationStats();
251
+ idx_t card = expression_get.EstimateCardinality(context);
252
+ stats.cardinality = card;
253
+ for (idx_t i = 0; i < expression_get.GetColumnBindings().size(); i++) {
254
+ stats.column_distinct_count.push_back(DistinctCount({card, false}));
255
+ stats.column_names.push_back("expression_get_column");
256
+ }
257
+ stats.stats_initialized = true;
258
+ stats.table_name = "expression_get";
259
+ return stats;
260
+ }
261
+
262
+ RelationStats RelationStatisticsHelper::ExtractWindowStats(LogicalWindow &window, RelationStats &child_stats) {
263
+ RelationStats stats;
264
+ stats.cardinality = child_stats.cardinality;
265
+ stats.column_distinct_count = child_stats.column_distinct_count;
266
+ stats.column_names = child_stats.column_names;
267
+ stats.stats_initialized = true;
268
+ auto num_child_columns = window.GetColumnBindings().size();
269
+
270
+ for (idx_t column_index = child_stats.column_distinct_count.size(); column_index < num_child_columns;
271
+ column_index++) {
272
+ stats.column_distinct_count.push_back(DistinctCount({child_stats.cardinality, false}));
273
+ stats.column_names.push_back("window");
274
+ }
275
+ return stats;
276
+ }
277
+
278
+ RelationStats RelationStatisticsHelper::ExtractAggregationStats(LogicalAggregate &aggr, RelationStats &child_stats) {
279
+ RelationStats stats;
280
+ // TODO: look at child distinct count to better estimate cardinality.
281
+ stats.cardinality = child_stats.cardinality;
282
+ stats.column_distinct_count = child_stats.column_distinct_count;
283
+ stats.column_names = child_stats.column_names;
284
+ stats.stats_initialized = true;
285
+ auto num_child_columns = aggr.GetColumnBindings().size();
286
+
287
+ for (idx_t column_index = child_stats.column_distinct_count.size(); column_index < num_child_columns;
288
+ column_index++) {
289
+ stats.column_distinct_count.push_back(DistinctCount({child_stats.cardinality, false}));
290
+ stats.column_names.push_back("aggregate");
291
+ }
292
+ return stats;
293
+ }
294
+
295
+ idx_t RelationStatisticsHelper::InspectConjunctionAND(idx_t cardinality, idx_t column_index,
296
+ ConjunctionAndFilter &filter, BaseStatistics &base_stats) {
297
+ auto cardinality_after_filters = cardinality;
298
+ for (auto &child_filter : filter.child_filters) {
299
+ if (child_filter->filter_type != TableFilterType::CONSTANT_COMPARISON) {
300
+ continue;
301
+ }
302
+ auto &comparison_filter = child_filter->Cast<ConstantFilter>();
303
+ if (comparison_filter.comparison_type != ExpressionType::COMPARE_EQUAL) {
304
+ continue;
305
+ }
306
+ auto column_count = base_stats.GetDistinctCount();
307
+ auto filtered_card = cardinality;
308
+ // column_count = 0 when there is no column count (i.e parquet scans)
309
+ if (column_count > 0) {
310
+ // we want the ceil of cardinality/column_count. We also want to avoid compiler errors
311
+ filtered_card = (cardinality + column_count - 1) / column_count;
312
+ cardinality_after_filters = filtered_card;
313
+ }
314
+ }
315
+ return cardinality_after_filters;
316
+ }
317
+
318
+ // TODO: Currently only simple AND filters are pushed into table scans.
319
+ // When OR filters are pushed this function can be added
320
+ // idx_t RelationStatisticsHelper::InspectConjunctionOR(idx_t cardinality, idx_t column_index, ConjunctionOrFilter
321
+ // &filter,
322
+ // BaseStatistics &base_stats) {
323
+ // auto has_equality_filter = false;
324
+ // auto cardinality_after_filters = cardinality;
325
+ // for (auto &child_filter : filter.child_filters) {
326
+ // if (child_filter->filter_type != TableFilterType::CONSTANT_COMPARISON) {
327
+ // continue;
328
+ // }
329
+ // auto &comparison_filter = child_filter->Cast<ConstantFilter>();
330
+ // if (comparison_filter.comparison_type == ExpressionType::COMPARE_EQUAL) {
331
+ // auto column_count = base_stats.GetDistinctCount();
332
+ // auto increment = MaxValue<idx_t>(((cardinality + column_count - 1) / column_count), 1);
333
+ // if (has_equality_filter) {
334
+ // cardinality_after_filters += increment;
335
+ // } else {
336
+ // cardinality_after_filters = increment;
337
+ // }
338
+ // has_equality_filter = true;
339
+ // }
340
+ // if (child_filter->filter_type == TableFilterType::CONJUNCTION_AND) {
341
+ // auto &and_filter = child_filter->Cast<ConjunctionAndFilter>();
342
+ // cardinality_after_filters = RelationStatisticsHelper::InspectConjunctionAND(
343
+ // cardinality_after_filters, column_index, and_filter, base_stats);
344
+ // continue;
345
+ // }
346
+ // }
347
+ // D_ASSERT(cardinality_after_filters > 0);
348
+ // return cardinality_after_filters;
349
+ //}
350
+
351
+ } // namespace duckdb
@@ -458,6 +458,8 @@ bool Executor::ExecutionIsFinished() {
458
458
  }
459
459
 
460
460
  PendingExecutionResult Executor::ExecuteTask() {
461
+ // Only executor should return NO_TASKS_AVAILABLE
462
+ D_ASSERT(execution_result != PendingExecutionResult::NO_TASKS_AVAILABLE);
461
463
  if (execution_result != PendingExecutionResult::RESULT_NOT_READY) {
462
464
  return execution_result;
463
465
  }
@@ -468,6 +470,10 @@ PendingExecutionResult Executor::ExecuteTask() {
468
470
  if (!task) {
469
471
  scheduler.GetTaskFromProducer(*producer, task);
470
472
  }
473
+ if (!task && !HasError()) {
474
+ // there are no tasks to be scheduled and there are tasks blocked
475
+ return PendingExecutionResult::NO_TASKS_AVAILABLE;
476
+ }
471
477
  if (task) {
472
478
  // if we have a task, partially process it
473
479
  auto result = task->Execute(TaskExecutionMode::PROCESS_PARTIAL);
@@ -9,6 +9,7 @@
9
9
  #include "concurrentqueue.h"
10
10
  #include "duckdb/common/thread.hpp"
11
11
  #include "lightweightsemaphore.h"
12
+ #include <thread>
12
13
  #else
13
14
  #include <queue>
14
15
  #endif
@@ -256,6 +257,12 @@ void TaskScheduler::Signal(idx_t n) {
256
257
  #endif
257
258
  }
258
259
 
260
+ void TaskScheduler::YieldThread() {
261
+ #ifndef DUCKDB_NO_THREADS
262
+ std::this_thread::yield();
263
+ #endif
264
+ }
265
+
259
266
  void TaskScheduler::SetThreadsInternal(int32_t n) {
260
267
  #ifndef DUCKDB_NO_THREADS
261
268
  if (threads.size() == idx_t(n - 1)) {
@@ -46,7 +46,7 @@ BoundStatement Binder::Bind(ExecuteStatement &stmt) {
46
46
  // catalog was modified or statement does not have clear types: rebind the statement before running the execute
47
47
  Planner prepared_planner(context);
48
48
  for (auto &pair : bind_values) {
49
- prepared_planner.parameter_data.emplace(pair);
49
+ prepared_planner.parameter_data.emplace(std::make_pair(pair.first, BoundParameterData(pair.second)));
50
50
  }
51
51
  prepared = prepared_planner.PrepareSQLStatement(entry->second->unbound_statement->Copy());
52
52
  rebound_plan = std::move(prepared_planner.plan);
@@ -109,6 +109,10 @@ void LogicalGet::ResolveTypes() {
109
109
  }
110
110
 
111
111
  idx_t LogicalGet::EstimateCardinality(ClientContext &context) {
112
+ // join order optimizer does better cardinality estimation.
113
+ if (has_estimated_cardinality) {
114
+ return estimated_cardinality;
115
+ }
112
116
  if (function.cardinality) {
113
117
  auto node_stats = function.cardinality(context, bind_data.get());
114
118
  if (node_stats && node_stats->has_estimated_cardinality) {
@@ -10,3 +10,13 @@
10
10
 
11
11
  #include "src/optimizer/join_order/cardinality_estimator.cpp"
12
12
 
13
+ #include "src/optimizer/join_order/cost_model.cpp"
14
+
15
+ #include "src/optimizer/join_order/plan_enumerator.cpp"
16
+
17
+ #include "src/optimizer/join_order/relation_manager.cpp"
18
+
19
+ #include "src/optimizer/join_order/query_graph_manager.cpp"
20
+
21
+ #include "src/optimizer/join_order/relation_statistics_helper.cpp"
22
+