duckdb 0.7.2-dev1901.0 → 0.7.2-dev2233.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.
- package/binding.gyp +2 -0
- package/package.json +1 -1
- package/src/duckdb/extension/parquet/column_reader.cpp +3 -0
- package/src/duckdb/extension/parquet/include/parquet_writer.hpp +1 -1
- package/src/duckdb/extension/parquet/parquet_metadata.cpp +4 -2
- package/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp +1 -1
- package/src/duckdb/src/common/arrow/arrow_appender.cpp +69 -44
- package/src/duckdb/src/common/arrow/arrow_converter.cpp +1 -1
- package/src/duckdb/src/common/arrow/arrow_wrapper.cpp +20 -2
- package/src/duckdb/src/common/box_renderer.cpp +4 -2
- package/src/duckdb/src/common/constants.cpp +10 -1
- package/src/duckdb/src/common/filename_pattern.cpp +41 -0
- package/src/duckdb/src/common/hive_partitioning.cpp +144 -15
- package/src/duckdb/src/common/radix_partitioning.cpp +101 -369
- package/src/duckdb/src/common/row_operations/row_aggregate.cpp +8 -9
- package/src/duckdb/src/common/row_operations/row_external.cpp +1 -1
- package/src/duckdb/src/common/row_operations/row_gather.cpp +5 -3
- package/src/duckdb/src/common/row_operations/row_match.cpp +117 -22
- package/src/duckdb/src/common/row_operations/row_scatter.cpp +2 -2
- package/src/duckdb/src/common/sort/partition_state.cpp +1 -1
- package/src/duckdb/src/common/sort/sort_state.cpp +2 -1
- package/src/duckdb/src/common/sort/sorted_block.cpp +1 -1
- package/src/duckdb/src/common/types/{column_data_allocator.cpp → column/column_data_allocator.cpp} +2 -2
- package/src/duckdb/src/common/types/{column_data_collection.cpp → column/column_data_collection.cpp} +29 -6
- package/src/duckdb/src/common/types/{column_data_collection_segment.cpp → column/column_data_collection_segment.cpp} +2 -1
- package/src/duckdb/src/common/types/{column_data_consumer.cpp → column/column_data_consumer.cpp} +1 -1
- package/src/duckdb/src/common/types/{partitioned_column_data.cpp → column/partitioned_column_data.cpp} +11 -9
- package/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp +316 -0
- package/src/duckdb/src/common/types/{row_data_collection.cpp → row/row_data_collection.cpp} +1 -1
- package/src/duckdb/src/common/types/{row_data_collection_scanner.cpp → row/row_data_collection_scanner.cpp} +2 -2
- package/src/duckdb/src/common/types/{row_layout.cpp → row/row_layout.cpp} +1 -1
- package/src/duckdb/src/common/types/row/tuple_data_allocator.cpp +465 -0
- package/src/duckdb/src/common/types/row/tuple_data_collection.cpp +511 -0
- package/src/duckdb/src/common/types/row/tuple_data_iterator.cpp +96 -0
- package/src/duckdb/src/common/types/row/tuple_data_layout.cpp +119 -0
- package/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp +1200 -0
- package/src/duckdb/src/common/types/row/tuple_data_segment.cpp +170 -0
- package/src/duckdb/src/common/types/vector.cpp +1 -1
- package/src/duckdb/src/execution/aggregate_hashtable.cpp +252 -290
- package/src/duckdb/src/execution/join_hashtable.cpp +192 -328
- package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +4 -4
- package/src/duckdb/src/execution/operator/helper/physical_execute.cpp +3 -3
- package/src/duckdb/src/execution/operator/helper/physical_limit_percent.cpp +2 -3
- package/src/duckdb/src/execution/operator/helper/physical_result_collector.cpp +2 -3
- package/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp +36 -21
- package/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp +2 -2
- package/src/duckdb/src/execution/operator/join/physical_cross_product.cpp +1 -1
- package/src/duckdb/src/execution/operator/join/physical_delim_join.cpp +2 -2
- package/src/duckdb/src/execution/operator/join/physical_hash_join.cpp +166 -144
- package/src/duckdb/src/execution/operator/join/physical_index_join.cpp +5 -5
- package/src/duckdb/src/execution/operator/join/physical_join.cpp +2 -10
- package/src/duckdb/src/execution/operator/join/physical_positional_join.cpp +0 -1
- package/src/duckdb/src/execution/operator/order/physical_top_n.cpp +2 -2
- package/src/duckdb/src/execution/operator/persistent/base_csv_reader.cpp +3 -0
- package/src/duckdb/src/execution/operator/persistent/buffered_csv_reader.cpp +71 -22
- package/src/duckdb/src/execution/operator/persistent/csv_buffer.cpp +17 -13
- package/src/duckdb/src/execution/operator/persistent/csv_reader_options.cpp +0 -7
- package/src/duckdb/src/execution/operator/persistent/parallel_csv_reader.cpp +124 -29
- package/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp +13 -11
- package/src/duckdb/src/execution/operator/persistent/physical_delete.cpp +3 -2
- package/src/duckdb/src/execution/operator/persistent/physical_export.cpp +25 -24
- package/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +1 -1
- package/src/duckdb/src/execution/operator/persistent/physical_update.cpp +4 -3
- package/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +1 -1
- package/src/duckdb/src/execution/operator/schema/physical_create_type.cpp +1 -1
- package/src/duckdb/src/execution/operator/set/physical_recursive_cte.cpp +3 -3
- package/src/duckdb/src/execution/partitionable_hashtable.cpp +9 -37
- package/src/duckdb/src/execution/physical_operator.cpp +1 -1
- package/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp +19 -18
- package/src/duckdb/src/execution/physical_plan/plan_copy_to_file.cpp +2 -1
- package/src/duckdb/src/execution/physical_plan/plan_execute.cpp +2 -2
- package/src/duckdb/src/execution/physical_plan/plan_explain.cpp +5 -6
- package/src/duckdb/src/execution/physical_plan/plan_expression_get.cpp +2 -2
- package/src/duckdb/src/execution/physical_plan/plan_recursive_cte.cpp +3 -3
- package/src/duckdb/src/execution/physical_plan_generator.cpp +1 -1
- package/src/duckdb/src/execution/radix_partitioned_hashtable.cpp +39 -17
- package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +2 -2
- package/src/duckdb/src/function/table/pragma_detailed_profiling_output.cpp +5 -5
- package/src/duckdb/src/function/table/pragma_last_profiling_output.cpp +2 -2
- package/src/duckdb/src/function/table/read_csv.cpp +124 -58
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/index_catalog_entry.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/arrow/arrow_appender.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/constants.hpp +2 -0
- package/src/duckdb/src/include/duckdb/common/exception.hpp +3 -0
- package/src/duckdb/src/include/duckdb/common/fast_mem.hpp +528 -0
- package/src/duckdb/src/include/duckdb/common/filename_pattern.hpp +34 -0
- package/src/duckdb/src/include/duckdb/common/helper.hpp +10 -0
- package/src/duckdb/src/include/duckdb/common/hive_partitioning.hpp +13 -3
- package/src/duckdb/src/include/duckdb/common/optional_ptr.hpp +8 -0
- package/src/duckdb/src/include/duckdb/common/perfect_map_set.hpp +34 -0
- package/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp +80 -27
- package/src/duckdb/src/include/duckdb/common/reference_map.hpp +38 -0
- package/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp +7 -6
- package/src/duckdb/src/include/duckdb/common/sort/comparators.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/sort/partition_state.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/sort/sort.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/sort/sorted_block.hpp +2 -2
- package/src/duckdb/src/include/duckdb/common/types/batched_data_collection.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/types/{column_data_allocator.hpp → column/column_data_allocator.hpp} +4 -4
- package/src/duckdb/src/include/duckdb/common/types/{column_data_collection.hpp → column/column_data_collection.hpp} +4 -4
- package/src/duckdb/src/include/duckdb/common/types/{column_data_collection_iterators.hpp → column/column_data_collection_iterators.hpp} +2 -2
- package/src/duckdb/src/include/duckdb/common/types/{column_data_collection_segment.hpp → column/column_data_collection_segment.hpp} +3 -3
- package/src/duckdb/src/include/duckdb/common/types/{column_data_consumer.hpp → column/column_data_consumer.hpp} +8 -4
- package/src/duckdb/src/include/duckdb/common/types/{column_data_scan_states.hpp → column/column_data_scan_states.hpp} +1 -1
- package/src/duckdb/src/include/duckdb/common/types/{partitioned_column_data.hpp → column/partitioned_column_data.hpp} +15 -7
- package/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp +140 -0
- package/src/duckdb/src/include/duckdb/common/types/{row_data_collection.hpp → row/row_data_collection.hpp} +1 -1
- package/src/duckdb/src/include/duckdb/common/types/{row_data_collection_scanner.hpp → row/row_data_collection_scanner.hpp} +2 -2
- package/src/duckdb/src/include/duckdb/common/types/{row_layout.hpp → row/row_layout.hpp} +3 -1
- package/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp +116 -0
- package/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp +239 -0
- package/src/duckdb/src/include/duckdb/common/types/row/tuple_data_iterator.hpp +64 -0
- package/src/duckdb/src/include/duckdb/common/types/row/tuple_data_layout.hpp +113 -0
- package/src/duckdb/src/include/duckdb/common/types/row/tuple_data_segment.hpp +124 -0
- package/src/duckdb/src/include/duckdb/common/types/row/tuple_data_states.hpp +74 -0
- package/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp +3 -0
- package/src/duckdb/src/include/duckdb/common/types/value.hpp +4 -12
- package/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp +34 -31
- package/src/duckdb/src/include/duckdb/execution/base_aggregate_hashtable.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/execution_context.hpp +3 -2
- package/src/duckdb/src/include/duckdb/execution/expression_executor.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/join_hashtable.hpp +41 -67
- package/src/duckdb/src/include/duckdb/execution/nested_loop_join.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/operator/helper/physical_execute.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/operator/helper/physical_result_collector.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/operator/join/outer_join_marker.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/operator/join/physical_cross_product.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp +0 -2
- package/src/duckdb/src/include/duckdb/execution/operator/join/physical_index_join.hpp +2 -2
- package/src/duckdb/src/include/duckdb/execution/operator/join/physical_positional_join.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/buffered_csv_reader.hpp +4 -1
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_buffer.hpp +8 -3
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/csv_reader_options.hpp +5 -7
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/parallel_csv_reader.hpp +5 -1
- package/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_copy_to_file.hpp +4 -1
- package/src/duckdb/src/include/duckdb/execution/operator/scan/physical_column_data_scan.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/operator/set/physical_recursive_cte.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/partitionable_hashtable.hpp +2 -2
- package/src/duckdb/src/include/duckdb/function/function.hpp +2 -0
- package/src/duckdb/src/include/duckdb/function/table/read_csv.hpp +25 -0
- package/src/duckdb/src/include/duckdb/main/client_data.hpp +3 -0
- package/src/duckdb/src/include/duckdb/main/config.hpp +0 -2
- package/src/duckdb/src/include/duckdb/main/materialized_query_result.hpp +1 -1
- package/src/duckdb/src/include/duckdb/main/query_result.hpp +14 -1
- package/src/duckdb/src/include/duckdb/optimizer/expression_rewriter.hpp +3 -3
- package/src/duckdb/src/include/duckdb/optimizer/join_order/cardinality_estimator.hpp +16 -16
- package/src/duckdb/src/include/duckdb/optimizer/join_order/join_node.hpp +8 -8
- package/src/duckdb/src/include/duckdb/optimizer/join_order/join_order_optimizer.hpp +23 -15
- package/src/duckdb/src/include/duckdb/optimizer/join_order/join_relation.hpp +9 -10
- package/src/duckdb/src/include/duckdb/optimizer/join_order/query_graph.hpp +18 -11
- package/src/duckdb/src/include/duckdb/parallel/meta_pipeline.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/parsed_data/exported_table_data.hpp +5 -1
- package/src/duckdb/src/include/duckdb/parser/parsed_data/vacuum_info.hpp +3 -2
- package/src/duckdb/src/include/duckdb/parser/query_error_context.hpp +4 -2
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +9 -35
- package/src/duckdb/src/include/duckdb/planner/binder.hpp +24 -23
- package/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +3 -3
- package/src/duckdb/src/include/duckdb/planner/operator/logical_column_data_get.hpp +1 -1
- package/src/duckdb/src/include/duckdb/planner/operator/logical_copy_to_file.hpp +3 -1
- package/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp +1 -1
- package/src/duckdb/src/main/appender.cpp +6 -6
- package/src/duckdb/src/main/client_context.cpp +1 -1
- package/src/duckdb/src/main/connection.cpp +2 -2
- package/src/duckdb/src/main/query_result.cpp +13 -0
- package/src/duckdb/src/main/settings/settings.cpp +3 -4
- package/src/duckdb/src/optimizer/expression_rewriter.cpp +4 -4
- package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +91 -105
- package/src/duckdb/src/optimizer/join_order/join_node.cpp +5 -8
- package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +163 -160
- package/src/duckdb/src/optimizer/join_order/join_relation_set.cpp +30 -30
- package/src/duckdb/src/optimizer/join_order/query_graph.cpp +37 -38
- package/src/duckdb/src/parallel/executor.cpp +1 -1
- package/src/duckdb/src/parallel/meta_pipeline.cpp +2 -2
- package/src/duckdb/src/parser/transform/helpers/transform_cte.cpp +1 -1
- package/src/duckdb/src/parser/transform/tableref/transform_subquery.cpp +1 -1
- package/src/duckdb/src/parser/transformer.cpp +50 -9
- package/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp +13 -0
- package/src/duckdb/src/planner/binder/statement/bind_copy.cpp +15 -5
- package/src/duckdb/src/planner/binder/statement/bind_create.cpp +19 -17
- package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +4 -4
- package/src/duckdb/src/planner/binder/statement/bind_export.cpp +20 -21
- package/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp +24 -22
- package/src/duckdb/src/planner/binder/tableref/bind_subqueryref.cpp +2 -2
- package/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp +9 -0
- package/src/duckdb/src/planner/binder.cpp +16 -19
- package/src/duckdb/src/planner/expression_binder.cpp +8 -8
- package/src/duckdb/src/planner/operator/logical_copy_to_file.cpp +3 -3
- package/src/duckdb/src/storage/checkpoint_manager.cpp +23 -23
- package/src/duckdb/src/storage/standard_buffer_manager.cpp +1 -1
- package/src/duckdb/src/storage/table_index_list.cpp +3 -3
- package/src/duckdb/src/verification/statement_verifier.cpp +1 -1
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +5552 -5598
- package/src/duckdb/ub_src_common.cpp +2 -0
- package/src/duckdb/ub_src_common_types.cpp +0 -16
- package/src/duckdb/ub_src_common_types_column.cpp +10 -0
- package/src/duckdb/ub_src_common_types_row.cpp +20 -0
@@ -1,8 +1,5 @@
|
|
1
1
|
#include "duckdb/execution/operator/join/physical_hash_join.hpp"
|
2
2
|
|
3
|
-
#include "duckdb/planner/expression/bound_aggregate_expression.hpp"
|
4
|
-
#include "duckdb/planner/expression/bound_reference_expression.hpp"
|
5
|
-
#include "duckdb/common/types/column_data_collection.hpp"
|
6
3
|
#include "duckdb/common/vector_operations/vector_operations.hpp"
|
7
4
|
#include "duckdb/execution/expression_executor.hpp"
|
8
5
|
#include "duckdb/function/aggregate/distributive_functions.hpp"
|
@@ -12,6 +9,8 @@
|
|
12
9
|
#include "duckdb/parallel/base_pipeline_event.hpp"
|
13
10
|
#include "duckdb/parallel/pipeline.hpp"
|
14
11
|
#include "duckdb/parallel/thread_context.hpp"
|
12
|
+
#include "duckdb/planner/expression/bound_aggregate_expression.hpp"
|
13
|
+
#include "duckdb/planner/expression/bound_reference_expression.hpp"
|
15
14
|
#include "duckdb/storage/buffer_manager.hpp"
|
16
15
|
#include "duckdb/storage/storage_manager.hpp"
|
17
16
|
|
@@ -52,20 +51,14 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptr<PhysicalOpera
|
|
52
51
|
//===--------------------------------------------------------------------===//
|
53
52
|
class HashJoinGlobalSinkState : public GlobalSinkState {
|
54
53
|
public:
|
55
|
-
HashJoinGlobalSinkState(const PhysicalHashJoin &op, ClientContext &
|
56
|
-
: finalized(false), scanned_data(false) {
|
54
|
+
HashJoinGlobalSinkState(const PhysicalHashJoin &op, ClientContext &context_p)
|
55
|
+
: context(context_p), finalized(false), scanned_data(false) {
|
57
56
|
hash_table = op.InitializeHashTable(context);
|
58
57
|
|
59
58
|
// for perfect hash join
|
60
59
|
perfect_join_executor = make_uniq<PerfectHashJoinExecutor>(op, *hash_table, op.perfect_join_statistics);
|
61
60
|
// for external hash join
|
62
|
-
external =
|
63
|
-
// memory usage per thread scales with max mem / num threads
|
64
|
-
double max_memory = BufferManager::GetBufferManager(context).GetMaxMemory();
|
65
|
-
double num_threads = TaskScheduler::GetScheduler(context).NumberOfThreads();
|
66
|
-
// HT may not exceed 60% of memory
|
67
|
-
max_ht_size = max_memory * 0.6;
|
68
|
-
sink_memory_per_thread = max_ht_size / num_threads;
|
61
|
+
external = ClientConfig::GetConfig(context).force_external;
|
69
62
|
// Set probe types
|
70
63
|
const auto &payload_types = op.children[0]->types;
|
71
64
|
probe_types.insert(probe_types.end(), op.condition_types.begin(), op.condition_types.end());
|
@@ -74,9 +67,10 @@ public:
|
|
74
67
|
}
|
75
68
|
|
76
69
|
void ScheduleFinalize(Pipeline &pipeline, Event &event);
|
77
|
-
void InitializeProbeSpill(
|
70
|
+
void InitializeProbeSpill();
|
78
71
|
|
79
72
|
public:
|
73
|
+
ClientContext &context;
|
80
74
|
//! Global HT used by the join
|
81
75
|
unique_ptr<JoinHashTable> hash_table;
|
82
76
|
//! The perfect hash join executor (if any)
|
@@ -86,9 +80,6 @@ public:
|
|
86
80
|
|
87
81
|
//! Whether we are doing an external join
|
88
82
|
bool external;
|
89
|
-
//! Memory usage per thread during the Sink and Execute phases
|
90
|
-
idx_t max_ht_size;
|
91
|
-
idx_t sink_memory_per_thread;
|
92
83
|
|
93
84
|
//! Hash tables built by each thread
|
94
85
|
mutex lock;
|
@@ -115,9 +106,13 @@ public:
|
|
115
106
|
join_keys.Initialize(allocator, op.condition_types);
|
116
107
|
|
117
108
|
hash_table = op.InitializeHashTable(context);
|
109
|
+
|
110
|
+
hash_table->GetSinkCollection().InitializeAppendState(append_state);
|
118
111
|
}
|
119
112
|
|
120
113
|
public:
|
114
|
+
PartitionedTupleDataAppendState append_state;
|
115
|
+
|
121
116
|
DataChunk build_chunk;
|
122
117
|
DataChunk join_keys;
|
123
118
|
ExpressionExecutor build_executor;
|
@@ -129,6 +124,7 @@ public:
|
|
129
124
|
unique_ptr<JoinHashTable> PhysicalHashJoin::InitializeHashTable(ClientContext &context) const {
|
130
125
|
auto result =
|
131
126
|
make_uniq<JoinHashTable>(BufferManager::GetBufferManager(context), conditions, build_types, join_type);
|
127
|
+
result->max_ht_size = double(BufferManager::GetBufferManager(context).GetMaxMemory()) * 0.6;
|
132
128
|
if (!delim_types.empty() && join_type == JoinType::MARK) {
|
133
129
|
// correlated MARK join
|
134
130
|
if (delim_types.size() + 1 == conditions.size()) {
|
@@ -187,12 +183,12 @@ unique_ptr<LocalSinkState> PhysicalHashJoin::GetLocalSinkState(ExecutionContext
|
|
187
183
|
|
188
184
|
SinkResultType PhysicalHashJoin::Sink(ExecutionContext &context, GlobalSinkState &gstate_p, LocalSinkState &lstate_p,
|
189
185
|
DataChunk &input) const {
|
190
|
-
auto &gstate = gstate_p.Cast<HashJoinGlobalSinkState>();
|
191
186
|
auto &lstate = lstate_p.Cast<HashJoinLocalSinkState>();
|
192
187
|
|
193
188
|
// resolve the join keys for the right chunk
|
194
189
|
lstate.join_keys.Reset();
|
195
190
|
lstate.build_executor.Execute(input, lstate.join_keys);
|
191
|
+
|
196
192
|
// build the HT
|
197
193
|
auto &ht = *lstate.hash_table;
|
198
194
|
if (!right_projection_map.empty()) {
|
@@ -202,21 +198,14 @@ SinkResultType PhysicalHashJoin::Sink(ExecutionContext &context, GlobalSinkState
|
|
202
198
|
for (idx_t i = 0; i < right_projection_map.size(); i++) {
|
203
199
|
lstate.build_chunk.data[i].Reference(input.data[right_projection_map[i]]);
|
204
200
|
}
|
205
|
-
ht.Build(lstate.join_keys, lstate.build_chunk);
|
201
|
+
ht.Build(lstate.append_state, lstate.join_keys, lstate.build_chunk);
|
206
202
|
} else if (!build_types.empty()) {
|
207
203
|
// there is not a projected map: place the entire right chunk in the HT
|
208
|
-
ht.Build(lstate.join_keys, input);
|
204
|
+
ht.Build(lstate.append_state, lstate.join_keys, input);
|
209
205
|
} else {
|
210
206
|
// there are only keys: place an empty chunk in the payload
|
211
207
|
lstate.build_chunk.SetCardinality(input.size());
|
212
|
-
ht.Build(lstate.join_keys, lstate.build_chunk);
|
213
|
-
}
|
214
|
-
|
215
|
-
// swizzle if we reach memory limit
|
216
|
-
auto approx_ptr_table_size = ht.Count() * 3 * sizeof(data_ptr_t);
|
217
|
-
if (can_go_external && ht.SizeInBytes() + approx_ptr_table_size >= gstate.sink_memory_per_thread) {
|
218
|
-
lstate.hash_table->SwizzleBlocks();
|
219
|
-
gstate.external = true;
|
208
|
+
ht.Build(lstate.append_state, lstate.join_keys, lstate.build_chunk);
|
220
209
|
}
|
221
210
|
|
222
211
|
return SinkResultType::NEED_MORE_INPUT;
|
@@ -226,6 +215,7 @@ void PhysicalHashJoin::Combine(ExecutionContext &context, GlobalSinkState &gstat
|
|
226
215
|
auto &gstate = gstate_p.Cast<HashJoinGlobalSinkState>();
|
227
216
|
auto &lstate = lstate_p.Cast<HashJoinLocalSinkState>();
|
228
217
|
if (lstate.hash_table) {
|
218
|
+
lstate.hash_table->GetSinkCollection().FlushAppendState(lstate.append_state);
|
229
219
|
lock_guard<mutex> local_ht_lock(gstate.lock);
|
230
220
|
gstate.local_hash_tables.push_back(std::move(lstate.hash_table));
|
231
221
|
}
|
@@ -239,14 +229,14 @@ void PhysicalHashJoin::Combine(ExecutionContext &context, GlobalSinkState &gstat
|
|
239
229
|
//===--------------------------------------------------------------------===//
|
240
230
|
class HashJoinFinalizeTask : public ExecutorTask {
|
241
231
|
public:
|
242
|
-
HashJoinFinalizeTask(shared_ptr<Event> event_p, ClientContext &context, HashJoinGlobalSinkState &
|
243
|
-
idx_t
|
244
|
-
: ExecutorTask(context), event(std::move(event_p)), sink(
|
245
|
-
|
232
|
+
HashJoinFinalizeTask(shared_ptr<Event> event_p, ClientContext &context, HashJoinGlobalSinkState &sink_p,
|
233
|
+
idx_t chunk_idx_from_p, idx_t chunk_idx_to_p, bool parallel_p)
|
234
|
+
: ExecutorTask(context), event(std::move(event_p)), sink(sink_p), chunk_idx_from(chunk_idx_from_p),
|
235
|
+
chunk_idx_to(chunk_idx_to_p), parallel(parallel_p) {
|
246
236
|
}
|
247
237
|
|
248
238
|
TaskExecutionResult ExecuteTask(TaskExecutionMode mode) override {
|
249
|
-
sink.hash_table->Finalize(
|
239
|
+
sink.hash_table->Finalize(chunk_idx_from, chunk_idx_to, parallel);
|
250
240
|
event->FinishTask();
|
251
241
|
return TaskExecutionResult::TASK_FINISHED;
|
252
242
|
}
|
@@ -254,8 +244,8 @@ public:
|
|
254
244
|
private:
|
255
245
|
shared_ptr<Event> event;
|
256
246
|
HashJoinGlobalSinkState &sink;
|
257
|
-
idx_t
|
258
|
-
idx_t
|
247
|
+
idx_t chunk_idx_from;
|
248
|
+
idx_t chunk_idx_to;
|
259
249
|
bool parallel;
|
260
250
|
};
|
261
251
|
|
@@ -273,26 +263,24 @@ public:
|
|
273
263
|
|
274
264
|
vector<unique_ptr<Task>> finalize_tasks;
|
275
265
|
auto &ht = *sink.hash_table;
|
276
|
-
const auto
|
277
|
-
const
|
278
|
-
|
279
|
-
if (block_collection.count < PARALLEL_CONSTRUCT_THRESHOLD && !context.config.verify_parallelism) {
|
266
|
+
const auto chunk_count = ht.GetDataCollection().ChunkCount();
|
267
|
+
const idx_t num_threads = TaskScheduler::GetScheduler(context).NumberOfThreads();
|
268
|
+
if (num_threads == 1 || (ht.Count() < PARALLEL_CONSTRUCT_THRESHOLD && !context.config.verify_parallelism)) {
|
280
269
|
// Single-threaded finalize
|
281
270
|
finalize_tasks.push_back(
|
282
|
-
make_uniq<HashJoinFinalizeTask>(shared_from_this(), context, sink, 0,
|
271
|
+
make_uniq<HashJoinFinalizeTask>(shared_from_this(), context, sink, 0, chunk_count, false));
|
283
272
|
} else {
|
284
273
|
// Parallel finalize
|
285
|
-
|
286
|
-
auto blocks_per_thread = MaxValue<idx_t>((num_blocks + num_threads - 1) / num_threads, 1);
|
274
|
+
auto chunks_per_thread = MaxValue<idx_t>((chunk_count + num_threads - 1) / num_threads, 1);
|
287
275
|
|
288
|
-
idx_t
|
276
|
+
idx_t chunk_idx = 0;
|
289
277
|
for (idx_t thread_idx = 0; thread_idx < num_threads; thread_idx++) {
|
290
|
-
auto
|
291
|
-
auto
|
278
|
+
auto chunk_idx_from = chunk_idx;
|
279
|
+
auto chunk_idx_to = MinValue<idx_t>(chunk_idx_from + chunks_per_thread, chunk_count);
|
292
280
|
finalize_tasks.push_back(make_uniq<HashJoinFinalizeTask>(shared_from_this(), context, sink,
|
293
|
-
|
294
|
-
|
295
|
-
if (
|
281
|
+
chunk_idx_from, chunk_idx_to, true));
|
282
|
+
chunk_idx = chunk_idx_to;
|
283
|
+
if (chunk_idx == chunk_count) {
|
296
284
|
break;
|
297
285
|
}
|
298
286
|
}
|
@@ -301,6 +289,7 @@ public:
|
|
301
289
|
}
|
302
290
|
|
303
291
|
void FinishEvent() override {
|
292
|
+
sink.hash_table->GetDataCollection().VerifyEverythingPinned();
|
304
293
|
sink.hash_table->finalized = true;
|
305
294
|
}
|
306
295
|
|
@@ -317,7 +306,7 @@ void HashJoinGlobalSinkState::ScheduleFinalize(Pipeline &pipeline, Event &event)
|
|
317
306
|
event.InsertEvent(std::move(new_event));
|
318
307
|
}
|
319
308
|
|
320
|
-
void HashJoinGlobalSinkState::InitializeProbeSpill(
|
309
|
+
void HashJoinGlobalSinkState::InitializeProbeSpill() {
|
321
310
|
lock_guard<mutex> guard(lock);
|
322
311
|
if (!probe_spill) {
|
323
312
|
probe_spill = make_uniq<JoinHashTable::ProbeSpill>(*hash_table, context, probe_types);
|
@@ -376,28 +365,37 @@ public:
|
|
376
365
|
SinkFinalizeType PhysicalHashJoin::Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
|
377
366
|
GlobalSinkState &gstate) const {
|
378
367
|
auto &sink = gstate.Cast<HashJoinGlobalSinkState>();
|
368
|
+
auto &ht = *sink.hash_table;
|
379
369
|
|
370
|
+
sink.external = ht.RequiresExternalJoin(context.config, sink.local_hash_tables);
|
380
371
|
if (sink.external) {
|
381
|
-
D_ASSERT(can_go_external);
|
382
|
-
// External join - partition HT
|
383
372
|
sink.perfect_join_executor.reset();
|
384
|
-
|
385
|
-
|
386
|
-
|
373
|
+
if (ht.RequiresPartitioning(context.config, sink.local_hash_tables)) {
|
374
|
+
auto new_event = make_shared<HashJoinPartitionEvent>(pipeline, sink, sink.local_hash_tables);
|
375
|
+
event.InsertEvent(std::move(new_event));
|
376
|
+
} else {
|
377
|
+
for (auto &local_ht : sink.local_hash_tables) {
|
378
|
+
ht.Merge(*local_ht);
|
379
|
+
}
|
380
|
+
sink.local_hash_tables.clear();
|
381
|
+
sink.hash_table->PrepareExternalFinalize();
|
382
|
+
sink.ScheduleFinalize(pipeline, event);
|
383
|
+
}
|
387
384
|
sink.finalized = true;
|
388
385
|
return SinkFinalizeType::READY;
|
389
386
|
} else {
|
390
387
|
for (auto &local_ht : sink.local_hash_tables) {
|
391
|
-
|
388
|
+
ht.Merge(*local_ht);
|
392
389
|
}
|
393
390
|
sink.local_hash_tables.clear();
|
391
|
+
ht.Unpartition();
|
394
392
|
}
|
395
393
|
|
396
394
|
// check for possible perfect hash table
|
397
395
|
auto use_perfect_hash = sink.perfect_join_executor->CanDoPerfectHashJoin();
|
398
396
|
if (use_perfect_hash) {
|
399
|
-
D_ASSERT(
|
400
|
-
auto key_type =
|
397
|
+
D_ASSERT(ht.equality_types.size() == 1);
|
398
|
+
auto key_type = ht.equality_types[0];
|
401
399
|
use_perfect_hash = sink.perfect_join_executor->BuildPerfectHashTable(key_type);
|
402
400
|
}
|
403
401
|
// In case of a large build side or duplicates, use regular hash join
|
@@ -406,7 +404,7 @@ SinkFinalizeType PhysicalHashJoin::Finalize(Pipeline &pipeline, Event &event, Cl
|
|
406
404
|
sink.ScheduleFinalize(pipeline, event);
|
407
405
|
}
|
408
406
|
sink.finalized = true;
|
409
|
-
if (
|
407
|
+
if (ht.Count() == 0 && EmptyResultIfRHSIsEmpty()) {
|
410
408
|
return SinkFinalizeType::NO_OUTPUT_POSSIBLE;
|
411
409
|
}
|
412
410
|
return SinkFinalizeType::READY;
|
@@ -450,7 +448,7 @@ unique_ptr<OperatorState> PhysicalHashJoin::GetOperatorState(ExecutionContext &c
|
|
450
448
|
}
|
451
449
|
if (sink.external) {
|
452
450
|
state->spill_chunk.Initialize(allocator, sink.probe_types);
|
453
|
-
sink.InitializeProbeSpill(
|
451
|
+
sink.InitializeProbeSpill();
|
454
452
|
}
|
455
453
|
|
456
454
|
return std::move(state);
|
@@ -466,7 +464,7 @@ OperatorResultType PhysicalHashJoin::ExecuteInternal(ExecutionContext &context,
|
|
466
464
|
// some initialization for external hash join
|
467
465
|
if (sink.external && !state.initialized) {
|
468
466
|
if (!sink.probe_spill) {
|
469
|
-
sink.InitializeProbeSpill(
|
467
|
+
sink.InitializeProbeSpill();
|
470
468
|
}
|
471
469
|
state.spill_state = sink.probe_spill->RegisterThread();
|
472
470
|
state.initialized = true;
|
@@ -524,12 +522,13 @@ public:
|
|
524
522
|
HashJoinGlobalSourceState(const PhysicalHashJoin &op, ClientContext &context);
|
525
523
|
|
526
524
|
//! Initialize this source state using the info in the sink
|
527
|
-
void Initialize(
|
525
|
+
void Initialize(HashJoinGlobalSinkState &sink);
|
528
526
|
//! Try to prepare the next stage
|
529
527
|
void TryPrepareNextStage(HashJoinGlobalSinkState &sink);
|
530
|
-
//! Prepare the next build/probe stage for external hash join (must hold lock)
|
528
|
+
//! Prepare the next build/probe/scan_ht stage for external hash join (must hold lock)
|
531
529
|
void PrepareBuild(HashJoinGlobalSinkState &sink);
|
532
530
|
void PrepareProbe(HashJoinGlobalSinkState &sink);
|
531
|
+
void PrepareScanHT(HashJoinGlobalSinkState &sink);
|
533
532
|
//! Assigns a task to a local source state
|
534
533
|
bool AssignTask(HashJoinGlobalSinkState &sink, HashJoinLocalSourceState &lstate);
|
535
534
|
|
@@ -545,21 +544,24 @@ public:
|
|
545
544
|
mutex lock;
|
546
545
|
|
547
546
|
//! For HT build synchronization
|
548
|
-
idx_t
|
549
|
-
idx_t
|
550
|
-
idx_t
|
551
|
-
idx_t
|
547
|
+
idx_t build_chunk_idx;
|
548
|
+
idx_t build_chunk_count;
|
549
|
+
idx_t build_chunk_done;
|
550
|
+
idx_t build_chunks_per_thread;
|
552
551
|
|
553
552
|
//! For probe synchronization
|
554
553
|
idx_t probe_chunk_count;
|
555
554
|
idx_t probe_chunk_done;
|
556
555
|
|
557
|
-
//! For full/outer synchronization
|
558
|
-
JoinHTScanState full_outer_scan;
|
559
|
-
|
560
556
|
//! To determine the number of threads
|
561
557
|
idx_t probe_count;
|
562
558
|
idx_t parallel_scan_chunk_count;
|
559
|
+
|
560
|
+
//! For full/outer synchronization
|
561
|
+
idx_t full_outer_chunk_idx;
|
562
|
+
idx_t full_outer_chunk_count;
|
563
|
+
idx_t full_outer_chunk_done;
|
564
|
+
idx_t full_outer_chunks_per_thread;
|
563
565
|
};
|
564
566
|
|
565
567
|
class HashJoinLocalSourceState : public LocalSourceState {
|
@@ -575,18 +577,15 @@ public:
|
|
575
577
|
void ExternalProbe(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate, DataChunk &chunk);
|
576
578
|
void ExternalScanHT(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate, DataChunk &chunk);
|
577
579
|
|
578
|
-
//! Scans the HT for full/outer join
|
579
|
-
void ScanFullOuter(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate);
|
580
|
-
|
581
580
|
public:
|
582
581
|
//! The stage that this thread was assigned work for
|
583
582
|
HashJoinSourceStage local_stage;
|
584
583
|
//! Vector with pointers here so we don't have to re-initialize
|
585
584
|
Vector addresses;
|
586
585
|
|
587
|
-
//!
|
588
|
-
idx_t
|
589
|
-
idx_t
|
586
|
+
//! Chunks assigned to this thread for building the pointer table
|
587
|
+
idx_t build_chunk_idx_from;
|
588
|
+
idx_t build_chunk_idx_to;
|
590
589
|
|
591
590
|
//! Local scan state for probe spill
|
592
591
|
ColumnDataConsumerScanState probe_local_scan;
|
@@ -599,10 +598,12 @@ public:
|
|
599
598
|
vector<idx_t> payload_indices;
|
600
599
|
//! Scan structure for the external probe
|
601
600
|
unique_ptr<JoinHashTable::ScanStructure> scan_structure;
|
601
|
+
bool empty_ht_probe_in_progress;
|
602
602
|
|
603
|
-
//!
|
604
|
-
idx_t
|
605
|
-
idx_t
|
603
|
+
//! Chunks assigned to this thread for a full/outer scan
|
604
|
+
idx_t full_outer_chunk_idx_from;
|
605
|
+
idx_t full_outer_chunk_idx_to;
|
606
|
+
unique_ptr<JoinHTScanState> full_outer_scan_state;
|
606
607
|
};
|
607
608
|
|
608
609
|
unique_ptr<GlobalSourceState> PhysicalHashJoin::GetGlobalSourceState(ClientContext &context) const {
|
@@ -615,36 +616,32 @@ unique_ptr<LocalSourceState> PhysicalHashJoin::GetLocalSourceState(ExecutionCont
|
|
615
616
|
}
|
616
617
|
|
617
618
|
HashJoinGlobalSourceState::HashJoinGlobalSourceState(const PhysicalHashJoin &op, ClientContext &context)
|
618
|
-
: op(op), global_stage(HashJoinSourceStage::INIT),
|
619
|
-
probe_count(op.children[0]->estimated_cardinality),
|
619
|
+
: op(op), global_stage(HashJoinSourceStage::INIT), build_chunk_count(0), build_chunk_done(0), probe_chunk_count(0),
|
620
|
+
probe_chunk_done(0), probe_count(op.children[0]->estimated_cardinality),
|
620
621
|
parallel_scan_chunk_count(context.config.verify_parallelism ? 1 : 120) {
|
621
622
|
}
|
622
623
|
|
623
|
-
void HashJoinGlobalSourceState::Initialize(
|
624
|
+
void HashJoinGlobalSourceState::Initialize(HashJoinGlobalSinkState &sink) {
|
624
625
|
lock_guard<mutex> init_lock(lock);
|
625
626
|
if (global_stage != HashJoinSourceStage::INIT) {
|
626
627
|
// Another thread initialized
|
627
628
|
return;
|
628
629
|
}
|
629
|
-
full_outer_scan.total = sink.hash_table->Count();
|
630
|
-
|
631
|
-
idx_t num_blocks = sink.hash_table->GetBlockCollection().blocks.size();
|
632
|
-
idx_t num_threads = TaskScheduler::GetScheduler(context).NumberOfThreads();
|
633
|
-
build_blocks_per_thread = MaxValue<idx_t>((num_blocks + num_threads - 1) / num_threads, 1);
|
634
630
|
|
635
|
-
// Finalize the probe spill
|
631
|
+
// Finalize the probe spill
|
636
632
|
if (sink.probe_spill) {
|
637
633
|
sink.probe_spill->Finalize();
|
638
634
|
}
|
639
635
|
|
640
636
|
global_stage = HashJoinSourceStage::PROBE;
|
637
|
+
TryPrepareNextStage(sink);
|
641
638
|
}
|
642
639
|
|
643
640
|
void HashJoinGlobalSourceState::TryPrepareNextStage(HashJoinGlobalSinkState &sink) {
|
644
|
-
lock_guard<mutex> guard(lock);
|
645
641
|
switch (global_stage.load()) {
|
646
642
|
case HashJoinSourceStage::BUILD:
|
647
|
-
if (
|
643
|
+
if (build_chunk_done == build_chunk_count) {
|
644
|
+
sink.hash_table->GetDataCollection().VerifyEverythingPinned();
|
648
645
|
sink.hash_table->finalized = true;
|
649
646
|
PrepareProbe(sink);
|
650
647
|
}
|
@@ -652,14 +649,14 @@ void HashJoinGlobalSourceState::TryPrepareNextStage(HashJoinGlobalSinkState &sin
|
|
652
649
|
case HashJoinSourceStage::PROBE:
|
653
650
|
if (probe_chunk_done == probe_chunk_count) {
|
654
651
|
if (IsRightOuterJoin(op.join_type)) {
|
655
|
-
|
652
|
+
PrepareScanHT(sink);
|
656
653
|
} else {
|
657
654
|
PrepareBuild(sink);
|
658
655
|
}
|
659
656
|
}
|
660
657
|
break;
|
661
658
|
case HashJoinSourceStage::SCAN_HT:
|
662
|
-
if (
|
659
|
+
if (full_outer_chunk_done == full_outer_chunk_count) {
|
663
660
|
PrepareBuild(sink);
|
664
661
|
}
|
665
662
|
break;
|
@@ -673,15 +670,24 @@ void HashJoinGlobalSourceState::PrepareBuild(HashJoinGlobalSinkState &sink) {
|
|
673
670
|
auto &ht = *sink.hash_table;
|
674
671
|
|
675
672
|
// Try to put the next partitions in the block collection of the HT
|
676
|
-
if (!ht.PrepareExternalFinalize()) {
|
673
|
+
if (!sink.external || !ht.PrepareExternalFinalize()) {
|
677
674
|
global_stage = HashJoinSourceStage::DONE;
|
678
675
|
return;
|
679
676
|
}
|
680
677
|
|
681
|
-
auto &
|
682
|
-
|
683
|
-
|
684
|
-
|
678
|
+
auto &data_collection = ht.GetDataCollection();
|
679
|
+
if (data_collection.Count() == 0 && op.EmptyResultIfRHSIsEmpty()) {
|
680
|
+
PrepareBuild(sink);
|
681
|
+
return;
|
682
|
+
}
|
683
|
+
|
684
|
+
build_chunk_idx = 0;
|
685
|
+
build_chunk_count = data_collection.ChunkCount();
|
686
|
+
build_chunk_done = 0;
|
687
|
+
|
688
|
+
auto num_threads = TaskScheduler::GetScheduler(sink.context).NumberOfThreads();
|
689
|
+
build_chunks_per_thread = MaxValue<idx_t>((build_chunk_count + num_threads - 1) / num_threads, 1);
|
690
|
+
|
685
691
|
ht.InitializePointerTable();
|
686
692
|
|
687
693
|
global_stage = HashJoinSourceStage::BUILD;
|
@@ -689,16 +695,31 @@ void HashJoinGlobalSourceState::PrepareBuild(HashJoinGlobalSinkState &sink) {
|
|
689
695
|
|
690
696
|
void HashJoinGlobalSourceState::PrepareProbe(HashJoinGlobalSinkState &sink) {
|
691
697
|
sink.probe_spill->PrepareNextProbe();
|
698
|
+
const auto &consumer = *sink.probe_spill->consumer;
|
692
699
|
|
693
|
-
probe_chunk_count =
|
700
|
+
probe_chunk_count = consumer.Count() == 0 ? 0 : consumer.ChunkCount();
|
694
701
|
probe_chunk_done = 0;
|
695
702
|
|
696
|
-
|
697
|
-
|
698
|
-
|
703
|
+
global_stage = HashJoinSourceStage::PROBE;
|
704
|
+
if (probe_chunk_count == 0) {
|
705
|
+
TryPrepareNextStage(sink);
|
706
|
+
return;
|
699
707
|
}
|
708
|
+
}
|
700
709
|
|
701
|
-
|
710
|
+
void HashJoinGlobalSourceState::PrepareScanHT(HashJoinGlobalSinkState &sink) {
|
711
|
+
D_ASSERT(global_stage != HashJoinSourceStage::SCAN_HT);
|
712
|
+
auto &ht = *sink.hash_table;
|
713
|
+
|
714
|
+
auto &data_collection = ht.GetDataCollection();
|
715
|
+
full_outer_chunk_idx = 0;
|
716
|
+
full_outer_chunk_count = data_collection.ChunkCount();
|
717
|
+
full_outer_chunk_done = 0;
|
718
|
+
|
719
|
+
auto num_threads = TaskScheduler::GetScheduler(sink.context).NumberOfThreads();
|
720
|
+
full_outer_chunks_per_thread = MaxValue<idx_t>((full_outer_chunk_count + num_threads - 1) / num_threads, 1);
|
721
|
+
|
722
|
+
global_stage = HashJoinSourceStage::SCAN_HT;
|
702
723
|
}
|
703
724
|
|
704
725
|
bool HashJoinGlobalSourceState::AssignTask(HashJoinGlobalSinkState &sink, HashJoinLocalSourceState &lstate) {
|
@@ -707,24 +728,28 @@ bool HashJoinGlobalSourceState::AssignTask(HashJoinGlobalSinkState &sink, HashJo
|
|
707
728
|
lock_guard<mutex> guard(lock);
|
708
729
|
switch (global_stage.load()) {
|
709
730
|
case HashJoinSourceStage::BUILD:
|
710
|
-
if (
|
731
|
+
if (build_chunk_idx != build_chunk_count) {
|
711
732
|
lstate.local_stage = global_stage;
|
712
|
-
lstate.
|
713
|
-
|
714
|
-
lstate.
|
733
|
+
lstate.build_chunk_idx_from = build_chunk_idx;
|
734
|
+
build_chunk_idx = MinValue<idx_t>(build_chunk_count, build_chunk_idx + build_chunks_per_thread);
|
735
|
+
lstate.build_chunk_idx_to = build_chunk_idx;
|
715
736
|
return true;
|
716
737
|
}
|
717
738
|
break;
|
718
739
|
case HashJoinSourceStage::PROBE:
|
719
740
|
if (sink.probe_spill->consumer && sink.probe_spill->consumer->AssignChunk(lstate.probe_local_scan)) {
|
720
741
|
lstate.local_stage = global_stage;
|
742
|
+
lstate.empty_ht_probe_in_progress = false;
|
721
743
|
return true;
|
722
744
|
}
|
723
745
|
break;
|
724
746
|
case HashJoinSourceStage::SCAN_HT:
|
725
|
-
if (
|
747
|
+
if (full_outer_chunk_idx != full_outer_chunk_count) {
|
726
748
|
lstate.local_stage = global_stage;
|
727
|
-
lstate.
|
749
|
+
lstate.full_outer_chunk_idx_from = full_outer_chunk_idx;
|
750
|
+
full_outer_chunk_idx =
|
751
|
+
MinValue<idx_t>(full_outer_chunk_count, full_outer_chunk_idx + full_outer_chunks_per_thread);
|
752
|
+
lstate.full_outer_chunk_idx_to = full_outer_chunk_idx;
|
728
753
|
return true;
|
729
754
|
}
|
730
755
|
break;
|
@@ -779,9 +804,9 @@ bool HashJoinLocalSourceState::TaskFinished() {
|
|
779
804
|
case HashJoinSourceStage::BUILD:
|
780
805
|
return true;
|
781
806
|
case HashJoinSourceStage::PROBE:
|
782
|
-
return scan_structure == nullptr;
|
807
|
+
return scan_structure == nullptr && !empty_ht_probe_in_progress;
|
783
808
|
case HashJoinSourceStage::SCAN_HT:
|
784
|
-
return
|
809
|
+
return full_outer_scan_state == nullptr;
|
785
810
|
default:
|
786
811
|
throw InternalException("Unexpected HashJoinSourceStage in TaskFinished!");
|
787
812
|
}
|
@@ -791,10 +816,10 @@ void HashJoinLocalSourceState::ExternalBuild(HashJoinGlobalSinkState &sink, Hash
|
|
791
816
|
D_ASSERT(local_stage == HashJoinSourceStage::BUILD);
|
792
817
|
|
793
818
|
auto &ht = *sink.hash_table;
|
794
|
-
ht.Finalize(
|
819
|
+
ht.Finalize(build_chunk_idx_from, build_chunk_idx_to, true);
|
795
820
|
|
796
821
|
lock_guard<mutex> guard(gstate.lock);
|
797
|
-
gstate.
|
822
|
+
gstate.build_chunk_done += build_chunk_idx_to - build_chunk_idx_from;
|
798
823
|
}
|
799
824
|
|
800
825
|
void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate,
|
@@ -802,14 +827,20 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash
|
|
802
827
|
D_ASSERT(local_stage == HashJoinSourceStage::PROBE && sink.hash_table->finalized);
|
803
828
|
|
804
829
|
if (scan_structure) {
|
805
|
-
//
|
830
|
+
// Still have elements remaining (i.e. we got >STANDARD_VECTOR_SIZE elements in the previous probe)
|
806
831
|
scan_structure->Next(join_keys, payload, chunk);
|
807
|
-
if (chunk.size()
|
808
|
-
|
809
|
-
sink.probe_spill->consumer->FinishChunk(probe_local_scan);
|
810
|
-
lock_guard<mutex> lock(gstate.lock);
|
811
|
-
gstate.probe_chunk_done++;
|
832
|
+
if (chunk.size() != 0) {
|
833
|
+
return;
|
812
834
|
}
|
835
|
+
}
|
836
|
+
|
837
|
+
if (scan_structure || empty_ht_probe_in_progress) {
|
838
|
+
// Previous probe is done
|
839
|
+
scan_structure = nullptr;
|
840
|
+
empty_ht_probe_in_progress = false;
|
841
|
+
sink.probe_spill->consumer->FinishChunk(probe_local_scan);
|
842
|
+
lock_guard<mutex> lock(gstate.lock);
|
843
|
+
gstate.probe_chunk_done++;
|
813
844
|
return;
|
814
845
|
}
|
815
846
|
|
@@ -821,6 +852,12 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash
|
|
821
852
|
payload.ReferenceColumns(probe_chunk, payload_indices);
|
822
853
|
auto precomputed_hashes = &probe_chunk.data.back();
|
823
854
|
|
855
|
+
if (sink.hash_table->Count() == 0 && !gstate.op.EmptyResultIfRHSIsEmpty()) {
|
856
|
+
gstate.op.ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, payload, chunk);
|
857
|
+
empty_ht_probe_in_progress = true;
|
858
|
+
return;
|
859
|
+
}
|
860
|
+
|
824
861
|
// Perform the probe
|
825
862
|
scan_structure = sink.hash_table->Probe(join_keys, precomputed_hashes);
|
826
863
|
scan_structure->Next(join_keys, payload, chunk);
|
@@ -828,27 +865,19 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash
|
|
828
865
|
|
829
866
|
void HashJoinLocalSourceState::ExternalScanHT(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate,
|
830
867
|
DataChunk &chunk) {
|
831
|
-
D_ASSERT(local_stage == HashJoinSourceStage::SCAN_HT
|
868
|
+
D_ASSERT(local_stage == HashJoinSourceStage::SCAN_HT);
|
832
869
|
|
833
|
-
if (
|
834
|
-
|
835
|
-
|
836
|
-
full_outer_found_entries = 0;
|
837
|
-
return;
|
870
|
+
if (!full_outer_scan_state) {
|
871
|
+
full_outer_scan_state = make_uniq<JoinHTScanState>(sink.hash_table->GetDataCollection(),
|
872
|
+
full_outer_chunk_idx_from, full_outer_chunk_idx_to);
|
838
873
|
}
|
874
|
+
sink.hash_table->ScanFullOuter(*full_outer_scan_state, addresses, chunk);
|
839
875
|
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
}
|
845
|
-
|
846
|
-
void HashJoinLocalSourceState::ScanFullOuter(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate) {
|
847
|
-
auto &fo_ss = gstate.full_outer_scan;
|
848
|
-
idx_t scan_index_before = fo_ss.scan_index;
|
849
|
-
full_outer_found_entries = sink.hash_table->ScanFullOuter(fo_ss, addresses);
|
850
|
-
idx_t scanned = fo_ss.scan_index - scan_index_before;
|
851
|
-
full_outer_in_progress = scanned;
|
876
|
+
if (chunk.size() == 0) {
|
877
|
+
full_outer_scan_state = nullptr;
|
878
|
+
lock_guard<mutex> guard(gstate.lock);
|
879
|
+
gstate.full_outer_chunk_done += full_outer_chunk_idx_to - full_outer_chunk_idx_from;
|
880
|
+
}
|
852
881
|
}
|
853
882
|
|
854
883
|
void PhysicalHashJoin::GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p,
|
@@ -858,20 +887,12 @@ void PhysicalHashJoin::GetData(ExecutionContext &context, DataChunk &chunk, Glob
|
|
858
887
|
auto &lstate = lstate_p.Cast<HashJoinLocalSourceState>();
|
859
888
|
sink.scanned_data = true;
|
860
889
|
|
861
|
-
if (!sink.external) {
|
862
|
-
if (IsRightOuterJoin(join_type)) {
|
863
|
-
{
|
864
|
-
lock_guard<mutex> guard(gstate.lock);
|
865
|
-
lstate.ScanFullOuter(sink, gstate);
|
866
|
-
}
|
867
|
-
sink.hash_table->GatherFullOuter(chunk, lstate.addresses, lstate.full_outer_found_entries);
|
868
|
-
}
|
890
|
+
if (!sink.external && !IsRightOuterJoin(join_type)) {
|
869
891
|
return;
|
870
892
|
}
|
871
893
|
|
872
|
-
D_ASSERT(can_go_external);
|
873
894
|
if (gstate.global_stage == HashJoinSourceStage::INIT) {
|
874
|
-
gstate.Initialize(
|
895
|
+
gstate.Initialize(sink);
|
875
896
|
}
|
876
897
|
|
877
898
|
// Any call to GetData must produce tuples, otherwise the pipeline executor thinks that we're done
|
@@ -880,6 +901,7 @@ void PhysicalHashJoin::GetData(ExecutionContext &context, DataChunk &chunk, Glob
|
|
880
901
|
if (!lstate.TaskFinished() || gstate.AssignTask(sink, lstate)) {
|
881
902
|
lstate.ExecuteTask(sink, gstate, chunk);
|
882
903
|
} else {
|
904
|
+
lock_guard<mutex> guard(gstate.lock);
|
883
905
|
gstate.TryPrepareNextStage(sink);
|
884
906
|
}
|
885
907
|
}
|