1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::collections::BTreeMap;
use query_planning::correlation::QueryId;
use super::QueryMetrics;
/// Join-strategy decision facts captured for diagnostics.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct JoinStrategyDecisionMetrics {
/// Query-wide diagnostic correlation id, when assigned.
pub(crate) query_id: Option<QueryId>,
/// Native join node id.
pub node_id: String,
/// Stable decision fact keys and values.
pub facts: BTreeMap<String, String>,
}
/// Join-specific operator metrics.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct JoinOperatorMetrics {
/// Query-wide diagnostic correlation id, when assigned.
pub query_id: Option<QueryId>,
/// Join type label.
pub join_type: String,
/// Execution strategy label.
pub execution_strategy: String,
/// Number of equality key pairs.
pub key_count: usize,
/// Whether a residual predicate was present.
pub residual_predicate: bool,
/// Null-equality policy label.
pub null_equality: String,
/// Planner orientation used to execute or describe this join.
///
/// For reusable hash joins this is the side that owns the hash table. For
/// keyless conditional and cross joins no hash table is built. For those
/// joins the value is an orientation label for comparable metrics, and no
/// physical build artifact backs it.
pub build_side: String,
/// The side opposite `build_side` in the planner orientation.
pub probe_side: String,
/// Build-side input row count.
pub build_rows: u64,
/// Build-side input bytes.
pub build_bytes: u64,
/// Probe-side input row count.
pub probe_rows: u64,
/// Probe-side input bytes.
pub probe_bytes: u64,
/// Device bytes retained by the reusable cuDF join build artifact.
///
/// This is a direct cudf observation. For hash joins it is the retained
/// hash table; for filtered joins it is the retained filtered-join build
/// artifact. It remains `0` for join paths without a reusable build artifact.
pub hash_table_bytes: u64,
/// Device bytes retained by a filtered-join probe state.
pub filtered_probe_state_bytes: u64,
/// Device bytes retained by a mixed join retained size-data state.
pub mixed_size_data_bytes: u64,
/// Device bytes retained by join gather maps produced for this join.
///
/// This is a direct cudf observation over the returned device index
/// columns; no row-count estimate is involved.
pub gather_map_bytes: u64,
/// Upper bound of the join output's materialized bytes, `None` when the
/// byte model cannot bound one of its columns.
pub output_reservation_bytes: Option<u64>,
/// Join output row count.
pub output_rows: u64,
/// Join output bytes.
pub output_bytes: u64,
}
impl QueryMetrics {
/// Records join-strategy diagnostics for a node.
pub fn record_join_strategy_decision(&mut self, node_id: impl ToString, facts: &BTreeMap<&'static str, String>) {
self.join_strategy_decisions.push(JoinStrategyDecisionMetrics {
query_id: self.inherited_query_id(),
node_id: node_id.to_string(),
facts: facts.iter().map(|(key, value)| ((*key).to_string(), value.clone())).collect(),
});
}
/// Records one reusable hash-join build.
pub fn record_hash_join_build(&mut self) {
self.hash_join_build_count = self.hash_join_build_count.saturating_add(1);
}
/// Records one reusable filtered-join build.
pub fn record_filtered_join_build(&mut self) {
self.filtered_join_build_count = self.filtered_join_build_count.saturating_add(1);
}
/// Records a one-shot join execution.
pub fn record_one_shot_join(&mut self) {
self.one_shot_join_count = self.one_shot_join_count.saturating_add(1);
}
/// Adds retained hash-join hash table bytes.
pub fn record_hash_join_hash_table_bytes(&mut self, bytes: u64) {
self.hash_join_hash_table_bytes = self.hash_join_hash_table_bytes.saturating_add(bytes);
}
/// Adds retained filtered-join hash table bytes.
pub fn record_filtered_join_hash_table_bytes(&mut self, bytes: u64) {
self.filtered_join_hash_table_bytes = self.filtered_join_hash_table_bytes.saturating_add(bytes);
}
/// Adds retained filtered-join probe-state bytes.
pub fn record_filtered_join_probe_state_bytes(&mut self, bytes: u64) {
self.filtered_join_probe_state_bytes = self.filtered_join_probe_state_bytes.saturating_add(bytes);
}
/// Adds retained mixed-join size-data bytes.
pub fn record_mixed_join_size_data_bytes(&mut self, bytes: u64) {
self.mixed_join_size_data_bytes = self.mixed_join_size_data_bytes.saturating_add(bytes);
}
/// Adds one-shot join index-map bytes.
pub fn record_one_shot_join_index_bytes(&mut self, bytes: u64) {
self.one_shot_join_index_bytes = self.one_shot_join_index_bytes.saturating_add(bytes);
}
/// Adds one-shot join output materialization reservation bytes.
pub fn record_one_shot_join_materialization_bytes(&mut self, bytes: u64) {
self.one_shot_join_materialization_bytes = self.one_shot_join_materialization_bytes.saturating_add(bytes);
}
/// Adds one-shot join output bytes.
pub fn record_one_shot_join_output_bytes(&mut self, bytes: u64) {
self.one_shot_join_output_bytes = self.one_shot_join_output_bytes.saturating_add(bytes);
}
}