Skip to content

Commit 2f73854

Browse files
committed
release 9.4.1
Signed-off-by: neo <1100909+neowu@users.noreply.github.com>
1 parent b71ce98 commit 2f73854

File tree

9 files changed

+41
-31
lines changed

9 files changed

+41
-31
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Change log
22

3-
### 9.4.0 (1/26/26 - 1/29/26)
3+
### 9.4.1 (1/26/26 - 1/29/26)
44

55
* log: for rust version of log-processor/log-collector/log-exporter, refer to https://github.com/neowu/core_rs_workspace
66
* db: removed mysql sslmode property, SSL mode will be detected by driver automatically

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66

77
subprojects {
88
group = "core.framework"
9-
version = "9.4.0"
9+
version = "9.4.1"
1010
repositories {
1111
maven {
1212
url = uri("https://neowu.github.io/maven-repo/")

core-ng/src/main/java/core/framework/internal/db/DatabaseImpl.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import core.framework.internal.db.inspector.MySQLQueryAnalyzer;
1111
import core.framework.internal.db.inspector.PostgreSQLQueryAnalyzer;
1212
import core.framework.internal.db.inspector.QueryInspector;
13-
import core.framework.internal.db.inspector.QueryPlan;
1413
import core.framework.internal.log.ActionLog;
1514
import core.framework.internal.log.LogManager;
1615
import core.framework.internal.resource.Pool;
@@ -35,8 +34,6 @@
3534
import java.util.Properties;
3635
import java.util.UUID;
3736

38-
import static core.framework.log.Markers.errorCode;
39-
4037
/**
4138
* @author neo
4239
*/
@@ -239,7 +236,7 @@ public <T> List<T> select(String sql, Class<T> viewClass, Object... params) {
239236
long elapsed = watch.elapsed();
240237
logger.debug("select, sql={}, params={}, returnedRows={}, elapsed={}", sql, new SQLParams(operation.enumMapper, params), returnedRows, elapsed);
241238
boolean slow = track(elapsed, returnedRows, 0, 1); // check after sql debug log, to make log easier to read
242-
logQueryPlan(sql, params, slow);
239+
inspector.explain(sql, params, slow);
243240
}
244241
}
245242

@@ -258,7 +255,7 @@ public <T> Optional<T> selectOne(String sql, Class<T> viewClass, Object... param
258255
long elapsed = watch.elapsed();
259256
logger.debug("selectOne, sql={}, params={}, returnedRows={}, elapsed={}", sql, new SQLParams(operation.enumMapper, params), returnedRows, elapsed);
260257
boolean slow = track(elapsed, returnedRows, 0, 1);
261-
logQueryPlan(sql, params, slow);
258+
inspector.explain(sql, params, slow);
262259
}
263260
}
264261

@@ -275,7 +272,7 @@ public int execute(String sql, Object... params) {
275272
long elapsed = watch.elapsed();
276273
logger.debug("execute, sql={}, params={}, affectedRows={}, elapsed={}", sql, new SQLParams(operation.enumMapper, params), affectedRows, elapsed);
277274
boolean slow = track(elapsed, 0, affectedRows, 1);
278-
logQueryPlan(sql, params, slow);
275+
inspector.explain(sql, params, slow);
279276
}
280277
}
281278

@@ -300,7 +297,7 @@ public int[] batchExecute(String sql, List<Object[]> params) {
300297
int size = params.size();
301298
logger.debug("batchExecute, sql={}, params={}, size={}, affectedRows={}, elapsed={}", sql, new SQLBatchParams(operation.enumMapper, params), size, affectedRows, elapsed);
302299
boolean slow = track(elapsed, 0, affectedRows, size);
303-
logQueryPlan(sql, params.getFirst(), slow);
300+
inspector.explain(sql, params.getFirst(), slow);
304301
}
305302
}
306303

@@ -329,15 +326,4 @@ boolean track(long elapsed, int readRows, int writeRows, int queries) {
329326
}
330327
return false;
331328
}
332-
333-
private void logQueryPlan(String sql, Object[] params, boolean slow) {
334-
QueryPlan plan = inspector.explain(sql, params, slow);
335-
if (plan != null) {
336-
if (!plan.efficient()) {
337-
logger.warn(errorCode("INEFFICIENT_QUERY"), "inefficient query, plan:\n{}", plan.plan());
338-
} else {
339-
logger.debug("plan:\n{}", plan.plan());
340-
}
341-
}
342-
}
343329
}

core-ng/src/main/java/core/framework/internal/db/inspector/MySQLQueryAnalyzer.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ boolean isEfficient(Explain explain) {
3131
return true; // skip derived table
3232
}
3333
if ("ALL".equals(explain.type) && explain.rowsGreaterThan(2000)) {
34+
return false; // table scan more than 2000 rows is inefficient
35+
}
36+
if (explain.extraContains("Using filesort") && explain.rowsGreaterThan(50_000)) {
3437
return false;
3538
}
36-
if (explain.extra != null && (explain.extra.contains("Using temporary") || explain.extra.contains("Using filesort"))
37-
&& explain.rowsGreaterThan(50_000)) {
39+
// only allow Using temporary for range queries
40+
if (explain.extraContains("Using temporary") && !"range".equals(explain.type) && explain.rowsGreaterThan(50_000)) {
3841
return false;
3942
}
4043
return true;
@@ -78,6 +81,10 @@ static class Explain {
7881
boolean rowsGreaterThan(long threshold) {
7982
return rows != null && rows > threshold;
8083
}
84+
85+
boolean extraContains(String keyword) {
86+
return extra != null && extra.contains(keyword);
87+
}
8188
}
8289

8390
static class ExplainRowMapper implements RowMapper<Explain> {

core-ng/src/main/java/core/framework/internal/db/inspector/QueryAnalyzer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22

33
public interface QueryAnalyzer {
44
QueryPlan explain(String sql, Object[] params);
5+
6+
record QueryPlan(String plan, boolean efficient) {
7+
}
58
}

core-ng/src/main/java/core/framework/internal/db/inspector/QueryInspector.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
package core.framework.internal.db.inspector;
22

3+
import core.framework.internal.db.inspector.QueryAnalyzer.QueryPlan;
34
import core.framework.util.ASCII;
45
import org.jspecify.annotations.Nullable;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
58

69
import java.util.Map;
710
import java.util.concurrent.ConcurrentHashMap;
811

12+
import static core.framework.log.Markers.errorCode;
13+
914
public class QueryInspector {
15+
private final Logger logger = LoggerFactory.getLogger(QueryInspector.class);
1016
private final Map<String, Long> lastCheckTimestamps = new ConcurrentHashMap<>();
1117
private final @Nullable QueryAnalyzer analyzer;
1218

1319
public QueryInspector(@Nullable QueryAnalyzer analyzer) {
1420
this.analyzer = analyzer;
1521
}
1622

17-
@Nullable
18-
public QueryPlan explain(String sql, Object[] params, boolean force) {
19-
if (analyzer == null) return null; // only unit tests don't have analyzer
23+
public void explain(String sql, Object[] params, boolean force) {
24+
if (analyzer == null) return; // only unit tests don't have analyzer
2025

2126
if (!force) {
2227
Long timestamp = lastCheckTimestamps.get(sql);
2328
long now = System.currentTimeMillis();
24-
if (timestamp != null && now - timestamp < 21_600_000) return null; // check every 6 hours
29+
if (timestamp != null && now - timestamp < 21_600_000) return; // check every 6 hours
2530
lastCheckTimestamps.put(sql, now); // to avoid duplicate analysis as much as possible
2631
}
2732

28-
return analyzer.explain(sql, params);
33+
QueryPlan plan = analyzer.explain(sql, params);
34+
if (plan != null) {
35+
if (!plan.efficient()) {
36+
logger.warn(errorCode("INEFFICIENT_QUERY"), "inefficient query, plan:\n{}", plan.plan());
37+
} else if (force) {
38+
logger.debug("plan:\n{}", plan.plan());
39+
}
40+
}
2941
}
3042

3143
public void validateSQL(String sql) {

core-ng/src/main/java/core/framework/internal/db/inspector/QueryPlan.java

Lines changed: 0 additions & 4 deletions
This file was deleted.

core-ng/src/test/java/core/framework/internal/db/inspector/MySQLQueryAnalyzerTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ void isEfficient() {
5858
// SELECT type, COUNT(1) AS count FROM customer WHERE created_time < ? GROUP BY type
5959
explain = parse("1 | SIMPLE | customer | null | ALL | idx_created_time | null | null | null | 203510 | 50.0 | Using where; Using temporary");
6060
assertThat(analyzer.isEfficient(explain)).isFalse();
61+
62+
// date range filtering with group by always using temporary
63+
// SELECT customer_id, SUM(value) AS value FROM orders WHERE updated_time >= ? AND updated_time <= ? GROUP BY customer_id
64+
explain = parse("1 | SIMPLE | orders | null | range | idx_updated_time | idx_updated_time | 7 | null | 112304 | 100 | Using index condition; Using temporary");
65+
assertThat(analyzer.isEfficient(explain)).isTrue();
6166
}
6267

6368
// 1|SIMPLE|daily_individual_stats||index_merge|PRIMARY,idx_customer_id|idx_customer_id,PRIMARY|149,149||1|100|Using intersect(idx_customer_id,PRIMARY); Using where

core-ng/src/test/java/core/framework/internal/db/inspector/QueryInspectorTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package core.framework.internal.db.inspector;
22

3+
import core.framework.internal.db.inspector.QueryAnalyzer.QueryPlan;
34
import org.junit.jupiter.api.BeforeEach;
45
import org.junit.jupiter.api.Test;
56
import org.junit.jupiter.api.extension.ExtendWith;

0 commit comments

Comments
 (0)