This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new d8826078f68 IGNITE-29011 SQL: Add result set size metrics for queries
- Fixes #13517.
d8826078f68 is described below
commit d8826078f689bf3202c2082ad7520eddba2964da
Author: Aleksey Plekhanov <[email protected]>
AuthorDate: Fri Sep 4 09:55:27 2026 +0300
IGNITE-29011 SQL: Add result set size metrics for queries - Fixes #13517.
Signed-off-by: Aleksey Plekhanov <[email protected]>
---
docs/_docs/monitoring-metrics/new-metrics.adoc | 2 +
.../query/calcite/exec/ExecutionServiceImpl.java | 2 +
.../integration/ResultSetSizeMetricsTest.java | 130 +++++++++++++++++++++
.../ignite/testsuites/IntegrationTestSuite.java | 2 +
.../query/running/RunningQueryManager.java | 25 ++++
.../processors/query/h2/H2ResultSetIterator.java | 2 +
.../query/h2/twostep/GridReduceQueryExecutor.java | 5 +
.../query/h2/twostep/ReduceIndexIterator.java | 6 +
8 files changed, 174 insertions(+)
diff --git a/docs/_docs/monitoring-metrics/new-metrics.adoc
b/docs/_docs/monitoring-metrics/new-metrics.adoc
index 7b749d7d212..23ce5e1a9e9 100644
--- a/docs/_docs/monitoring-metrics/new-metrics.adoc
+++ b/docs/_docs/monitoring-metrics/new-metrics.adoc
@@ -520,4 +520,6 @@ Register name: `sql.queries.user`
|success| long | The number of succesfully executed SQL queries.
|failed| long | The number of failed SQL queries (including canceled).
|canceled| long | The number of canceled SQL queries.
+|resultSetSizeHistogram| histogram | Histogram of fetched result set sizes for
SQL queries.
+|maxResultSetSize| max value | Maximum fetched result set size for SQL queries.
|===
diff --git
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
index 5ab4e94c773..3824416e78b 100644
---
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
+++
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
@@ -1270,6 +1270,8 @@ public class ExecutionServiceImpl<Row> extends
AbstractService implements Execut
);
}
+
ctx.query().runningQueryManager().onFullyFetched(resultSetChecker.fetchedSize());
+
resultSetChecker.checkOnClose();
};
diff --git
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/ResultSetSizeMetricsTest.java
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/ResultSetSizeMetricsTest.java
new file mode 100644
index 00000000000..95430e21e5e
--- /dev/null
+++
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/ResultSetSizeMetricsTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.internal.processors.query.calcite.integration;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.MetricRegistryImpl;
+import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
+import org.junit.Test;
+
+import static
org.apache.ignite.internal.processors.query.running.RunningQueryManager.SQL_USER_QUERIES_REG_NAME;
+
+/**
+ * Tests for result set size histogram and max result set size metrics.
+ */
+public class ResultSetSizeMetricsTest extends
AbstractMultiEngineIntegrationTest {
+ /** */
+ private static final int FILL_SIZE = 1000;
+
+ /** */
+ @Override protected void afterTest() throws Exception {
+ stopAllGrids();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String
igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setCacheConfiguration(new CacheConfiguration<>(DEFAULT_CACHE_NAME)
+ .setIndexedTypes(Integer.class, Integer.class));
+
+ return cfg;
+ }
+
+ /** */
+ @Test
+ public void testResultSetSizeMetrics() throws Exception {
+ IgniteEx initNode = startGrids(nodeCount());
+
+ IgniteCache<Integer, Integer> cache =
initNode.cache(DEFAULT_CACHE_NAME);
+
+ for (int i = 0; i < FILL_SIZE; i++)
+ cache.put(i, i);
+
+ // Execute simple queries with result set sizes: 0, 1, 5, 50, 500.
+ for (int limit : new int[] {0, 1, 5, 50, 500})
+ sql(initNode, "SELECT _key FROM \"" + DEFAULT_CACHE_NAME +
"\".Integer WHERE _key < ?", limit);
+
+ // Execute queries with aggregation (different reducers on h2) with
result set sizes: 10, 100.
+ for (int limit : new int[] {10, 100})
+ sql(initNode, "SELECT DISTINCT _key FROM \"" + DEFAULT_CACHE_NAME
+ "\".Integer WHERE _key < ?", limit);
+
+ // Verify histogram on the initiating node.
+ // Bounds: {0, 1, 10, 100, 1_000, 10_000, 100_000, 1_000_000}
+ // Bucket 0: x <= 0 -> 1 (size 0)
+ // Bucket 1: x <= 1 -> 1 (size 1)
+ // Bucket 2: x <= 10 -> 2 (sizes 5, 10)
+ // Bucket 3: x <= 100 -> 2 (sizes 50, 100)
+ // Bucket 4: x <= 1000 -> 1 (size 500)
+ // Buckets 5-8 -> 0
+ long[] values = resultSetSizeHistogram(initNode).value();
+
+ assertEquals(1, values[0]);
+ assertEquals(1, values[1]);
+ assertEquals(2, values[2]);
+ assertEquals(2, values[3]);
+ assertEquals(1, values[4]);
+
+ for (int i = 5; i < values.length; i++)
+ assertEquals(0, values[i]);
+
+ // Verify max value on the initiating node.
+ assertEquals(500L, resultSetSizeMax(initNode).value());
+
+ // Verify all other server nodes have zero metrics.
+ for (int i = 0; i < nodeCount(); i++) {
+ IgniteEx node = grid(i);
+
+ if (node == initNode)
+ continue;
+
+ long[] nodeVals = resultSetSizeHistogram(node).value();
+
+ for (long v : nodeVals)
+ assertEquals(0, v);
+
+ assertEquals("Expected max value 0 on node [" + node.name() + "]",
+ 0L, resultSetSizeMax(node).value());
+ }
+ }
+
+ /** */
+ private HistogramMetricImpl resultSetSizeHistogram(IgniteEx ignite) {
+ MetricRegistryImpl mreg =
ignite.context().metric().registry(SQL_USER_QUERIES_REG_NAME);
+
+ HistogramMetricImpl hist = mreg.findMetric("resultSetSizeHistogram");
+
+ assertNotNull(hist);
+
+ return hist;
+ }
+
+ /** */
+ private MaxValueMetric resultSetSizeMax(IgniteEx ignite) {
+ MetricRegistryImpl mreg =
ignite.context().metric().registry(SQL_USER_QUERIES_REG_NAME);
+
+ MaxValueMetric max = mreg.findMetric("maxResultSetSize");
+
+ assertNotNull(max);
+
+ return max;
+ }
+}
diff --git
a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
index 2a2cb856731..c9605a431cd 100644
---
a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
+++
b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java
@@ -68,6 +68,7 @@ import
org.apache.ignite.internal.processors.query.calcite.integration.QueryEngi
import
org.apache.ignite.internal.processors.query.calcite.integration.QueryMetadataIntegrationTest;
import
org.apache.ignite.internal.processors.query.calcite.integration.QueryWithPartitionsIntegrationTest;
import
org.apache.ignite.internal.processors.query.calcite.integration.RecursiveCteIntegrationTest;
+import
org.apache.ignite.internal.processors.query.calcite.integration.ResultSetSizeMetricsTest;
import
org.apache.ignite.internal.processors.query.calcite.integration.RunningQueriesIntegrationTest;
import
org.apache.ignite.internal.processors.query.calcite.integration.ScalarInIntegrationTest;
import
org.apache.ignite.internal.processors.query.calcite.integration.SelectByKeyFieldTest;
@@ -197,6 +198,7 @@ import org.junit.runners.Suite;
SystemColumnsScanTest.class,
BulkOperationDeadlockIntegrationTest.class,
SelectForUpdateIntegrationTest.class,
+ ResultSetSizeMetricsTest.class,
})
public class IntegrationTestSuite {
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/running/RunningQueryManager.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/running/RunningQueryManager.java
index 0d1229add8a..3990d21b353 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/running/RunningQueryManager.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/running/RunningQueryManager.java
@@ -47,7 +47,9 @@ import
org.apache.ignite.internal.processors.cache.query.GridCacheQueryType;
import org.apache.ignite.internal.processors.closure.GridClosureProcessor;
import org.apache.ignite.internal.processors.metric.MetricRegistryImpl;
import org.apache.ignite.internal.processors.metric.impl.AtomicLongMetric;
+import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.LongAdderMetric;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
import org.apache.ignite.internal.processors.query.GridQueryCancel;
import org.apache.ignite.internal.processors.query.GridQueryFinishedInfo;
import org.apache.ignite.internal.processors.query.GridQueryStartedInfo;
@@ -141,6 +143,12 @@ public class RunningQueryManager {
*/
private final AtomicLongMetric canceledQrsCnt;
+ /** Histogram of result set sizes for SQL queries. */
+ private final HistogramMetricImpl resultSetSizeHistogram;
+
+ /** Maximum result set size for SQL queries. */
+ private final MaxValueMetric maxResultSetSize;
+
/** Kernal context. */
private final GridKernalContext ctx;
@@ -231,6 +239,13 @@ public class RunningQueryManager {
canceledQrsCnt = userMetrics.longMetric("canceled", "Number of
canceled queries that have been started " +
"on this node. This metric number included in the general 'failed'
metric.");
+
+ resultSetSizeHistogram =
userMetrics.histogram("resultSetSizeHistogram",
+ new long[] {0, 1, 10, 100, 1_000, 10_000, 100_000, 1_000_000},
+ "Histogram of result set sizes for SQL queries.");
+
+ maxResultSetSize = userMetrics.maxValueMetric("maxResultSetSize",
+ "Maximum result set size for SQL queries.", 60_000L, 5);
}
/** */
@@ -269,6 +284,16 @@ public class RunningQueryManager {
}, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT);
}
+ /**
+ * Called when a result set is fully fetched. Increments result set size
metrics.
+ *
+ * @param size Result set size (number of fetched rows).
+ */
+ public void onFullyFetched(long size) {
+ resultSetSizeHistogram.value(size);
+ maxResultSetSize.update(size);
+ }
+
/**
* Registers running query and returns an id associated with the query.
*
diff --git
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java
index 379b2153677..729fd8b2ef8 100644
---
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java
+++
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2ResultSetIterator.java
@@ -320,6 +320,8 @@ public abstract class H2ResultSetIterator<T> extends
GridIteratorAdapter<T> impl
try {
resultSetChecker.checkOnClose();
+
h2.runningQueryManager().onFullyFetched(resultSetChecker.fetchedSize());
+
PerformanceStatisticsProcessor perfStat =
ctx.performanceStatistics();
if (perfStat.enabled() && resultSetChecker.fetchedSize() > 0) {
diff --git
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
index a5c896e39fb..d3695c2c479 100644
---
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
+++
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java
@@ -1400,4 +1400,9 @@ public class GridReduceQueryExecutor {
return Collections.singletonList(originalQry);
}
+
+ /** */
+ IgniteH2Indexing h2() {
+ return h2;
+ }
}
diff --git
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReduceIndexIterator.java
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReduceIndexIterator.java
index 5924b7ce826..74ceceb1b31 100644
---
a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReduceIndexIterator.java
+++
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/ReduceIndexIterator.java
@@ -57,6 +57,9 @@ public class ReduceIndexIterator implements
Iterator<List<?>>, AutoCloseable {
/** Whether remote resources were released. */
private boolean released;
+ /** Fetched rows count. */
+ private long fetched;
+
/**
* Constructor.
*
@@ -95,6 +98,8 @@ public class ReduceIndexIterator implements
Iterator<List<?>>, AutoCloseable {
if (res == null)
throw new NoSuchElementException();
+ fetched++;
+
advance();
return res;
@@ -156,6 +161,7 @@ public class ReduceIndexIterator implements
Iterator<List<?>>, AutoCloseable {
if (!released) {
try {
rdcExec.releaseRemoteResources(nodes, run, qryReqId,
distributedJoins);
+ rdcExec.h2().runningQueryManager().onFullyFetched(fetched);
}
finally {
released = true;