diff --git a/.chloggen/drosiek-mysql-select-metric.yaml b/.chloggen/drosiek-mysql-select-metric.yaml
new file mode 100755
index 000000000000..e2aeb37384b6
--- /dev/null
+++ b/.chloggen/drosiek-mysql-select-metric.yaml
@@ -0,0 +1,16 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: enhancement
+
+# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
+component: mysqlreceiver
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: add mysql.joins metric
+
+# One or more tracking issues related to the change
+issues: [14138]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext:
diff --git a/receiver/mysqlreceiver/documentation.md b/receiver/mysqlreceiver/documentation.md
index 9b35170ee455..a5f454197a6a 100644
--- a/receiver/mysqlreceiver/documentation.md
+++ b/receiver/mysqlreceiver/documentation.md
@@ -19,6 +19,7 @@ These are the metrics available for this scraper.
| **mysql.handlers** | The number of requests to various MySQL handlers. | 1 | Sum(Int) |
|
| **mysql.index.io.wait.count** | The total count of I/O wait events for an index. | 1 | Sum(Int) | - io_waits_operations
- table_name
- schema
- index_name
|
| **mysql.index.io.wait.time** | The total time of I/O wait events for an index. | ns | Sum(Int) | - io_waits_operations
- table_name
- schema
- index_name
|
+| **mysql.joins** | The number of joins that perform table scans. | 1 | Sum(Int) | |
| **mysql.locks** | The number of MySQL locks. | 1 | Sum(Int) | |
| **mysql.log_operations** | The number of InnoDB log operations. | 1 | Sum(Int) | |
| **mysql.operations** | The number of InnoDB operations. | 1 | Sum(Int) | |
@@ -58,6 +59,7 @@ metrics:
| handler (kind) | The handler types. | commit, delete, discover, external_lock, mrr_init, prepare, read_first, read_key, read_last, read_next, read_prev, read_rnd, read_rnd_next, rollback, savepoint, savepoint_rollback, update, write |
| index_name (index) | The name of the index. | |
| io_waits_operations (operation) | The io_waits operation type. | delete, fetch, insert, update |
+| join_kind (kind) | The kind of join. | full, full_range, range, range_check, scan |
| locks (kind) | The table locks type. | immediate, waited |
| log_operations (operation) | The log operation types. | waits, write_requests, writes |
| operations (operation) | The operation types. | fsyncs, reads, writes |
diff --git a/receiver/mysqlreceiver/internal/metadata/generated_metrics.go b/receiver/mysqlreceiver/internal/metadata/generated_metrics.go
index bd607f400d3c..d6bc3d44d3c9 100644
--- a/receiver/mysqlreceiver/internal/metadata/generated_metrics.go
+++ b/receiver/mysqlreceiver/internal/metadata/generated_metrics.go
@@ -30,6 +30,7 @@ type MetricsSettings struct {
MysqlHandlers MetricSettings `mapstructure:"mysql.handlers"`
MysqlIndexIoWaitCount MetricSettings `mapstructure:"mysql.index.io.wait.count"`
MysqlIndexIoWaitTime MetricSettings `mapstructure:"mysql.index.io.wait.time"`
+ MysqlJoins MetricSettings `mapstructure:"mysql.joins"`
MysqlLocks MetricSettings `mapstructure:"mysql.locks"`
MysqlLogOperations MetricSettings `mapstructure:"mysql.log_operations"`
MysqlOperations MetricSettings `mapstructure:"mysql.operations"`
@@ -78,6 +79,9 @@ func DefaultMetricsSettings() MetricsSettings {
MysqlIndexIoWaitTime: MetricSettings{
Enabled: true,
},
+ MysqlJoins: MetricSettings{
+ Enabled: true,
+ },
MysqlLocks: MetricSettings{
Enabled: true,
},
@@ -408,6 +412,44 @@ var MapAttributeIoWaitsOperations = map[string]AttributeIoWaitsOperations{
"update": AttributeIoWaitsOperationsUpdate,
}
+// AttributeJoinKind specifies the a value join_kind attribute.
+type AttributeJoinKind int
+
+const (
+ _ AttributeJoinKind = iota
+ AttributeJoinKindFull
+ AttributeJoinKindFullRange
+ AttributeJoinKindRange
+ AttributeJoinKindRangeCheck
+ AttributeJoinKindScan
+)
+
+// String returns the string representation of the AttributeJoinKind.
+func (av AttributeJoinKind) String() string {
+ switch av {
+ case AttributeJoinKindFull:
+ return "full"
+ case AttributeJoinKindFullRange:
+ return "full_range"
+ case AttributeJoinKindRange:
+ return "range"
+ case AttributeJoinKindRangeCheck:
+ return "range_check"
+ case AttributeJoinKindScan:
+ return "scan"
+ }
+ return ""
+}
+
+// MapAttributeJoinKind is a helper map of string to AttributeJoinKind attribute value.
+var MapAttributeJoinKind = map[string]AttributeJoinKind{
+ "full": AttributeJoinKindFull,
+ "full_range": AttributeJoinKindFullRange,
+ "range": AttributeJoinKindRange,
+ "range_check": AttributeJoinKindRangeCheck,
+ "scan": AttributeJoinKindScan,
+}
+
// AttributeLocks specifies the a value locks attribute.
type AttributeLocks int
@@ -1267,6 +1309,59 @@ func newMetricMysqlIndexIoWaitTime(settings MetricSettings) metricMysqlIndexIoWa
return m
}
+type metricMysqlJoins struct {
+ data pmetric.Metric // data buffer for generated metric.
+ settings MetricSettings // metric settings provided by user.
+ capacity int // max observed number of data points added to the metric.
+}
+
+// init fills mysql.joins metric with initial data.
+func (m *metricMysqlJoins) init() {
+ m.data.SetName("mysql.joins")
+ m.data.SetDescription("The number of joins that perform table scans.")
+ m.data.SetUnit("1")
+ m.data.SetEmptySum()
+ m.data.Sum().SetIsMonotonic(true)
+ m.data.Sum().SetAggregationTemporality(pmetric.MetricAggregationTemporalityCumulative)
+ m.data.Sum().DataPoints().EnsureCapacity(m.capacity)
+}
+
+func (m *metricMysqlJoins) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, joinKindAttributeValue string) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntValue(val)
+ dp.Attributes().PutStr("kind", joinKindAttributeValue)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricMysqlJoins) updateCapacity() {
+ if m.data.Sum().DataPoints().Len() > m.capacity {
+ m.capacity = m.data.Sum().DataPoints().Len()
+ }
+}
+
+// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points.
+func (m *metricMysqlJoins) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricMysqlJoins(settings MetricSettings) metricMysqlJoins {
+ m := metricMysqlJoins{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
type metricMysqlLocks struct {
data pmetric.Metric // data buffer for generated metric.
settings MetricSettings // metric settings provided by user.
@@ -1873,6 +1968,7 @@ type MetricsBuilder struct {
metricMysqlHandlers metricMysqlHandlers
metricMysqlIndexIoWaitCount metricMysqlIndexIoWaitCount
metricMysqlIndexIoWaitTime metricMysqlIndexIoWaitTime
+ metricMysqlJoins metricMysqlJoins
metricMysqlLocks metricMysqlLocks
metricMysqlLogOperations metricMysqlLogOperations
metricMysqlOperations metricMysqlOperations
@@ -1912,6 +2008,7 @@ func NewMetricsBuilder(settings MetricsSettings, buildInfo component.BuildInfo,
metricMysqlHandlers: newMetricMysqlHandlers(settings.MysqlHandlers),
metricMysqlIndexIoWaitCount: newMetricMysqlIndexIoWaitCount(settings.MysqlIndexIoWaitCount),
metricMysqlIndexIoWaitTime: newMetricMysqlIndexIoWaitTime(settings.MysqlIndexIoWaitTime),
+ metricMysqlJoins: newMetricMysqlJoins(settings.MysqlJoins),
metricMysqlLocks: newMetricMysqlLocks(settings.MysqlLocks),
metricMysqlLogOperations: newMetricMysqlLogOperations(settings.MysqlLogOperations),
metricMysqlOperations: newMetricMysqlOperations(settings.MysqlOperations),
@@ -1993,6 +2090,7 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) {
mb.metricMysqlHandlers.emit(ils.Metrics())
mb.metricMysqlIndexIoWaitCount.emit(ils.Metrics())
mb.metricMysqlIndexIoWaitTime.emit(ils.Metrics())
+ mb.metricMysqlJoins.emit(ils.Metrics())
mb.metricMysqlLocks.emit(ils.Metrics())
mb.metricMysqlLogOperations.emit(ils.Metrics())
mb.metricMysqlOperations.emit(ils.Metrics())
@@ -2113,6 +2211,16 @@ func (mb *MetricsBuilder) RecordMysqlIndexIoWaitTimeDataPoint(ts pcommon.Timesta
mb.metricMysqlIndexIoWaitTime.recordDataPoint(mb.startTime, ts, val, ioWaitsOperationsAttributeValue.String(), tableNameAttributeValue, schemaAttributeValue, indexNameAttributeValue)
}
+// RecordMysqlJoinsDataPoint adds a data point to mysql.joins metric.
+func (mb *MetricsBuilder) RecordMysqlJoinsDataPoint(ts pcommon.Timestamp, inputVal string, joinKindAttributeValue AttributeJoinKind) error {
+ val, err := strconv.ParseInt(inputVal, 10, 64)
+ if err != nil {
+ return fmt.Errorf("failed to parse int64 for MysqlJoins, value was %s: %w", inputVal, err)
+ }
+ mb.metricMysqlJoins.recordDataPoint(mb.startTime, ts, val, joinKindAttributeValue.String())
+ return nil
+}
+
// RecordMysqlLocksDataPoint adds a data point to mysql.locks metric.
func (mb *MetricsBuilder) RecordMysqlLocksDataPoint(ts pcommon.Timestamp, inputVal string, locksAttributeValue AttributeLocks) error {
val, err := strconv.ParseInt(inputVal, 10, 64)
diff --git a/receiver/mysqlreceiver/metadata.yaml b/receiver/mysqlreceiver/metadata.yaml
index 8d919bdafd28..7e83e9fa06bc 100644
--- a/receiver/mysqlreceiver/metadata.yaml
+++ b/receiver/mysqlreceiver/metadata.yaml
@@ -75,6 +75,10 @@ attributes:
index_name:
value: index
description: The name of the index.
+ join_kind:
+ value: kind
+ description: The kind of join.
+ enum: [full, full_range, range, range_check, scan]
tmp_resource:
value: resource
description: The kind of temporary resources.
@@ -283,6 +287,16 @@ metrics:
monotonic: false
aggregation: cumulative
attributes: [threads]
+ mysql.joins:
+ enabled: true
+ description: The number of joins that perform table scans.
+ unit: 1
+ sum:
+ value_type: int
+ input_type: string
+ monotonic: true
+ aggregation: cumulative
+ attributes: [join_kind]
mysql.tmp_resources:
enabled: true
description: The number of created temporary resources.
diff --git a/receiver/mysqlreceiver/scraper.go b/receiver/mysqlreceiver/scraper.go
index 9b7163505547..db94a7cc5b3b 100644
--- a/receiver/mysqlreceiver/scraper.go
+++ b/receiver/mysqlreceiver/scraper.go
@@ -274,6 +274,18 @@ func (m *mySQLScraper) scrapeGlobalStats(now pcommon.Timestamp, errs *scrapererr
case "Table_locks_waited":
addPartialIfError(errs, m.mb.RecordMysqlLocksDataPoint(now, v, metadata.AttributeLocksWaited))
+ // joins
+ case "Select_full_join":
+ addPartialIfError(errs, m.mb.RecordMysqlJoinsDataPoint(now, v, metadata.AttributeJoinKindFull))
+ case "Select_full_range_join":
+ addPartialIfError(errs, m.mb.RecordMysqlJoinsDataPoint(now, v, metadata.AttributeJoinKindFullRange))
+ case "Select_range":
+ addPartialIfError(errs, m.mb.RecordMysqlJoinsDataPoint(now, v, metadata.AttributeJoinKindRange))
+ case "Select_range_check":
+ addPartialIfError(errs, m.mb.RecordMysqlJoinsDataPoint(now, v, metadata.AttributeJoinKindRangeCheck))
+ case "Select_scan":
+ addPartialIfError(errs, m.mb.RecordMysqlJoinsDataPoint(now, v, metadata.AttributeJoinKindScan))
+
// sorts
case "Sort_merge_passes":
addPartialIfError(errs, m.mb.RecordMysqlSortsDataPoint(now, v, metadata.AttributeSortsMergePasses))
diff --git a/receiver/mysqlreceiver/testdata/scraper/expected.json b/receiver/mysqlreceiver/testdata/scraper/expected.json
index bed533c47f10..4224583f5bd5 100644
--- a/receiver/mysqlreceiver/testdata/scraper/expected.json
+++ b/receiver/mysqlreceiver/testdata/scraper/expected.json
@@ -1537,6 +1537,77 @@
},
"unit": "ns"
},
+ {
+ "description": "The number of joins that perform table scans.",
+ "name": "mysql.joins",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "isMonotonic": true,
+ "dataPoints": [
+ {
+ "asInt": "408",
+ "attributes": [
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "full"
+ }
+ } ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "409",
+ "attributes": [
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "full_range"
+ }
+ } ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "410",
+ "attributes": [
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "range"
+ }
+ } ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "411",
+ "attributes": [
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "range_check"
+ }
+ } ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ },
+ {
+ "asInt": "412",
+ "attributes": [
+ {
+ "key": "kind",
+ "value": {
+ "stringValue": "scan"
+ }
+ } ],
+ "startTimeUnixNano": "1644862687825728000",
+ "timeUnixNano": "1644862687825772000"
+ }
+ ]
+ },
+ "unit": "1"
+ },
{
"description": "The number of created temporary resources.",
"name": "mysql.tmp_resources",