This is an automated email from the ASF dual-hosted git repository.
zhaoqingran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new 6c0d5c0db4 [fix]Fix issues such as index failure (#3953)
6c0d5c0db4 is described below
commit 6c0d5c0db415b44df9ec967ad3b70b5686756345
Author: Duansg <[email protected]>
AuthorDate: Sun Jan 18 23:07:42 2026 +0800
[fix]Fix issues such as index failure (#3953)
Co-authored-by: shown <[email protected]>
Co-authored-by: Yang Chen <[email protected]>
Co-authored-by: Logic <[email protected]>
---
.../entity/alerter/AlertDefineMonitorBind.java | 4 +-
.../entity/manager/CollectorMonitorBind.java | 4 +-
.../hertzbeat/common/entity/manager/Monitor.java | 40 +-
.../common/entity/manager/MonitorBind.java | 4 +-
.../hertzbeat/common/entity/manager/Param.java | 9 +-
.../manager/StatusPageIncidentComponentBind.java | 5 +-
.../hertzbeat/common/entity/push/PushMetrics.java | 4 +-
.../hertzbeat/common/entity/warehouse/History.java | 10 +-
.../hertzbeat/manager/pojo/dto/PluginParam.java | 11 +-
.../db/migration/h2/V181__update_indexes.sql | 534 +++++++++++++++++++++
.../db/migration/mysql/V181__update_indexes.sql | 450 +++++++++++++++++
.../migration/postgresql/V181__update_indexes.sql | 247 ++++++++++
.../startup/EntityIndexIntegrationTest.java | 185 +++++++
13 files changed, 1466 insertions(+), 41 deletions(-)
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/alerter/AlertDefineMonitorBind.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/alerter/AlertDefineMonitorBind.java
index 6ba5d6ee95..f40241c393 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/alerter/AlertDefineMonitorBind.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/alerter/AlertDefineMonitorBind.java
@@ -48,8 +48,8 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@Entity
@Table(name = "hzb_alert_define_monitor_bind", indexes = {
- @Index(name = "index_alert_define_monitor", columnList =
"alertDefineId"),
- @Index(name = "index_alert_define_monitor", columnList = "monitor_id")
+ @Index(name = "idx_alert_define_id", columnList = "alert_define_id"),
+ @Index(name = "idx_monitor_id", columnList = "monitor_id")
})
@Data
@Builder
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/CollectorMonitorBind.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/CollectorMonitorBind.java
index f961adb5d6..bad92c4a80 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/CollectorMonitorBind.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/CollectorMonitorBind.java
@@ -42,8 +42,8 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@Entity
@Table(name = "hzb_collector_monitor_bind", indexes = {
- @Index(name = "index_collector_monitor", columnList = "collector"),
- @Index(name = "index_collector_monitor", columnList = "monitor_id")
+ @Index(name = "idx_collector_monitor_collector", columnList =
"collector"),
+ @Index(name = "idx_collector_monitor_monitor_id", columnList =
"monitor_id")
})
@Data
@Builder
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java
index 585a7018cf..95ff7a05bd 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Monitor.java
@@ -51,9 +51,9 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@Entity
@Table(name = "hzb_monitor", indexes = {
- @Index(name = "monitor_query_index", columnList = "app"),
- @Index(name = "monitor_query_index", columnList = "instance"),
- @Index(name = "monitor_query_index", columnList = "name")
+ @Index(name = "idx_hzb_monitor_app", columnList = "app"),
+ @Index(name = "idx_hzb_monitor_instance", columnList = "instance"),
+ @Index(name = "idx_hzb_monitor_name", columnList = "name")
})
@Data
@Builder
@@ -62,51 +62,51 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
@Schema(description = "Monitor Entity")
@EntityListeners(AuditingEntityListener.class)
public class Monitor {
-
+
@Id
@Schema(title = "Monitor task ID", example = "87584674384", accessMode =
READ_ONLY)
private Long id;
-
+
@Schema(title = "Collect task ID", example = "43243543543", accessMode =
READ_ONLY)
private Long jobId;
-
+
@Schema(title = "task name", example = "Api-TanCloud.cn", accessMode =
READ_WRITE)
@Size(max = 100)
private String name;
-
+
@Schema(title = "Type of monitoring", example = "TanCloud", accessMode =
READ_WRITE)
@Size(max = 100)
private String app;
-
+
@Schema(title = "Scrape type: static | http_sd | dns_sd | zookeeper_sd",
example = "static", accessMode = READ_WRITE)
@Size(max = 100)
private String scrape;
-
+
@Schema(title = "the monitor target: ip/domain+port or ip/domain", example
= "192.167.25.11:8081", accessMode = READ_WRITE)
@Size(max = 100)
@HostValid
private String instance;
-
+
@Schema(title = "Monitoring of the acquisition interval time in seconds",
example = "600", accessMode = READ_WRITE)
@Min(10)
private Integer intervals;
-
+
@Schema(title = "Schedule type: interval | cron", example = "interval",
accessMode = READ_WRITE)
@Size(max = 20)
private String scheduleType;
-
+
@Schema(title = "Cron expression when scheduleType is cron", example =
"0/5 * * * * ?", accessMode = READ_WRITE)
@Size(max = 100)
private String cronExpression;
-
+
@Schema(title = "Task status 0: Paused, 1: Up, 2: Down", accessMode =
READ_WRITE)
@Min(0)
@Max(4)
private byte status;
-
+
@Schema(title = "Task type 0: Normal, 1: push auto create, 2: discovery
auto create")
private byte type;
-
+
@Schema(title = "task label", example = "{env:test}", accessMode =
READ_WRITE)
@Convert(converter = JsonMapAttributeConverter.class)
@Column(length = 4096)
@@ -116,23 +116,23 @@ public class Monitor {
@Convert(converter = JsonMapAttributeConverter.class)
@Column(length = 4096)
private Map<String, String> annotations;
-
+
@Schema(title = "Monitor note description", example = "Availability
monitoring of the SAAS website TanCloud", accessMode = READ_WRITE)
@Size(max = 255)
private String description;
-
+
@Schema(title = "The creator of this record", example = "tom", accessMode
= READ_ONLY)
@CreatedBy
private String creator;
-
+
@Schema(title = "The modifier of this record", example = "tom", accessMode
= READ_ONLY)
@LastModifiedBy
private String modifier;
-
+
@Schema(title = "Record create time", example =
"2024-07-02T20:09:34.903217", accessMode = READ_ONLY)
@CreatedDate
private LocalDateTime gmtCreate;
-
+
@Schema(title = "Record modify time", example =
"2024-07-02T20:09:34.903217", accessMode = READ_ONLY)
@LastModifiedDate
private LocalDateTime gmtUpdate;
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/MonitorBind.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/MonitorBind.java
index 9161447696..885c99b567 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/MonitorBind.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/MonitorBind.java
@@ -42,7 +42,7 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@Entity
@Table(name = "hzb_monitor_bind", indexes = {
- @Index(name = "index_monitor_bind", columnList = "bizId"),
+ @Index(name = "index_monitor_bind", columnList = "biz_id"),
@Index(name = "index_monitor_bin", columnList = "monitor_id")
})
@Data
@@ -59,7 +59,7 @@ public class MonitorBind {
@Schema(title = "key string: ip:port")
private String keyStr;
-
+
@Schema(title = "connect bind id", example = "87432674384")
private Long bizId;
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Param.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Param.java
index 220092ad63..7829ca831c 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Param.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/Param.java
@@ -46,8 +46,11 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
* Monitor parameter values
*/
@Entity
-@Table(name = "hzb_param", indexes = { @Index(columnList = "monitorId") },
- uniqueConstraints = @UniqueConstraint(columnNames = {"monitorId",
"field"}))
+@Table(
+ name = "hzb_param",
+ indexes = {@Index(name = "idx_hzb_param_monitor_id", columnList =
"monitor_id")},
+ uniqueConstraints = {@UniqueConstraint(name =
"uk_hzb_param_monitor_field", columnNames = {"monitor_id", "field"})}
+)
@Data
@Builder
@AllArgsConstructor
@@ -68,6 +71,7 @@ public class Param {
* Monitor ID
*/
@Schema(title = "Monitor task ID", example = "875846754543", accessMode =
READ_WRITE)
+ @Column(name = "monitor_id")
private Long monitorId;
/**
@@ -75,6 +79,7 @@ public class Param {
*/
@Schema(title = "Parameter identifier field", example = "port", accessMode
= READ_WRITE)
@Size(max = 100)
+ @Column(name = "field")
@NotBlank(message = "field can not null")
private String field;
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageIncidentComponentBind.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageIncidentComponentBind.java
index f1f18074a7..a7941df0b5 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageIncidentComponentBind.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageIncidentComponentBind.java
@@ -41,7 +41,6 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
@Entity
@Table(name = "hzb_status_page_incident_component_bind", indexes = {
@Index(name = "index_incident_component", columnList = "incident_id"),
- @Index(name = "index_incident_component", columnList = "component_id")
})
@Data
@Builder
@@ -59,7 +58,7 @@ public class StatusPageIncidentComponentBind {
@Schema(title = "Incident ID", example = "87432674384")
@Column(name = "incident_id")
private Long incidentId;
-
+
@Schema(title = "Component ID", example = "87432674336")
@Column(name = "component_id")
private Long componentId;
@@ -71,5 +70,5 @@ public class StatusPageIncidentComponentBind {
@Schema(title = "Record modify time", example = "1612198444000")
@LastModifiedDate
private LocalDateTime gmtUpdate;
-
+
}
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/push/PushMetrics.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/push/PushMetrics.java
index 1f72f83dc8..5c58cfb0ba 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/push/PushMetrics.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/push/PushMetrics.java
@@ -35,8 +35,8 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@Entity
@Table(name = "hzb_push_metrics", indexes = {
- @Index(name = "push_query_index", columnList = "monitorId"),
- @Index(name = "push_query_index", columnList = "time")
+ @Index(name = "idx_push_metrics_monitor_id", columnList =
"monitor_id"),
+ @Index(name = "idx_push_metrics_time", columnList = "time")
})
@Data
@Builder
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/warehouse/History.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/warehouse/History.java
index 24729b16e8..6e29d33cbd 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/warehouse/History.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/warehouse/History.java
@@ -37,10 +37,10 @@ import lombok.NoArgsConstructor;
*/
@Entity
@Table(name = "hzb_history", indexes = {
- @Index(name = "history_query_index", columnList = "instance"),
- @Index(name = "history_query_index", columnList = "app"),
- @Index(name = "history_query_index", columnList = "metrics"),
- @Index(name = "history_query_index", columnList = "metric")
+ @Index(name = "idx_hzb_history_instance", columnList = "instance"),
+ @Index(name = "idx_hzb_history_app", columnList = "app"),
+ @Index(name = "idx_hzb_history_metrics", columnList = "metrics"),
+ @Index(name = "idx_hzb_history_metric", columnList = "metric")
})
@Data
@Builder
@@ -65,7 +65,7 @@ public class History {
@Schema(title = "Monitoring Metric usage speed count")
private String metric;
-
+
@Column(length = 5000)
private String metricLabels;
diff --git
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java
index b92948f2b1..faae0fefa6 100644
---
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java
+++
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java
@@ -45,8 +45,11 @@ import
org.springframework.data.jpa.domain.support.AuditingEntityListener;
* PluginParam
*/
@Entity
-@Table(name = "hzb_plugin_param", indexes = { @Index(columnList =
"pluginMetadataId") },
- uniqueConstraints = @UniqueConstraint(columnNames =
{"pluginMetadataId", "field"}))
+@Table(
+ name = "hzb_plugin_param",
+ indexes = {@Index(name = "idx_hzb_plugin_param_plugin_metadata_id",
columnList = "plugin_metadata_id")},
+ uniqueConstraints = @UniqueConstraint(name =
"uk_hzb_plugin_param_metadata_field", columnNames = {"plugin_metadata_id",
"field"})
+)
@Data
@Builder
@AllArgsConstructor
@@ -65,8 +68,9 @@ public class PluginParam {
/**
* Monitor ID
*/
- @Schema(title = "Plugin task ID", example = "875846754543", accessMode =
READ_WRITE)
@NotNull
+ @Column(name = "plugin_metadata_id")
+ @Schema(title = "Plugin task ID", example = "875846754543", accessMode =
READ_WRITE)
private Long pluginMetadataId;
/**
@@ -75,6 +79,7 @@ public class PluginParam {
@Schema(title = "Parameter identifier field", example = "port", accessMode
= READ_WRITE)
@Size(max = 100)
@NotNull
+ @Column(name = "field")
private String field;
/**
diff --git
a/hertzbeat-startup/src/main/resources/db/migration/h2/V181__update_indexes.sql
b/hertzbeat-startup/src/main/resources/db/migration/h2/V181__update_indexes.sql
new file mode 100644
index 0000000000..dcf84b2794
--- /dev/null
+++
b/hertzbeat-startup/src/main/resources/db/migration/h2/V181__update_indexes.sql
@@ -0,0 +1,534 @@
+-- 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.
+
+-- Ensure every SQL can rerun without error
+-- This migration updates indexes to match the entity annotations
+
+-- ========================================
+-- hzb_alert_define_monitor_bind table
+-- ========================================
+CREATE ALIAS UPDATE_ALERT_DEFINE_MONITOR_BIND_INDEXES AS $$
+void updateAlertDefineMonitorBindIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_ALERT_DEFINE_MONITOR_BIND", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_ALERT_DEFINE_MONITOR_BIND", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if
("INDEX_ALERT_DEFINE_MONITOR".equalsIgnoreCase(indexName)) {
+ stmt.execute("DROP INDEX INDEX_ALERT_DEFINE_MONITOR");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new indexes if not exist
+ boolean alertDefineIdIndexExists = false;
+ boolean monitorIdIndexExists = false;
+
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_ALERT_DEFINE_MONITOR_BIND", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("IDX_ALERT_DEFINE_ID".equalsIgnoreCase(indexName)) {
+ alertDefineIdIndexExists = true;
+ }
+ if ("IDX_MONITOR_ID".equalsIgnoreCase(indexName)) {
+ monitorIdIndexExists = true;
+ }
+ }
+ }
+
+ if (!alertDefineIdIndexExists) {
+ stmt.execute("CREATE INDEX IDX_ALERT_DEFINE_ID ON
HZB_ALERT_DEFINE_MONITOR_BIND(ALERT_DEFINE_ID)");
+ }
+
+ if (!monitorIdIndexExists) {
+ stmt.execute("CREATE INDEX IDX_MONITOR_ID ON
HZB_ALERT_DEFINE_MONITOR_BIND(MONITOR_ID)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_ALERT_DEFINE_MONITOR_BIND_INDEXES();
+DROP ALIAS UPDATE_ALERT_DEFINE_MONITOR_BIND_INDEXES;
+
+-- ========================================
+-- hzb_collector_monitor_bind table
+-- ========================================
+CREATE ALIAS UPDATE_COLLECTOR_MONITOR_BIND_INDEXES AS $$
+void updateCollectorMonitorBindIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_COLLECTOR_MONITOR_BIND", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_COLLECTOR_MONITOR_BIND", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("INDEX_COLLECTOR_MONITOR".equalsIgnoreCase(indexName))
{
+ stmt.execute("DROP INDEX INDEX_COLLECTOR_MONITOR");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new indexes if not exist
+ boolean collectorIndexExists = false;
+ boolean monitorIdIndexExists = false;
+
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_COLLECTOR_MONITOR_BIND", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if
("IDX_COLLECTOR_MONITOR_COLLECTOR".equalsIgnoreCase(indexName)) {
+ collectorIndexExists = true;
+ }
+ if
("IDX_COLLECTOR_MONITOR_MONITOR_ID".equalsIgnoreCase(indexName)) {
+ monitorIdIndexExists = true;
+ }
+ }
+ }
+
+ if (!collectorIndexExists) {
+ stmt.execute("CREATE INDEX IDX_COLLECTOR_MONITOR_COLLECTOR ON
HZB_COLLECTOR_MONITOR_BIND(COLLECTOR)");
+ }
+
+ if (!monitorIdIndexExists) {
+ stmt.execute("CREATE INDEX IDX_COLLECTOR_MONITOR_MONITOR_ID ON
HZB_COLLECTOR_MONITOR_BIND(MONITOR_ID)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_COLLECTOR_MONITOR_BIND_INDEXES();
+DROP ALIAS UPDATE_COLLECTOR_MONITOR_BIND_INDEXES;
+
+-- ========================================
+-- hzb_monitor table
+-- ========================================
+CREATE ALIAS UPDATE_MONITOR_INDEXES AS $$
+void updateMonitorIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_MONITOR", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_MONITOR", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("MONITOR_QUERY_INDEX".equalsIgnoreCase(indexName)) {
+ stmt.execute("DROP INDEX MONITOR_QUERY_INDEX");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new indexes if not exist
+ boolean appIndexExists = false;
+ boolean instanceIndexExists = false;
+ boolean nameIndexExists = false;
+
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_MONITOR", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("IDX_HZB_MONITOR_APP".equalsIgnoreCase(indexName)) {
+ appIndexExists = true;
+ }
+ if
("IDX_HZB_MONITOR_INSTANCE".equalsIgnoreCase(indexName)) {
+ instanceIndexExists = true;
+ }
+ if ("IDX_HZB_MONITOR_NAME".equalsIgnoreCase(indexName)) {
+ nameIndexExists = true;
+ }
+ }
+ }
+
+ if (!appIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_MONITOR_APP ON
HZB_MONITOR(APP)");
+ }
+
+ if (!instanceIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_MONITOR_INSTANCE ON
HZB_MONITOR(INSTANCE)");
+ }
+
+ if (!nameIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_MONITOR_NAME ON
HZB_MONITOR(NAME)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_MONITOR_INDEXES();
+DROP ALIAS UPDATE_MONITOR_INDEXES;
+
+-- ========================================
+-- hzb_monitor_bind table
+-- ========================================
+CREATE ALIAS UPDATE_MONITOR_BIND_INDEXES AS $$
+void updateMonitorBindIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_MONITOR_BIND", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Create new index if not exist
+ boolean bindIndexExists = false;
+
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_MONITOR_BIND", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("INDEX_MONITOR_BIND".equalsIgnoreCase(indexName)) {
+ bindIndexExists = true;
+ }
+ }
+ }
+
+ if (!bindIndexExists) {
+ stmt.execute("CREATE INDEX INDEX_MONITOR_BIND ON
HZB_MONITOR_BIND(BIZ_ID)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_MONITOR_BIND_INDEXES();
+DROP ALIAS UPDATE_MONITOR_BIND_INDEXES;
+
+-- ========================================
+-- hzb_status_page_incident_component_bind table
+-- Special handling: component_id might have auto-created index from FK
+-- ========================================
+CREATE ALIAS UPDATE_STATUS_PAGE_INCIDENT_COMPONENT_BIND_INDEXES AS $$
+void updateStatusPageIncidentComponentBindIndexes(java.sql.Connection conn)
throws java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_STATUS_PAGE_INCIDENT_COMPONENT_BIND", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Check if component_id column already has any index
+ boolean hasComponentIdIndex = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_STATUS_PAGE_INCIDENT_COMPONENT_BIND", false, false)) {
+ while (rs.next()) {
+ String columnName = rs.getString("COLUMN_NAME");
+ if (columnName != null &&
"COMPONENT_ID".equalsIgnoreCase(columnName)) {
+ hasComponentIdIndex = true;
+ break;
+ }
+ }
+ }
+
+ // Create index on component_id only if no index exists on this
column
+ if (!hasComponentIdIndex) {
+ stmt.execute("CREATE INDEX IDX_INCIDENT_COMPONENT_COMPONENT_ID
ON HZB_STATUS_PAGE_INCIDENT_COMPONENT_BIND(COMPONENT_ID)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_STATUS_PAGE_INCIDENT_COMPONENT_BIND_INDEXES();
+DROP ALIAS UPDATE_STATUS_PAGE_INCIDENT_COMPONENT_BIND_INDEXES;
+
+-- ========================================
+-- hzb_push_metrics table
+-- ========================================
+CREATE ALIAS UPDATE_PUSH_METRICS_INDEXES AS $$
+void updatePushMetricsIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_PUSH_METRICS", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PUSH_METRICS", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("PUSH_QUERY_INDEX".equalsIgnoreCase(indexName)) {
+ stmt.execute("DROP INDEX PUSH_QUERY_INDEX");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new indexes if not exist
+ boolean monitorIdIndexExists = false;
+ boolean timeIndexExists = false;
+
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PUSH_METRICS", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if
("IDX_PUSH_METRICS_MONITOR_ID".equalsIgnoreCase(indexName)) {
+ monitorIdIndexExists = true;
+ }
+ if ("IDX_PUSH_METRICS_TIME".equalsIgnoreCase(indexName)) {
+ timeIndexExists = true;
+ }
+ }
+ }
+
+ if (!monitorIdIndexExists) {
+ stmt.execute("CREATE INDEX IDX_PUSH_METRICS_MONITOR_ID ON
HZB_PUSH_METRICS(MONITOR_ID)");
+ }
+
+ if (!timeIndexExists) {
+ stmt.execute("CREATE INDEX IDX_PUSH_METRICS_TIME ON
HZB_PUSH_METRICS(TIME)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_PUSH_METRICS_INDEXES();
+DROP ALIAS UPDATE_PUSH_METRICS_INDEXES;
+
+-- ========================================
+-- hzb_history table
+-- ========================================
+CREATE ALIAS UPDATE_HISTORY_INDEXES AS $$
+void updateHistoryIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_HISTORY", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_HISTORY", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if ("HISTORY_QUERY_INDEX".equalsIgnoreCase(indexName)) {
+ stmt.execute("DROP INDEX HISTORY_QUERY_INDEX");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new indexes if not exist
+ boolean instanceIndexExists = false;
+ boolean appIndexExists = false;
+ boolean metricsIndexExists = false;
+ boolean metricIndexExists = false;
+
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_HISTORY", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if
("IDX_HZB_HISTORY_INSTANCE".equalsIgnoreCase(indexName)) {
+ instanceIndexExists = true;
+ }
+ if ("IDX_HZB_HISTORY_APP".equalsIgnoreCase(indexName)) {
+ appIndexExists = true;
+ }
+ if ("IDX_HZB_HISTORY_METRICS".equalsIgnoreCase(indexName))
{
+ metricsIndexExists = true;
+ }
+ if ("IDX_HZB_HISTORY_METRIC".equalsIgnoreCase(indexName)) {
+ metricIndexExists = true;
+ }
+ }
+ }
+
+ if (!instanceIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_HISTORY_INSTANCE ON
HZB_HISTORY(INSTANCE)");
+ }
+
+ if (!appIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_HISTORY_APP ON
HZB_HISTORY(APP)");
+ }
+
+ if (!metricsIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_HISTORY_METRICS ON
HZB_HISTORY(METRICS)");
+ }
+
+ if (!metricIndexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_HISTORY_METRIC ON
HZB_HISTORY(METRIC)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_HISTORY_INDEXES();
+DROP ALIAS UPDATE_HISTORY_INDEXES;
+
+-- ========================================
+-- hzb_param table
+-- ========================================
+CREATE ALIAS UPDATE_PARAM_TABLE_INDEXES AS $$
+void updateParamTableIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_PARAM", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PARAM", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if
("IDX_HZB_PARAM_MONITOR_ID".equalsIgnoreCase(indexName)) {
+ stmt.execute("DROP INDEX IDX_HZB_PARAM_MONITOR_ID");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new index if not exist
+ boolean indexExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PARAM", false, false)) {
+ while (rs.next()) {
+ if
("IDX_HZB_PARAM_MONITOR_ID".equalsIgnoreCase(rs.getString("INDEX_NAME"))) {
+ indexExists = true;
+ break;
+ }
+ }
+ }
+ if (!indexExists) {
+ stmt.execute("CREATE INDEX IDX_HZB_PARAM_MONITOR_ID ON
HZB_PARAM(MONITOR_ID)");
+ }
+
+ // Drop old unique constraint if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PARAM", true, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if (indexName != null &&
indexName.equalsIgnoreCase("UK_HZB_PARAM_MONITOR_FIELD")) {
+ stmt.execute("DROP INDEX UK_HZB_PARAM_MONITOR_FIELD");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Constraint may not exist, continue
+ }
+
+ // Create new unique constraint if not exist
+ boolean constraintExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PARAM", true, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if (indexName != null &&
indexName.equalsIgnoreCase("UK_HZB_PARAM_MONITOR_FIELD")) {
+ constraintExists = true;
+ break;
+ }
+ }
+ }
+ if (!constraintExists) {
+ stmt.execute("CREATE UNIQUE INDEX UK_HZB_PARAM_MONITOR_FIELD
ON HZB_PARAM(MONITOR_ID, FIELD)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_PARAM_TABLE_INDEXES();
+DROP ALIAS UPDATE_PARAM_TABLE_INDEXES;
+
+-- ========================================
+-- hzb_plugin_param table
+-- ========================================
+CREATE ALIAS UPDATE_PLUGIN_PARAM_TABLE_INDEXES AS $$
+void updatePluginParamTableIndexes(java.sql.Connection conn) throws
java.sql.SQLException {
+ boolean tableExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getTables(null, null,
"HZB_PLUGIN_PARAM", null)) {
+ if (rs.next()) tableExists = true;
+ }
+
+ if (tableExists) {
+ try (java.sql.Statement stmt = conn.createStatement()) {
+ // Drop old index if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PLUGIN_PARAM", false, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if
("IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID".equalsIgnoreCase(indexName)) {
+ stmt.execute("DROP INDEX
IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Index may not exist, continue
+ }
+
+ // Create new index if not exist
+ boolean indexExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PLUGIN_PARAM", false, false)) {
+ while (rs.next()) {
+ if
("IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID".equalsIgnoreCase(rs.getString("INDEX_NAME")))
{
+ indexExists = true;
+ break;
+ }
+ }
+ }
+ if (!indexExists) {
+ stmt.execute("CREATE INDEX
IDX_HZB_PLUGIN_PARAM_PLUGIN_METADATA_ID ON
HZB_PLUGIN_PARAM(PLUGIN_METADATA_ID)");
+ }
+
+ // Drop old unique constraint if exists
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PLUGIN_PARAM", true, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if (indexName != null &&
indexName.equalsIgnoreCase("UK_HZB_PLUGIN_PARAM_METADATA_FIELD")) {
+ stmt.execute("DROP INDEX
UK_HZB_PLUGIN_PARAM_METADATA_FIELD");
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // Constraint may not exist, continue
+ }
+
+ // Create new unique constraint if not exist
+ boolean constraintExists = false;
+ try (java.sql.ResultSet rs = conn.getMetaData().getIndexInfo(null,
null, "HZB_PLUGIN_PARAM", true, false)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if (indexName != null &&
indexName.equalsIgnoreCase("UK_HZB_PLUGIN_PARAM_METADATA_FIELD")) {
+ constraintExists = true;
+ break;
+ }
+ }
+ }
+ if (!constraintExists) {
+ stmt.execute("CREATE UNIQUE INDEX
UK_HZB_PLUGIN_PARAM_METADATA_FIELD ON HZB_PLUGIN_PARAM(PLUGIN_METADATA_ID,
FIELD)");
+ }
+ }
+ }
+}
+$$;
+CALL UPDATE_PLUGIN_PARAM_TABLE_INDEXES();
+DROP ALIAS UPDATE_PLUGIN_PARAM_TABLE_INDEXES;
diff --git
a/hertzbeat-startup/src/main/resources/db/migration/mysql/V181__update_indexes.sql
b/hertzbeat-startup/src/main/resources/db/migration/mysql/V181__update_indexes.sql
new file mode 100644
index 0000000000..88442f98c6
--- /dev/null
+++
b/hertzbeat-startup/src/main/resources/db/migration/mysql/V181__update_indexes.sql
@@ -0,0 +1,450 @@
+-- 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.
+
+-- Ensure every SQL can rerun without error
+-- This migration updates indexes to match the entity annotations
+
+-- ========================================
+-- hzb_alert_define_monitor_bind table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateAlertDefineMonitorBindIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME =
'hzb_alert_define_monitor_bind';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_alert_define_monitor_bind'
+ AND INDEX_NAME = 'index_alert_define_monitor') THEN
+ SET @drop_sql = 'DROP INDEX index_alert_define_monitor ON
hzb_alert_define_monitor_bind';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_alert_define_monitor_bind'
+ AND INDEX_NAME = 'idx_alert_define_id') THEN
+ CREATE INDEX idx_alert_define_id ON
hzb_alert_define_monitor_bind(alert_define_id);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_alert_define_monitor_bind'
+ AND INDEX_NAME = 'idx_monitor_id') THEN
+ CREATE INDEX idx_monitor_id ON
hzb_alert_define_monitor_bind(monitor_id);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateAlertDefineMonitorBindIndexes();
+DROP PROCEDURE IF EXISTS UpdateAlertDefineMonitorBindIndexes;
+
+-- ========================================
+-- hzb_collector_monitor_bind table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateCollectorMonitorBindIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME =
'hzb_collector_monitor_bind';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_collector_monitor_bind'
+ AND INDEX_NAME = 'index_collector_monitor') THEN
+ SET @drop_sql = 'DROP INDEX index_collector_monitor ON
hzb_collector_monitor_bind';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_collector_monitor_bind'
+ AND INDEX_NAME = 'idx_collector_monitor_collector') THEN
+ CREATE INDEX idx_collector_monitor_collector ON
hzb_collector_monitor_bind(collector);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_collector_monitor_bind'
+ AND INDEX_NAME = 'idx_collector_monitor_monitor_id') THEN
+ CREATE INDEX idx_collector_monitor_monitor_id ON
hzb_collector_monitor_bind(monitor_id);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateCollectorMonitorBindIndexes();
+DROP PROCEDURE IF EXISTS UpdateCollectorMonitorBindIndexes;
+
+-- ========================================
+-- hzb_monitor table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateMonitorIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_monitor';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_monitor'
+ AND INDEX_NAME = 'monitor_query_index') THEN
+ SET @drop_sql = 'DROP INDEX monitor_query_index ON hzb_monitor';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_monitor'
+ AND INDEX_NAME = 'idx_hzb_monitor_app') THEN
+ CREATE INDEX idx_hzb_monitor_app ON hzb_monitor(app);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_monitor'
+ AND INDEX_NAME = 'idx_hzb_monitor_instance') THEN
+ CREATE INDEX idx_hzb_monitor_instance ON hzb_monitor(instance);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_monitor'
+ AND INDEX_NAME = 'idx_hzb_monitor_name') THEN
+ CREATE INDEX idx_hzb_monitor_name ON hzb_monitor(name);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateMonitorIndexes();
+DROP PROCEDURE IF EXISTS UpdateMonitorIndexes;
+
+-- ========================================
+-- hzb_monitor_bind table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateMonitorBindIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_monitor_bind';
+
+ IF table_exists = 1 THEN
+ -- Create new index if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_monitor_bind'
+ AND INDEX_NAME = 'index_monitor_bind') THEN
+ CREATE INDEX index_monitor_bind ON hzb_monitor_bind(biz_id);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateMonitorBindIndexes();
+DROP PROCEDURE IF EXISTS UpdateMonitorBindIndexes;
+
+-- ========================================
+-- hzb_status_page_incident_component_bind table
+-- Special handling: component_id might have auto-created index from FK
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateStatusPageIncidentComponentBindIndexes()
+BEGIN
+ DECLARE table_exists INT;
+ DECLARE component_id_has_index INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME =
'hzb_status_page_incident_component_bind';
+
+ IF table_exists = 1 THEN
+ -- Check if component_id column already has any index (including
auto-created by FK)
+ SELECT COUNT(*) INTO component_id_has_index
+ FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_status_page_incident_component_bind'
+ AND COLUMN_NAME = 'component_id'
+ AND INDEX_NAME != 'PRIMARY';
+
+ -- Create index on component_id only if no index exists on this column
+ IF component_id_has_index = 0 THEN
+ CREATE INDEX idx_incident_component_component_id ON
hzb_status_page_incident_component_bind(component_id);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateStatusPageIncidentComponentBindIndexes();
+DROP PROCEDURE IF EXISTS UpdateStatusPageIncidentComponentBindIndexes;
+
+-- ========================================
+-- hzb_push_metrics table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdatePushMetricsIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_push_metrics';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_push_metrics'
+ AND INDEX_NAME = 'push_query_index') THEN
+ SET @drop_sql = 'DROP INDEX push_query_index ON hzb_push_metrics';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_push_metrics'
+ AND INDEX_NAME = 'idx_push_metrics_monitor_id') THEN
+ CREATE INDEX idx_push_metrics_monitor_id ON
hzb_push_metrics(monitor_id);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_push_metrics'
+ AND INDEX_NAME = 'idx_push_metrics_time') THEN
+ CREATE INDEX idx_push_metrics_time ON hzb_push_metrics(time);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdatePushMetricsIndexes();
+DROP PROCEDURE IF EXISTS UpdatePushMetricsIndexes;
+
+-- ========================================
+-- hzb_history table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateHistoryIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_history';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_history'
+ AND INDEX_NAME = 'history_query_index') THEN
+ SET @drop_sql = 'DROP INDEX history_query_index ON hzb_history';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_history'
+ AND INDEX_NAME = 'idx_hzb_history_instance') THEN
+ CREATE INDEX idx_hzb_history_instance ON hzb_history(instance);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_history'
+ AND INDEX_NAME = 'idx_hzb_history_app') THEN
+ CREATE INDEX idx_hzb_history_app ON hzb_history(app);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_history'
+ AND INDEX_NAME = 'idx_hzb_history_metrics') THEN
+ CREATE INDEX idx_hzb_history_metrics ON hzb_history(metrics);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_history'
+ AND INDEX_NAME = 'idx_hzb_history_metric') THEN
+ CREATE INDEX idx_hzb_history_metric ON hzb_history(metric);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateHistoryIndexes();
+DROP PROCEDURE IF EXISTS UpdateHistoryIndexes;
+
+-- ========================================
+-- hzb_param table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdateParamTableIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_param';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_param'
+ AND INDEX_NAME = 'idx_hzb_param_monitor_id') THEN
+ SET @drop_sql = 'DROP INDEX idx_hzb_param_monitor_id ON hzb_param';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new index if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_param'
+ AND INDEX_NAME = 'idx_hzb_param_monitor_id') THEN
+ CREATE INDEX idx_hzb_param_monitor_id ON hzb_param(monitor_id);
+ END IF;
+
+ -- Drop old unique constraint if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_param'
+ AND CONSTRAINT_TYPE = 'UNIQUE'
+ AND CONSTRAINT_NAME = 'uk_hzb_param_monitor_field') THEN
+ SET @drop_sql = 'ALTER TABLE hzb_param DROP INDEX
uk_hzb_param_monitor_field';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new unique constraint if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_param'
+ AND CONSTRAINT_TYPE = 'UNIQUE'
+ AND CONSTRAINT_NAME = 'uk_hzb_param_monitor_field') THEN
+ ALTER TABLE hzb_param
+ ADD CONSTRAINT uk_hzb_param_monitor_field
+ UNIQUE (monitor_id, field);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdateParamTableIndexes();
+DROP PROCEDURE IF EXISTS UpdateParamTableIndexes;
+
+-- ========================================
+-- hzb_plugin_param table
+-- ========================================
+DELIMITER //
+CREATE PROCEDURE UpdatePluginParamTableIndexes()
+BEGIN
+ DECLARE table_exists INT;
+
+ SELECT COUNT(*) INTO table_exists
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'hzb_plugin_param';
+
+ IF table_exists = 1 THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_plugin_param'
+ AND INDEX_NAME = 'idx_hzb_plugin_param_plugin_metadata_id')
THEN
+ SET @drop_sql = 'DROP INDEX
idx_hzb_plugin_param_plugin_metadata_id ON hzb_plugin_param';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new index if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_plugin_param'
+ AND INDEX_NAME =
'idx_hzb_plugin_param_plugin_metadata_id') THEN
+ CREATE INDEX idx_hzb_plugin_param_plugin_metadata_id ON
hzb_plugin_param(plugin_metadata_id);
+ END IF;
+
+ -- Drop old unique constraint if exists
+ IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_plugin_param'
+ AND CONSTRAINT_TYPE = 'UNIQUE'
+ AND CONSTRAINT_NAME = 'uk_hzb_plugin_param_metadata_field')
THEN
+ SET @drop_sql = 'ALTER TABLE hzb_plugin_param DROP INDEX
uk_hzb_plugin_param_metadata_field';
+ PREPARE stmt FROM @drop_sql;
+ EXECUTE stmt;
+ DEALLOCATE PREPARE stmt;
+ END IF;
+
+ -- Create new unique constraint if not exist
+ IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'hzb_plugin_param'
+ AND CONSTRAINT_TYPE = 'UNIQUE'
+ AND CONSTRAINT_NAME =
'uk_hzb_plugin_param_metadata_field') THEN
+ ALTER TABLE hzb_plugin_param
+ ADD CONSTRAINT uk_hzb_plugin_param_metadata_field
+ UNIQUE (plugin_metadata_id, field);
+ END IF;
+ END IF;
+END //
+DELIMITER ;
+
+CALL UpdatePluginParamTableIndexes();
+DROP PROCEDURE IF EXISTS UpdatePluginParamTableIndexes;
+
+COMMIT;
diff --git
a/hertzbeat-startup/src/main/resources/db/migration/postgresql/V181__update_indexes.sql
b/hertzbeat-startup/src/main/resources/db/migration/postgresql/V181__update_indexes.sql
new file mode 100644
index 0000000000..da88582de3
--- /dev/null
+++
b/hertzbeat-startup/src/main/resources/db/migration/postgresql/V181__update_indexes.sql
@@ -0,0 +1,247 @@
+-- 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.
+
+-- Ensure every SQL can rerun without error
+-- This migration updates indexes to match the entity annotations
+
+-- ========================================
+-- hzb_alert_define_monitor_bind table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_alert_define_monitor_bind') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_alert_define_monitor_bind' AND indexname = 'index_alert_define_monitor')
THEN
+ DROP INDEX IF EXISTS index_alert_define_monitor;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_alert_define_monitor_bind' AND indexname = 'idx_alert_define_id') THEN
+ CREATE INDEX idx_alert_define_id ON
hzb_alert_define_monitor_bind(alert_define_id);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_alert_define_monitor_bind' AND indexname = 'idx_monitor_id') THEN
+ CREATE INDEX idx_monitor_id ON
hzb_alert_define_monitor_bind(monitor_id);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_collector_monitor_bind table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_collector_monitor_bind') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_collector_monitor_bind' AND indexname = 'index_collector_monitor') THEN
+ DROP INDEX IF EXISTS index_collector_monitor;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_collector_monitor_bind' AND indexname = 'idx_collector_monitor_collector')
THEN
+ CREATE INDEX idx_collector_monitor_collector ON
hzb_collector_monitor_bind(collector);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_collector_monitor_bind' AND indexname =
'idx_collector_monitor_monitor_id') THEN
+ CREATE INDEX idx_collector_monitor_monitor_id ON
hzb_collector_monitor_bind(monitor_id);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_monitor table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_monitor') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_monitor'
AND indexname = 'monitor_query_index') THEN
+ DROP INDEX IF EXISTS monitor_query_index;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_monitor' AND indexname = 'idx_hzb_monitor_app') THEN
+ CREATE INDEX idx_hzb_monitor_app ON hzb_monitor(app);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_monitor' AND indexname = 'idx_hzb_monitor_instance') THEN
+ CREATE INDEX idx_hzb_monitor_instance ON hzb_monitor(instance);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_monitor' AND indexname = 'idx_hzb_monitor_name') THEN
+ CREATE INDEX idx_hzb_monitor_name ON hzb_monitor(name);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_monitor_bind table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_monitor_bind') THEN
+ -- Create new index if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_monitor_bind' AND indexname = 'index_monitor_bind') THEN
+ CREATE INDEX index_monitor_bind ON hzb_monitor_bind(biz_id);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_status_page_incident_component_bind table
+-- Special handling: component_id might have auto-created index from FK
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_status_page_incident_component_bind') THEN
+ -- Check if component_id column already has any index, create if not
+ IF NOT EXISTS (
+ SELECT 1 FROM pg_indexes
+ WHERE tablename = 'hzb_status_page_incident_component_bind'
+ AND indexdef LIKE '%component_id%'
+ AND indexname NOT LIKE '%_pkey'
+ ) THEN
+ CREATE INDEX idx_incident_component_component_id ON
hzb_status_page_incident_component_bind(component_id);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_push_metrics table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_push_metrics') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_push_metrics' AND indexname = 'push_query_index') THEN
+ DROP INDEX IF EXISTS push_query_index;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_push_metrics' AND indexname = 'idx_push_metrics_monitor_id') THEN
+ CREATE INDEX idx_push_metrics_monitor_id ON
hzb_push_metrics(monitor_id);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_push_metrics' AND indexname = 'idx_push_metrics_time') THEN
+ CREATE INDEX idx_push_metrics_time ON hzb_push_metrics(time);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_history table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_history') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_history'
AND indexname = 'history_query_index') THEN
+ DROP INDEX IF EXISTS history_query_index;
+ END IF;
+
+ -- Create new indexes if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_history' AND indexname = 'idx_hzb_history_instance') THEN
+ CREATE INDEX idx_hzb_history_instance ON hzb_history(instance);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_history' AND indexname = 'idx_hzb_history_app') THEN
+ CREATE INDEX idx_hzb_history_app ON hzb_history(app);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_history' AND indexname = 'idx_hzb_history_metrics') THEN
+ CREATE INDEX idx_hzb_history_metrics ON hzb_history(metrics);
+ END IF;
+
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_history' AND indexname = 'idx_hzb_history_metric') THEN
+ CREATE INDEX idx_hzb_history_metric ON hzb_history(metric);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_param table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_param') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_param' AND
indexname = 'idx_hzb_param_monitor_id') THEN
+ DROP INDEX IF EXISTS idx_hzb_param_monitor_id;
+ END IF;
+
+ -- Create new index if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename = 'hzb_param'
AND indexname = 'idx_hzb_param_monitor_id') THEN
+ CREATE INDEX idx_hzb_param_monitor_id ON hzb_param(monitor_id);
+ END IF;
+
+ -- Drop old unique constraint if exists
+ IF EXISTS (SELECT 1 FROM information_schema.table_constraints
+ WHERE table_name = 'hzb_param'
+ AND constraint_type = 'UNIQUE'
+ AND constraint_name = 'uk_hzb_param_monitor_field') THEN
+ ALTER TABLE hzb_param DROP CONSTRAINT IF EXISTS
uk_hzb_param_monitor_field;
+ END IF;
+
+ -- Create new unique constraint if not exist
+ IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints
+ WHERE table_name = 'hzb_param'
+ AND constraint_type = 'UNIQUE'
+ AND constraint_name = 'uk_hzb_param_monitor_field') THEN
+ ALTER TABLE hzb_param
+ ADD CONSTRAINT uk_hzb_param_monitor_field
+ UNIQUE (monitor_id, field);
+ END IF;
+ END IF;
+END $$;
+
+-- ========================================
+-- hzb_plugin_param table
+-- ========================================
+DO $$
+BEGIN
+ IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name =
'hzb_plugin_param') THEN
+ -- Drop old index if exists
+ IF EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_plugin_param' AND indexname = 'idx_hzb_plugin_param_plugin_metadata_id')
THEN
+ DROP INDEX IF EXISTS idx_hzb_plugin_param_plugin_metadata_id;
+ END IF;
+
+ -- Create new index if not exist
+ IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE tablename =
'hzb_plugin_param' AND indexname = 'idx_hzb_plugin_param_plugin_metadata_id')
THEN
+ CREATE INDEX idx_hzb_plugin_param_plugin_metadata_id ON
hzb_plugin_param(plugin_metadata_id);
+ END IF;
+
+ -- Drop old unique constraint if exists
+ IF EXISTS (SELECT 1 FROM information_schema.table_constraints
+ WHERE table_name = 'hzb_plugin_param'
+ AND constraint_type = 'UNIQUE'
+ AND constraint_name = 'uk_hzb_plugin_param_metadata_field')
THEN
+ ALTER TABLE hzb_plugin_param DROP CONSTRAINT IF EXISTS
uk_hzb_plugin_param_metadata_field;
+ END IF;
+
+ -- Create new unique constraint if not exist
+ IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints
+ WHERE table_name = 'hzb_plugin_param'
+ AND constraint_type = 'UNIQUE'
+ AND constraint_name =
'uk_hzb_plugin_param_metadata_field') THEN
+ ALTER TABLE hzb_plugin_param
+ ADD CONSTRAINT uk_hzb_plugin_param_metadata_field
+ UNIQUE (plugin_metadata_id, field);
+ END IF;
+ END IF;
+END $$;
+
+COMMIT;
diff --git
a/hertzbeat-startup/src/test/java/org/apache/hertzbeat/startup/EntityIndexIntegrationTest.java
b/hertzbeat-startup/src/test/java/org/apache/hertzbeat/startup/EntityIndexIntegrationTest.java
new file mode 100644
index 0000000000..43c82cc818
--- /dev/null
+++
b/hertzbeat-startup/src/test/java/org/apache/hertzbeat/startup/EntityIndexIntegrationTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.hertzbeat.startup;
+
+import jakarta.persistence.Index;
+import jakarta.persistence.Table;
+import jakarta.persistence.UniqueConstraint;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hertzbeat.common.entity.alerter.AlertDefineMonitorBind;
+import org.apache.hertzbeat.common.entity.manager.CollectorMonitorBind;
+import org.apache.hertzbeat.common.entity.manager.Monitor;
+import org.apache.hertzbeat.common.entity.manager.MonitorBind;
+import org.apache.hertzbeat.common.entity.manager.Param;
+import
org.apache.hertzbeat.common.entity.manager.StatusPageIncidentComponentBind;
+import org.apache.hertzbeat.common.entity.push.PushMetrics;
+import org.apache.hertzbeat.common.entity.warehouse.History;
+import org.apache.hertzbeat.manager.pojo.dto.PluginParam;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.web.WebProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Integration test for validating that entity indexes are actually created in
the database.
+ * This test uses H2 in-memory database to verify DDL generation and index
creation.
+ */
+@Slf4j
+@SpringBootTest(classes = HertzBeatApplication.class, webEnvironment =
SpringBootTest.WebEnvironment.NONE)
+@ActiveProfiles("test")
+@TestPropertySource(properties = {
+ "spring.jpa.hibernate.ddl-auto=create-drop",
+ "spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1",
+ "spring.datasource.driver-class-name=org.h2.Driver",
+ "spring.jpa.show-sql=false"
+})
+@DisplayName("Entity Index Creation Integration Test")
+class EntityIndexIntegrationTest {
+
+ @Autowired
+ private DataSource dataSource;
+
+ public List<Class<?>> entities = List.of(
+ AlertDefineMonitorBind.class,
+ CollectorMonitorBind.class,
+ Monitor.class,
+ MonitorBind.class,
+ Param.class,
+ StatusPageIncidentComponentBind.class,
+ PushMetrics.class,
+ History.class,
+ PluginParam.class
+ );
+
+ @Test
+ @DisplayName("All entity indexes should be created in database")
+ public void testAllEntityIndexes() throws SQLException {
+ for (Class<?> entity : entities) {
+ List<ExpectedIndex> expectedIndexes = parseExpectedIndexes(entity);
+ if (expectedIndexes.isEmpty()) {
+ continue;
+ }
+ Map<String, IndexMeta> actual =
getIndexes(expectedIndexes.get(0).tableName());
+
+ for (ExpectedIndex expected : expectedIndexes) {
+ assertIndexExists(expected, actual);
+ }
+ }
+
+ }
+
+ private List<ExpectedIndex> parseExpectedIndexes(Class<?> entityClass) {
+ Table table = entityClass.getAnnotation(Table.class);
+ if (table == null) {
+ return List.of();
+ }
+ String tableName = table.name().toUpperCase();
+ List<ExpectedIndex> result = new ArrayList<>();
+
+ for (Index idx : table.indexes()) {
+ Set<String> columns = Arrays.stream(idx.columnList().split(","))
+ .map(String::trim)
+ .map(String::toUpperCase)
+ .collect(Collectors.toSet());
+
+ result.add(new ExpectedIndex(tableName, columns, false));
+ }
+ for (UniqueConstraint uc : table.uniqueConstraints()) {
+ Set<String> columns = Arrays.stream(uc.columnNames())
+ .map(String::toUpperCase).collect(Collectors.toSet());
+ result.add(new ExpectedIndex(tableName, columns, true));
+ }
+ return result;
+ }
+
+ private void assertIndexExists(ExpectedIndex expected, Map<String,
IndexMeta> actualIndexes) {
+ boolean found = actualIndexes.values().stream().filter(idx ->
!expected.unique || idx.unique).anyMatch(idx ->
idx.columns.containsAll(expected.columns));
+ assertTrue(found, "Expected index not found. Table=" +
expected.tableName + ", columns=" + expected.columns + ", unique=" +
expected.unique + ", actual=" + actualIndexes);
+ }
+
+ private Map<String, IndexMeta> getIndexes(String tableName) throws
SQLException {
+ Map<String, IndexMeta> indexes = new HashMap<>();
+
+ String sql = """
+ SELECT
+ INDEX_NAME,
+ COLUMN_NAME,
+ IS_UNIQUE
+ FROM INFORMATION_SCHEMA.INDEX_COLUMNS
+ WHERE TABLE_NAME = ?
+ """;
+ try (Connection conn = dataSource.getConnection(); var ps =
conn.prepareStatement(sql)) {
+ ps.setString(1, tableName.toUpperCase());
+
+ try (ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ String column = rs.getString("COLUMN_NAME");
+ boolean unique = rs.getBoolean("IS_UNIQUE");
+ if ("PRIMARY".equalsIgnoreCase(indexName)) {
+ continue;
+ }
+ indexes.computeIfAbsent(indexName, k -> new
IndexMeta(unique)).columns.add(column.toUpperCase());
+ }
+ }
+ }
+ return indexes;
+ }
+
+ static class IndexMeta {
+ final boolean unique;
+ final Set<String> columns = new HashSet<>();
+
+ IndexMeta(boolean unique) {
+ this.unique = unique;
+ }
+ }
+
+ record ExpectedIndex(String tableName, Set<String> columns, boolean
unique) {
+
+ }
+
+ @TestConfiguration
+ static class TestConfig {
+
+ @Bean
+ public WebProperties webProperties() {
+ return new WebProperties();
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]