Repository: apache/skywalking (language: python)

Issue:
[Feature][Breaking Change] Enhance SQL-database storage through merging table and managing day-based table rolling.
### Search before asking

- [X] I had searched in the [issues](https://github.com/apache/skywalking/issues?q=is%3Aissue) and found no similar feature requirement.


### Description

Currently, with increasing requirements of using SQL database to support medium-scale deployment, from H2 to MySQL/Postgre, then Sharding MySQL. We face the length limitation for tables and indices to limit our flexibility. 
Here, I want to propose changing the SQL database storage in another way.
1. Merging all tables by referring to the latest ElasticSearch's [`SW_STORAGE_ES_LOGIC_SHARDING=false`](https://skywalking.apache.org/docs/main/next/en/faq/new-elasticsearch-storage-option-explanation-in-9.2.0/)
2. We begin to implement day-based rolling as we had done in ElasticSearch.

### Use case

The primary background of this change is due to the super quickly expanding of SkyWalking's monitoring scope. More metrics are being added for various data sources, such as AWS services(#9883) and Airflow(#10341).
The database eventually would not be able to support the number of tables. Meanwhile, the scale of monitoring targets could be unbalanced, such as the number of VM is much less than the number of pods and services.


### Related issues

_No response_

### Are you willing to submit a PR?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/skywalking.yaml b/.github/workflows/skywalking.yaml
index 0beb4ef5c805..f90552885c74 100644
--- a/.github/workflows/skywalking.yaml
+++ b/.github/workflows/skywalking.yaml
@@ -283,8 +283,6 @@ jobs:
     strategy:
       matrix:
         test:
-          - name: ShardingSphere
-            class: org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.ShardingSphereIT
           - name: ElasticSearch / OpenSearch
             class: org.apache.skywalking.library.elasticsearch.ElasticSearchIT
     steps:
@@ -344,8 +342,6 @@ jobs:
             config: test/e2e-v2/cases/storage/h2/e2e.yaml
           - name: Storage MySQL
             config: test/e2e-v2/cases/storage/mysql/e2e.yaml
-          - name: Storage TiDB
-            config: test/e2e-v2/cases/storage/tidb/e2e.yaml
           - name: Storage PostgreSQL
             config: test/e2e-v2/cases/storage/postgres/e2e.yaml
           - name: Storage ES 6.3.2
@@ -395,10 +391,6 @@ jobs:
           - name: Alarm PostgreSQL
             config: test/e2e-v2/cases/alarm/postgres/e2e.yaml
 
-          - name: TTL TiDB
-            config: test/e2e-v2/cases/ttl/tidb/e2e.yaml
-          - name: TTL PostgreSQL
-            config: test/e2e-v2/cases/ttl/postgresql/e2e.yaml
           - name: TTL ES 6.3.2
             config: test/e2e-v2/cases/ttl/es/e2e.yaml
             env: ES_VERSION=6.3.2
@@ -480,8 +472,6 @@ jobs:
             config: test/e2e-v2/cases/profiling/trace/mysql/e2e.yaml
           - name: Trace Profiling Postgres
             config: test/e2e-v2/cases/profiling/trace/postgres/e2e.yaml
-          - name: Trace Profiling TiDB
-            config: test/e2e-v2/cases/profiling/trace/tidb/e2e.yaml
           - name: Trace Profiling OpenSearch 1.1.0
             config: test/e2e-v2/cases/profiling/trace/opensearch/e2e.yaml
             env: OPENSEARCH_VERSION=1.1.0
@@ -504,8 +494,6 @@ jobs:
             config: test/e2e-v2/cases/profiling/ebpf/oncpu/mysql/e2e.yaml
           - name: eBPF Profiling On CPU Postgres
             config: test/e2e-v2/cases/profiling/ebpf/oncpu/postgres/e2e.yaml
-          - name: eBPF Profiling On CPU TiDB
-            config: test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/e2e.yaml
           - name: eBPF Profiling On CPU OpenSearch 1.1.0
             config: test/e2e-v2/cases/profiling/ebpf/oncpu/opensearch/e2e.yaml
             env: OPENSEARCH_VERSION=1.1.0
@@ -530,8 +518,6 @@ jobs:
             config: test/e2e-v2/cases/profiling/ebpf/network/mysql/e2e.yaml
           - name: eBPF Profiling Network Postgres
             config: test/e2e-v2/cases/profiling/ebpf/network/postgres/e2e.yaml
-          - name: eBPF Profiling Network TiDB
-            config: test/e2e-v2/cases/profiling/ebpf/network/tidb/e2e.yaml
           - name: eBPF Profiling Network OpenSearch 1.1.0
             config: test/e2e-v2/cases/profiling/ebpf/network/opensearch/e2e.yaml
             env: OPENSEARCH_VERSION=1.1.0
@@ -651,14 +637,6 @@ jobs:
           - name: Zipkin BanyanDB
             config: test/e2e-v2/cases/zipkin/banyandb/e2e.yaml
 
-          - name: MySQL-Sharding storage
-            config: test/e2e-v2/cases/storage/mysql/sharding/e2e.yaml
-          - name: MySQL-Sharding log
-            config: test/e2e-v2/cases/log/mysql/sharding/e2e.yaml
-          - name: MySQL-Sharding browser
-            config: test/e2e-v2/cases/browser/mysql/sharding/e2e.yaml
-          - name: MySQL-Sharding zipkin
-            config: test/e2e-v2/cases/zipkin/mysql/sharding/e2e.yaml
           - name: APISIX metrics
             config: test/e2e-v2/cases/apisix/otel-collector/e2e.yaml
           - name: Exporter Kafka
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 44b62ae03c72..810e21a8de41 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -11,6 +11,8 @@
 * Support to bind TLS status as a part of component for service topology.
 * Fix component ID priority bug.
 * Fix component ID of topology overlap due to storage layer bugs.
+* [Breaking Change] Enhance JDBC storage through merging tables and managing day-based table rolling.
+* [Breaking Change] Sharding-MySQL implementations and tests get removed due to we have the day-based rolling mechanism by default
 
 #### Documentation
 
diff --git a/docs/en/setup/backend/backend-setup.md b/docs/en/setup/backend/backend-setup.md
index a4d460531012..ef5bc0a3e90f 100755
--- a/docs/en/setup/backend/backend-setup.md
+++ b/docs/en/setup/backend/backend-setup.md
@@ -61,12 +61,12 @@ storage:
   selector: mysql # the mysql storage will actually be activated, while the h2 storage takes no effect
   h2:
     properties:
-      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1}
+      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE}
       dataSource.user: ${SW_STORAGE_H2_USER:sa}
     metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
   mysql:
     properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest"}
+      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?allowMultiQueries=true"}
       dataSource.user: ${SW_DATA_SOURCE_USER:root}
       dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root@1234}
       dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
diff --git a/docs/en/setup/backend/backend-storage.md b/docs/en/setup/backend/backend-storage.md
index 5abe9faf3e9d..9ae0361fce3a 100644
--- a/docs/en/setup/backend/backend-storage.md
+++ b/docs/en/setup/backend/backend-storage.md
@@ -260,7 +260,7 @@ storage:
   selector: ${SW_STORAGE:mysql}
   mysql:
     properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true"}
+      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true&allowMultiQueries=true"}
       dataSource.user: ${SW_DATA_SOURCE_USER:root}
       dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root@1234}
       dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
@@ -275,60 +275,8 @@ All connection-related settings, including URL link, username, and password, are
 Only part of the settings is listed here. See the [HikariCP](https://github.com/brettwooldridge/HikariCP) connection pool document for full settings.
 To understand the function of the parameter `rewriteBatchedStatements=true` in MySQL, see the [MySQL official document](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-performance-extensions.html#cj-conn-prop_rewriteBatchedStatements).
 
-## MySQL-Sharding
-MySQL-Sharding plugin provides the MySQL database sharding and table sharding, this feature
-leverage [Shardingsphere-Proxy](https://shardingsphere.apache.org/document/current/en/overview/#shardingsphere-proxy)
-to manage the JDBC between OAP and multi-database instances, and according to the sharding rules do routing to the database and table sharding.
-
-Tested Shardingsphere-Proxy 5.3.1 version, and MySQL Client driver 8.0.13 version is currently available.
-Activate MySQL and Shardingsphere-Proxy as storage, and set storage provider to **mysql-sharding**.
-
-**NOTE:** MySQL driver is NOT allowed in Apache official distribution and source codes.
-Please download the MySQL driver on your own. Copy the connection driver jar to `oap-libs`.
-
-```yaml
-storage:
-  selector: ${SW_STORAGE:mysql-sharding}
-  mysql-sharding:
-    properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:13307/swtest?rewriteBatchedStatements=true"}
-      dataSource.user: ${SW_DATA_SOURCE_USER:root}
-      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}
-    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
-    maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
-    asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}
-    # The dataSources are configured in ShardingSphere-Proxy config-sharding.yaml
-    # The dataSource name should include the prefix "ds_" and separated by ","
-    dataSources: ${SW_JDBC_SHARDING_DATA_SOURCES:ds_0,ds_1}
-
-```
-
-## TiDB
-Tested TiDB Server 4.0.8 version, and MySQL Client driver 8.0.13 version is currently available.
-Activate TiDB as storage, and set storage provider to **tidb**.
-
-```yaml
-storage:
-  selector: ${SW_STORAGE:tidb}
-  tidb:
-    properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:4000/swtest?rewriteBatchedStatements=true"}
-      dataSource.user: ${SW_DATA_SOURCE_USER:root}
-      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:""}
-      dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
-      dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
-      dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
-      dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
-      dataSource.useAffectedRows: ${SW_DATA_SOURCE_USE_AFFECTED_ROWS:true}
-    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
-    maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}
-    numOfSearchableValuesPerTag: ${SW_STORAGE_NUM_OF_SEARCHABLE_VALUES_PER_TAG:2}
-    maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
-    asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}
-```
-All connection-related settings, including URL link, username, and password are found in `application.yml`.
-For details on settings, refer to the configuration of *MySQL* above.
-To understand the function of the parameter `rewriteBatchedStatements=true` in TiDB, see the document of [TiDB best practices](https://docs.pingcap.com/tidb/stable/java-app-best-practices#use-batch-api).
+In theory, all other databases that are compatible with MySQL protocol should be able to use this storage plugin,
+such as TiDB. Please compose the JDBC URL according to the database's documentation.
 
 ## PostgreSQL
 PostgreSQL JDBC driver uses version 42.3.2. It supports PostgreSQL 8.2 or newer.
diff --git a/docs/en/setup/backend/configuration-vocabulary.md b/docs/en/setup/backend/configuration-vocabulary.md
index 68608ce79c0f..be3a1cf0fb5b 100644
--- a/docs/en/setup/backend/configuration-vocabulary.md
+++ b/docs/en/setup/backend/configuration-vocabulary.md
@@ -129,12 +129,6 @@ The Configuration Vocabulary lists all available configurations provided by `app
 | -                       | -             | metadataQueryMaxSize                                                                                                                                                     | The maximum size of metadata per query.                                                                                                                                                                                                                                                                                                                                                                                                                         | SW_STORAGE_MYSQL_QUERY_MAX_SIZE                   | 5000                                                                                         |
 | -                       | -             | maxSizeOfBatchSql                                                                                                                                                        | The maximum size of batch size of SQL execution                                                                                                                                                                                                                                                                                                                                                                                                                 | SW_STORAGE_MAX_SIZE_OF_BATCH_SQL                  | 2000                                                                                         |
 | -                       | -             | asyncBatchPersistentPoolSize                                                                                                                                             | async flush data into database thread size                                                                                                                                                                                                                                                                                                                                                                                                                      | SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE       | 4                                                                                            |
-| -                       | mysql-sharding | -                                                                                                                                                                        | Sharding-Proxy for MySQL properties. The MySQL JDBC Driver is not in the dist. Please copy it into the oap-lib folder manually.                                                                                                                                                                                                                                                                                                                                                       | -                                                 | -                                                                                            |
-| -                       | -             | properties                                                                                                                                                               | Hikari connection pool configurations.                                                                                                                                                                                                                                                                                                                                                                                                                          | -                                                 | Listed in the `application.yaml`.                                                            |
-| -                       | -             | metadataQueryMaxSize                                                                                                                                                     | The maximum size of metadata per query.                                                                                                                                                                                                                                                                                                                                                                                                                         | SW_STORAGE_MYSQL_QUERY_MAX_SIZE                   | 5000                                                                                         |
-| -                       | -             | maxSizeOfBatchSql                                                                                                                                                        | The maximum size of batch size of SQL execution                                                                                                                                                                                                                                                                                                                                                                                                                 | SW_STORAGE_MAX_SIZE_OF_BATCH_SQL                  | 2000                                                                                         |
-| -                       | -             | asyncBatchPersistentPoolSize                                                                                                                                             | async flush data into database thread size                                                                                                                                                                                                                                                                                                                                                                                                                      | SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE       | 4                                                                                            |
-| -                       | -             | dataSources                                                                                                                                             |  The dataSources are configured in ShardingSphere-Proxy config-sharding.yaml.The dataSource name should include the prefix "ds_" and separated by "," and start from ds_0                                                                                                                                                                                                                                                                                                                                                                                                                     | SW_JDBC_SHARDING_DATA_SOURCES       | ds_0,ds_1                                                                                    |
 | -                       | postgresql    | -                                                                                                                                                                        | PostgreSQL storage.                                                                                                                                                                                                                                                                                                                                                                                                                                             | -                                                 | -                                                                                            |
 | -                       | -             | properties                                                                                                                                                               | Hikari connection pool configurations.                                                                                                                                                                                                                                                                                                                                                                                                                          | -                                                 | Listed in the `application.yaml`.                                                            |
 | -                       | -             | metadataQueryMaxSize                                                                                                                                                     | The maximum size of metadata per query.                                                                                                                                                                                                                                                                                                                                                                                                                         | SW_STORAGE_MYSQL_QUERY_MAX_SIZE                   | 5000                                                                                         |
diff --git a/oap-server-bom/pom.xml b/oap-server-bom/pom.xml
index 06152588e613..f038479d3146 100644
--- a/oap-server-bom/pom.xml
+++ b/oap-server-bom/pom.xml
@@ -553,6 +553,12 @@
                 <version>${testcontainers.version}</version>
                 <scope>test</scope>
             </dependency>
+            <dependency>
+                <groupId>org.testcontainers</groupId>
+                <artifactId>postgresql</artifactId>
+                <version>${testcontainers.version}</version>
+                <scope>test</scope>
+            </dependency>
             <dependency>
                 <groupId>org.testcontainers</groupId>
                 <artifactId>junit-jupiter</artifactId>
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/Const.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/Const.java
index d61ead60d23e..8a51c4316e1c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/Const.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/Const.java
@@ -27,6 +27,7 @@ public class Const {
     public static final String RELATION_ID_CONNECTOR = "-";
     public static final String RELATION_ID_PARSER_SPLIT = "\\-";
     public static final String LINE = "-";
+    public static final String UNDERSCORE = "_";
     public static final String COMMA = ",";
     public static final String SPACE = " ";
     public static final String KEY_VALUE_SPLIT = ",";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/EndpointTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/EndpointTraffic.java
index 1517a115a596..a8c72c93638d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/EndpointTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/endpoint/EndpointTraffic.java
@@ -18,6 +18,10 @@
 
 package org.apache.skywalking.oap.server.core.analysis.manual.endpoint;
 
+import com.google.common.base.Strings;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.MetricsExtension;
@@ -26,27 +30,18 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import com.google.common.base.Strings;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.TIME_BUCKET;
 
 @Stream(name = EndpointTraffic.INDEX_NAME, scopeId = DefaultScopeDefine.ENDPOINT,
     builder = EndpointTraffic.Builder.class, processor = MetricsStreamProcessor.class)
 @MetricsExtension(supportDownSampling = false, supportUpdate = false)
 @EqualsAndHashCode
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_MIN_RANGE_SHARDING_ALGORITHM, tableShardingColumn = TIME_BUCKET, dataSourceShardingColumn = ID)
 public class EndpointTraffic extends Metrics {
 
     public static final String INDEX_NAME = "endpoint_traffic";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/InstanceTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/InstanceTraffic.java
index 1bafe6d835a5..24f3bb0d6288 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/InstanceTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/instance/InstanceTraffic.java
@@ -18,6 +18,11 @@
 
 package org.apache.skywalking.oap.server.core.analysis.manual.instance;
 
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.MetricsExtension;
@@ -25,21 +30,15 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
+
 import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_INSTANCE;
 
 @Stream(name = InstanceTraffic.INDEX_NAME, scopeId = SERVICE_INSTANCE,
@@ -49,7 +48,6 @@
     "serviceId",
     "name"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class InstanceTraffic extends Metrics {
     public static final String INDEX_NAME = "instance_traffic";
     public static final String SERVICE_ID = "service_id";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/log/LogRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/log/LogRecord.java
index db28356a6502..6715948e10b5 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/log/LogRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/log/LogRecord.java
@@ -22,7 +22,6 @@
 import org.apache.skywalking.oap.server.core.analysis.Stream;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
@@ -31,13 +30,11 @@
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 
-import static org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord.SERVICE_ID;
 import static org.apache.skywalking.oap.server.core.analysis.record.Record.TIME_BUCKET;
 
 @SuperDataset
 @Stream(name = LogRecord.INDEX_NAME, scopeId = DefaultScopeDefine.LOG, builder = LogRecord.Builder.class, processor = RecordStreamProcessor.class)
 @SQLDatabase.ExtraColumn4AdditionalEntity(additionalTable = AbstractLogRecord.ADDITIONAL_TAG_TABLE, parentColumn = TIME_BUCKET)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_SEC_RANGE_SHARDING_ALGORITHM, dataSourceShardingColumn = SERVICE_ID, tableShardingColumn = TIME_BUCKET)
 @BanyanDB.TimestampColumn(AbstractLogRecord.TIMESTAMP)
 public class LogRecord extends AbstractLogRecord {
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/networkalias/NetworkAddressAlias.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/networkalias/NetworkAddressAlias.java
index a4d621f8c41f..a0a6db0f0c55 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/networkalias/NetworkAddressAlias.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/networkalias/NetworkAddressAlias.java
@@ -28,11 +28,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -46,7 +44,6 @@
 @EqualsAndHashCode(of = {
     "address"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class NetworkAddressAlias extends Metrics {
     public static final String INDEX_NAME = "network_address_alias";
     public static final String ADDRESS = "address";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ProcessTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ProcessTraffic.java
index 878563c60584..03fb399caf8e 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ProcessTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ProcessTraffic.java
@@ -31,11 +31,9 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -52,7 +50,6 @@
     "instanceId",
     "name",
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 @BanyanDB.StoreIDAsTag
 public class ProcessTraffic extends Metrics {
     public static final String INDEX_NAME = "process_traffic";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ServiceLabelRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ServiceLabelRecord.java
index d52ac8cf40d3..95e6d4e3078b 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ServiceLabelRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/process/ServiceLabelRecord.java
@@ -25,11 +25,9 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -50,7 +48,6 @@
         "serviceId",
         "label"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ServiceLabelRecord extends Metrics {
 
     public static final String INDEX_NAME = "service_label";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/EndpointRelationServerSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/EndpointRelationServerSideMetrics.java
index 71e94ebf08e3..b5420c3677fc 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/EndpointRelationServerSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/endpoint/EndpointRelationServerSideMetrics.java
@@ -27,25 +27,19 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ENTITY_ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.TIME_BUCKET;
-
 @Stream(name = EndpointRelationServerSideMetrics.INDEX_NAME, scopeId = DefaultScopeDefine.ENDPOINT_RELATION,
     builder = EndpointRelationServerSideMetrics.Builder.class, processor = MetricsStreamProcessor.class)
 @MetricsExtension(supportDownSampling = true, supportUpdate = false, timeRelativeID = true)
 @EqualsAndHashCode(of = {
     "entityId"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_BUCKET_SHARDING_ALGORITHM, tableShardingColumn = TIME_BUCKET, dataSourceShardingColumn = ENTITY_ID)
 public class EndpointRelationServerSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "endpoint_relation_server_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationClientSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationClientSideMetrics.java
index e72d3414ef54..39a21ee9fb51 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationClientSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationClientSideMetrics.java
@@ -27,25 +27,19 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ENTITY_ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.TIME_BUCKET;
-
 @Stream(name = ServiceInstanceRelationClientSideMetrics.INDEX_NAME, scopeId = DefaultScopeDefine.SERVICE_INSTANCE_RELATION,
     builder = ServiceInstanceRelationClientSideMetrics.Builder.class, processor = MetricsStreamProcessor.class)
 @MetricsExtension(supportDownSampling = true, supportUpdate = false, timeRelativeID = true)
 @EqualsAndHashCode(of = {
     "entityId"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_BUCKET_SHARDING_ALGORITHM, tableShardingColumn = TIME_BUCKET, dataSourceShardingColumn = ENTITY_ID)
 public class ServiceInstanceRelationClientSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "service_instance_relation_client_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationServerSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationServerSideMetrics.java
index b470f1d78ca7..1a0753df3a4c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationServerSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/instance/ServiceInstanceRelationServerSideMetrics.java
@@ -27,25 +27,19 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ENTITY_ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.TIME_BUCKET;
-
 @Stream(name = ServiceInstanceRelationServerSideMetrics.INDEX_NAME, scopeId = DefaultScopeDefine.SERVICE_INSTANCE_RELATION,
     builder = ServiceInstanceRelationServerSideMetrics.Builder.class, processor = MetricsStreamProcessor.class)
 @MetricsExtension(supportDownSampling = true, supportUpdate = false, timeRelativeID = true)
 @EqualsAndHashCode(of = {
     "entityId"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_BUCKET_SHARDING_ALGORITHM, tableShardingColumn = TIME_BUCKET, dataSourceShardingColumn = ENTITY_ID)
 public class ServiceInstanceRelationServerSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "service_instance_relation_server_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationClientSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationClientSideMetrics.java
index 79a943ccf8af..e4f54d086ac1 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationClientSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationClientSideMetrics.java
@@ -28,11 +28,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -44,7 +42,6 @@
     "entityId",
     "component_id"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ProcessRelationClientSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "process_relation_client_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationServerSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationServerSideMetrics.java
index 09d8d3f7ccb8..d5dbaa2c2842 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationServerSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/process/ProcessRelationServerSideMetrics.java
@@ -28,11 +28,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -43,7 +41,6 @@
 @EqualsAndHashCode(of = {
     "entityId"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ProcessRelationServerSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "process_relation_server_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationClientSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationClientSideMetrics.java
index 5288d13c98ef..9632c6c32c99 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationClientSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationClientSideMetrics.java
@@ -27,25 +27,19 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ENTITY_ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.TIME_BUCKET;
-
 @Stream(name = ServiceRelationClientSideMetrics.INDEX_NAME, scopeId = DefaultScopeDefine.SERVICE_RELATION,
     builder = ServiceRelationClientSideMetrics.Builder.class, processor = MetricsStreamProcessor.class)
 @EqualsAndHashCode(of = {
     "entityId"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_BUCKET_SHARDING_ALGORITHM, tableShardingColumn = TIME_BUCKET, dataSourceShardingColumn = ENTITY_ID)
 public class ServiceRelationClientSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "service_relation_client_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationServerSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationServerSideMetrics.java
index 8ac2fd2ab5ce..4940b43ca746 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationServerSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/relation/service/ServiceRelationServerSideMetrics.java
@@ -28,26 +28,20 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ENTITY_ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.TIME_BUCKET;
-
 @Stream(name = ServiceRelationServerSideMetrics.INDEX_NAME, scopeId = DefaultScopeDefine.SERVICE_RELATION,
     builder = ServiceRelationServerSideMetrics.Builder.class, processor = MetricsStreamProcessor.class)
 @MetricsExtension(supportDownSampling = true, supportUpdate = true, timeRelativeID = true)
 @EqualsAndHashCode(of = {
     "entityId"
 }, callSuper = true)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_BUCKET_SHARDING_ALGORITHM, tableShardingColumn = TIME_BUCKET, dataSourceShardingColumn = ENTITY_ID)
 public class ServiceRelationServerSideMetrics extends Metrics {
 
     public static final String INDEX_NAME = "service_relation_server_side";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/searchtag/TagAutocompleteData.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/searchtag/TagAutocompleteData.java
index 372e5aeb848f..469b6eaac7de 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/searchtag/TagAutocompleteData.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/searchtag/TagAutocompleteData.java
@@ -27,11 +27,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -47,7 +45,6 @@
     "tagValue",
     "tagType"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class TagAutocompleteData extends Metrics {
     public static final String INDEX_NAME = "tag_autocomplete";
     public static final String TAG_KEY = "tag_key";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/segment/SegmentRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/segment/SegmentRecord.java
index e123596f258c..e33adbaee014 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/segment/SegmentRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/segment/SegmentRecord.java
@@ -18,7 +18,6 @@
 
 package org.apache.skywalking.oap.server.core.analysis.manual.segment;
 
-import java.util.List;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.skywalking.oap.server.core.analysis.Stream;
@@ -26,24 +25,23 @@
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
 import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.annotation.SuperDataset;
-import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord.SERVICE_ID;
+import java.util.List;
+
 import static org.apache.skywalking.oap.server.core.analysis.record.Record.TIME_BUCKET;
 
 @SuperDataset
 @Stream(name = SegmentRecord.INDEX_NAME, scopeId = DefaultScopeDefine.SEGMENT, builder = SegmentRecord.Builder.class, processor = RecordStreamProcessor.class)
 @SQLDatabase.ExtraColumn4AdditionalEntity(additionalTable = SegmentRecord.ADDITIONAL_TAG_TABLE, parentColumn = TIME_BUCKET)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_SEC_RANGE_SHARDING_ALGORITHM, dataSourceShardingColumn = SERVICE_ID, tableShardingColumn = TIME_BUCKET)
 @BanyanDB.TimestampColumn(SegmentRecord.START_TIME)
 public class SegmentRecord extends Record {
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/ServiceTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/ServiceTraffic.java
index af015fbf80e1..d1404b880983 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/ServiceTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/service/ServiceTraffic.java
@@ -18,6 +18,9 @@
 
 package org.apache.skywalking.oap.server.core.analysis.manual.service;
 
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
@@ -27,18 +30,14 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ElasticSearch;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
+
 import static org.apache.logging.log4j.util.Base64Util.encode;
 import static org.apache.skywalking.oap.server.core.Const.DOUBLE_COLONS_SPLIT;
 
@@ -49,7 +48,6 @@
     "name",
     "layer"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ServiceTraffic extends Metrics {
     public static final String INDEX_NAME = "service_traffic";
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Event.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Event.java
index 6fecb832a3e4..59555b8b106d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Event.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Event.java
@@ -29,11 +29,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -50,7 +48,6 @@
     callSuper = false,
     of = "uuid"
 )
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class Event extends Metrics {
 
     public static final String INDEX_NAME = "events";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Metrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Metrics.java
index 5c0b212e2256..79840056a211 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Metrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/Metrics.java
@@ -23,14 +23,9 @@
 import lombok.Setter;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.remote.data.StreamData;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageData;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
-
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ENTITY_ID;
-import static org.apache.skywalking.oap.server.core.analysis.metrics.Metrics.ID;
 
 /**
  * Metrics represents the statistic data, which analysis by OAL script or hard code. It has the lifecycle controlled by
@@ -39,7 +34,6 @@
 @EqualsAndHashCode(of = {
     "timeBucket"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_RELATIVE_ID_SHARDING_ALGORITHM, tableShardingColumn = ID, dataSourceShardingColumn = ENTITY_ID)
 public abstract class Metrics extends StreamData implements StorageData {
     public static final String ENTITY_ID = "entity_id";
     public static final String ID = "id";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java
index f48157a9c289..0c0e6e508fd6 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java
@@ -18,9 +18,6 @@
 
 package org.apache.skywalking.oap.server.core.analysis.worker;
 
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
@@ -38,6 +35,10 @@
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
 
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * ManagementProcessor represents the UI/CLI interactive process. They are management data, which size is not huge and
  * time serious.
@@ -77,7 +78,7 @@ public void create(final ModuleDefineHolder moduleDefineHolder, final Stream str
 
         ModelCreator modelSetter = moduleDefineHolder.find(CoreModule.NAME).provider().getService(ModelCreator.class);
         // Management stream doesn't read data from database during the persistent process. Keep the timeRelativeID == false always.
-        Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.None), false);
+        Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.None));
 
         final ManagementPersistentWorker persistentWorker = new ManagementPersistentWorker(moduleDefineHolder, model, managementDAO);
         workers.put(streamClass, persistentWorker);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/MetricsStreamProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/MetricsStreamProcessor.java
index de4c48a2c7b1..290b51122488 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/MetricsStreamProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/MetricsStreamProcessor.java
@@ -18,11 +18,6 @@
 
 package org.apache.skywalking.oap.server.core.analysis.worker;
 
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.skywalking.oap.server.core.CoreModule;
@@ -46,6 +41,12 @@
 import org.apache.skywalking.oap.server.core.worker.IWorkerInstanceSetter;
 import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder;
 
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * MetricsStreamProcessor represents the entrance and creator of the metrics streaming aggregation work flow.
  *
@@ -165,15 +166,13 @@ private void create(ModuleDefineHolder moduleDefineHolder,
         if (supportDownSampling) {
             if (configService.shouldToHour()) {
                 Model model = modelSetter.add(
-                    metricsClass, stream.getScopeId(), new Storage(stream.getName(), timeRelativeID, DownSampling.Hour),
-                    false
+                    metricsClass, stream.getScopeId(), new Storage(stream.getName(), timeRelativeID, DownSampling.Hour)
                 );
                 hourPersistentWorker = downSamplingWorker(moduleDefineHolder, metricsDAO, model, supportUpdate, kind);
             }
             if (configService.shouldToDay()) {
                 Model model = modelSetter.add(
-                    metricsClass, stream.getScopeId(), new Storage(stream.getName(), timeRelativeID, DownSampling.Day),
-                    false
+                    metricsClass, stream.getScopeId(), new Storage(stream.getName(), timeRelativeID, DownSampling.Day)
                 );
                 dayPersistentWorker = downSamplingWorker(moduleDefineHolder, metricsDAO, model, supportUpdate, kind);
             }
@@ -183,8 +182,7 @@ private void create(ModuleDefineHolder moduleDefineHolder,
         }
 
         Model model = modelSetter.add(
-            metricsClass, stream.getScopeId(), new Storage(stream.getName(), timeRelativeID, DownSampling.Minute),
-            false
+            metricsClass, stream.getScopeId(), new Storage(stream.getName(), timeRelativeID, DownSampling.Minute)
         );
         MetricsPersistentWorker minutePersistentWorker = minutePersistentWorker(
             moduleDefineHolder, metricsDAO, model, transWorker, supportUpdate, kind);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java
index ffb31ded4276..0d59ff3b566c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java
@@ -77,7 +77,7 @@ public void create(ModuleDefineHolder moduleDefineHolder, Stream stream, Class<?
 
         ModelCreator modelSetter = moduleDefineHolder.find(CoreModule.NAME).provider().getService(ModelCreator.class);
         // None stream doesn't read data from database during the persistent process. Keep the timeRelativeID == false always.
-        Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.Minute), true);
+        Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.Minute));
 
         final NoneStreamPersistentWorker persistentWorker = new NoneStreamPersistentWorker(moduleDefineHolder, model, noneStream);
         workers.put(streamClass, persistentWorker);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/RecordStreamProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/RecordStreamProcessor.java
index 3d081a8bb5c7..a962917e233e 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/RecordStreamProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/RecordStreamProcessor.java
@@ -73,7 +73,7 @@ public void create(ModuleDefineHolder moduleDefineHolder, Stream stream, Class<?
         ModelCreator modelSetter = moduleDefineHolder.find(CoreModule.NAME).provider().getService(ModelCreator.class);
         // Record stream doesn't read data from database during the persistent process. Keep the timeRelativeID == false always.
         Model model = modelSetter.add(
-            recordClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.Second), true);
+            recordClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.Second));
         ExportRecordWorker exportWorker = new ExportRecordWorker(moduleDefineHolder);
         RecordPersistentWorker persistentWorker = new RecordPersistentWorker(moduleDefineHolder, model, recordDAO, exportWorker);
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/TopNStreamProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/TopNStreamProcessor.java
index dc6efcd5b252..1b4a84e9e2af 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/TopNStreamProcessor.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/TopNStreamProcessor.java
@@ -92,7 +92,7 @@ public void create(ModuleDefineHolder moduleDefineHolder,
         ModelCreator modelSetter = moduleDefineHolder.find(CoreModule.NAME).provider().getService(ModelCreator.class);
         // Top N metrics doesn't read data from database during the persistent process. Keep the timeRelativeID == false always.
         Model model = modelSetter.add(
-            topNClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.Second), true);
+            topNClass, stream.scopeId(), new Storage(stream.name(), false, DownSampling.Second));
 
         TopNWorker persistentWorker = new TopNWorker(
             moduleDefineHolder, model, topSize, topNWorkerReportCycle * 60 * 1000L, recordDAO);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java
index ad245397204a..1310a8efc787 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java
@@ -23,22 +23,16 @@
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.annotation.SuperDataset;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 
-import static org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord.SERVICE_ID;
-import static org.apache.skywalking.oap.server.core.analysis.record.Record.TIME_BUCKET;
-
 @SuperDataset
 @Stream(name = BrowserErrorLogRecord.INDEX_NAME, scopeId = DefaultScopeDefine.BROWSER_ERROR_LOG, builder = BrowserErrorLogRecord.Builder.class, processor = RecordStreamProcessor.class)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_SEC_RANGE_SHARDING_ALGORITHM, dataSourceShardingColumn = SERVICE_ID, tableShardingColumn = TIME_BUCKET)
 @BanyanDB.TimestampColumn(BrowserErrorLogRecord.TIMESTAMP)
 public class BrowserErrorLogRecord extends Record {
     public static final String INDEX_NAME = "browser_error_log";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/EBPFProfilingQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/EBPFProfilingQueryService.java
index 46d80e3c79d2..066a65b4cd26 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/EBPFProfilingQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/EBPFProfilingQueryService.java
@@ -19,16 +19,6 @@
 package org.apache.skywalking.oap.server.core.profiling.ebpf;
 
 import com.google.gson.Gson;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
@@ -63,6 +53,17 @@
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
 @Slf4j
 @RequiredArgsConstructor
 public class EBPFProfilingQueryService implements Service {
@@ -190,8 +191,11 @@ public List<EBPFProfilingTask> queryEBPFProfilingTasks(String serviceId, String
         return new ArrayList<>(tmpMap.values());
     }
 
-    public List<EBPFProfilingSchedule> queryEBPFProfilingSchedules(String taskId) throws IOException {
+    public List<EBPFProfilingSchedule> queryEBPFProfilingSchedules(String taskId) throws Exception {
         final List<EBPFProfilingSchedule> schedules = getScheduleDAO().querySchedules(taskId);
+
+        log.info("schedules: {}", GSON.toJson(schedules));
+
         if (CollectionUtils.isNotEmpty(schedules)) {
             final Model processModel = getProcessModel();
             final List<Metrics> processMetrics = schedules.stream()
@@ -202,6 +206,8 @@ public List<EBPFProfilingSchedule> queryEBPFProfilingSchedules(String taskId) th
                     }).collect(Collectors.toList());
             final List<Metrics> processes = getProcessMetricsDAO().multiGet(processModel, processMetrics);
 
+            log.info("processes: {}", GSON.toJson(processes));
+
             final Map<String, Process> processMap = processes.stream()
                                                                 .map(t -> (ProcessTraffic) t)
                                                                 .collect(Collectors.toMap(m -> m.id().build(), this::convertProcess));
@@ -238,4 +244,4 @@ private Process convertProcess(ProcessTraffic traffic) {
         }
         return process;
     }
-}
\ No newline at end of file
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingDataRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingDataRecord.java
index d4b8404edf3c..b40aa2348885 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingDataRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingDataRecord.java
@@ -50,10 +50,10 @@ public class EBPFProfilingDataRecord extends Record {
     public static final String DATA_BINARY = "dump_binary";
     public static final String UPLOAD_TIME = "upload_time";
 
-    @Column(name = TASK_ID, length = 600)
+    @Column(name = TASK_ID)
     @BanyanDB.SeriesID(index = 0)
     private String taskId;
-    @Column(name = SCHEDULE_ID, length = 600)
+    @Column(name = SCHEDULE_ID)
     private String scheduleId;
     @Column(name = STACK_ID_LIST)
     private String stackIdList;
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingScheduleRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingScheduleRecord.java
index 98042fbcb63e..9e9f78b5e648 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingScheduleRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/ebpf/storage/EBPFProfilingScheduleRecord.java
@@ -26,11 +26,9 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -52,7 +50,6 @@
     "processId",
     "startTime",
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class EBPFProfilingScheduleRecord extends Metrics {
 
     public static final String INDEX_NAME = "ebpf_profiling_schedule";
@@ -62,7 +59,7 @@ public class EBPFProfilingScheduleRecord extends Metrics {
     public static final String END_TIME = "end_time";
     public static final String EBPF_PROFILING_SCHEDULE_ID = "ebpf_profiling_schedule_id";
 
-    @Column(name = TASK_ID, length = 600)
+    @Column(name = TASK_ID)
     private String taskId;
     @Column(name = PROCESS_ID, length = 600)
     private String processId;
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
index 218bfa322f8c..db8eebfa7665 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileThreadSnapshotRecord.java
@@ -52,11 +52,11 @@ public class ProfileThreadSnapshotRecord extends Record {
     public static final String STACK_BINARY = "stack_binary";
 
     @Column(name = TASK_ID)
-    @SQLDatabase.QueryUnifiedIndex(withColumns = {SEGMENT_ID})
+    @SQLDatabase.CompositeIndex(withColumns = {SEGMENT_ID})
     private String taskId;
     @Column(name = SEGMENT_ID)
-    @SQLDatabase.QueryUnifiedIndex(withColumns = {SEQUENCE})
-    @SQLDatabase.QueryUnifiedIndex(withColumns = {DUMP_TIME})
+    @SQLDatabase.CompositeIndex(withColumns = {SEQUENCE})
+    @SQLDatabase.CompositeIndex(withColumns = {DUMP_TIME})
     @BanyanDB.SeriesID(index = 0)
     private String segmentId;
     @Column(name = DUMP_TIME)
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/DurationUtils.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/DurationUtils.java
index cc53aa83f105..6af72e04940d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/DurationUtils.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/DurationUtils.java
@@ -18,8 +18,6 @@
 
 package org.apache.skywalking.oap.server.core.query;
 
-import java.util.LinkedList;
-import java.util.List;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.query.enumeration.Step;
@@ -27,6 +25,9 @@
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 
+import java.util.LinkedList;
+import java.util.List;
+
 public enum DurationUtils {
     INSTANCE;
 
@@ -190,5 +191,4 @@ public void verifyDateTimeString(Step step, String dateStr) {
         }
         throw new UnexpectedException("Unsupported step " + step.name());
     }
-
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java
index cb57a5c01a65..498868109e56 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java
@@ -18,15 +18,6 @@
 
 package org.apache.skywalking.oap.server.core.query;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
@@ -44,6 +35,15 @@
 import org.apache.skywalking.oap.server.core.storage.model.StorageModels;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 @Slf4j
 public class ProcessTopologyBuilder {
     private final IComponentLibraryCatalogService componentLibraryCatalogService;
@@ -68,7 +68,7 @@ public ProcessTopologyBuilder(ModuleManager moduleManager, StorageModels storage
     }
 
     ProcessTopology build(List<Call.CallDetail> clientCalls,
-                          List<Call.CallDetail> serverCalls) throws IOException {
+                          List<Call.CallDetail> serverCalls) throws Exception {
         List<Call> calls = new LinkedList<>();
         HashMap<String, Call> callMap = new HashMap<>();
 
@@ -135,4 +135,4 @@ private ProcessNode buildNode(ProcessTraffic traffic) {
         processNode.setReal(!Objects.equals(traffic.getDetectType(), ProcessDetectType.VIRTUAL.value()));
         return processNode;
     }
-}
\ No newline at end of file
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java
index 4ed5796127ec..69ebfee476e5 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java
@@ -19,11 +19,6 @@
 package org.apache.skywalking.oap.server.core.query;
 
 import com.google.common.base.Strings;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
@@ -45,6 +40,12 @@
 import org.apache.skywalking.oap.server.library.module.Service;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 @Slf4j
 public class TopologyQueryService implements Service {
     private final ModuleManager moduleManager;
@@ -198,7 +199,7 @@ public EndpointTopology getEndpointDependencies(final Duration duration,
         return topology;
     }
 
-    public ProcessTopology getProcessTopology(final String instanceId, final Duration duration) throws IOException {
+    public ProcessTopology getProcessTopology(final String instanceId, final Duration duration) throws Exception {
         final List<Call.CallDetail> clientCalls = getTopologyQueryDAO().loadProcessRelationDetectedAtClientSide(instanceId, duration);
         final List<Call.CallDetail> serverCalls = getTopologyQueryDAO().loadProcessRelationDetectedAtServerSide(instanceId, duration);
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/Duration.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/Duration.java
index a9d16ba397d7..ff71638e1bca 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/Duration.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/Duration.java
@@ -18,13 +18,14 @@
 
 package org.apache.skywalking.oap.server.core.query.input;
 
-import java.util.List;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.skywalking.oap.server.core.query.DurationUtils;
 import org.apache.skywalking.oap.server.core.query.PointOfTime;
 import org.apache.skywalking.oap.server.core.query.enumeration.Step;
 
+import java.util.List;
+
 @Getter
 @Setter
 public class Duration {
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Alarms.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Alarms.java
index cbb125751403..b065d6aa3900 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Alarms.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Alarms.java
@@ -18,9 +18,10 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
+import lombok.Getter;
+
 import java.util.ArrayList;
 import java.util.List;
-import lombok.Getter;
 
 @Getter
 public class Alarms {
@@ -30,4 +31,8 @@ public class Alarms {
     public Alarms() {
         this.msgs = new ArrayList<>();
     }
+
+    public Alarms(List<AlarmMessage> msgs) {
+        this.msgs = msgs;
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java
index 04b5912adc1b..3d0ac0c66f85 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java
@@ -17,11 +17,14 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
 import java.util.ArrayList;
 import java.util.List;
-import lombok.Getter;
 
 @Getter
+@RequiredArgsConstructor
 public class BrowserErrorLogs {
     private final List<BrowserErrorLog> logs;
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Logs.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Logs.java
index e9d6759a50d1..523e0a69fed5 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Logs.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Logs.java
@@ -18,12 +18,13 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
-import java.util.ArrayList;
-import java.util.List;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @Setter
 @Getter
 @Accessors(chain = true)
@@ -34,4 +35,8 @@ public class Logs {
     public Logs() {
         this.logs = new ArrayList<>();
     }
+
+    public Logs(final List<Log> logs) {
+        this.logs = logs;
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Record.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Record.java
index f9ad56596454..36d5cec99ca5 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Record.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Record.java
@@ -50,4 +50,4 @@ public SelectedRecord toSelectedRecord() {
         result.setValue(getValue());
         return result;
     }
-}
\ No newline at end of file
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TraceBrief.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TraceBrief.java
index 81598bbdd45f..dbbca5154e40 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TraceBrief.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TraceBrief.java
@@ -18,9 +18,10 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
+import lombok.Getter;
+
 import java.util.ArrayList;
 import java.util.List;
-import lombok.Getter;
 
 @Getter
 public class TraceBrief {
@@ -29,4 +30,8 @@ public class TraceBrief {
     public TraceBrief() {
         this.traces = new ArrayList<>();
     }
+
+    public TraceBrief(List<BasicTrace> traces) {
+        this.traces = traces;
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/event/Events.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/event/Events.java
index a586edcd100e..8136efb77a14 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/event/Events.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/event/Events.java
@@ -18,11 +18,20 @@
 
 package org.apache.skywalking.oap.server.core.query.type.event;
 
+import lombok.Data;
+
 import java.util.ArrayList;
 import java.util.List;
-import lombok.Data;
 
 @Data
 public class Events {
-    private List<Event> events = new ArrayList<>();
+    private final List<Event> events;
+
+    public Events() {
+        events = new ArrayList<>();
+    }
+
+    public Events(List<Event> events) {
+        this.events = events;
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ScopeDefaultColumn.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ScopeDefaultColumn.java
index 61566f9f7089..3ebef71fe1c8 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ScopeDefaultColumn.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ScopeDefaultColumn.java
@@ -18,11 +18,12 @@
 
 package org.apache.skywalking.oap.server.core.source;
 
+import lombok.Getter;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import lombok.Getter;
 
 /**
  * Define the default columns of source scope. These columns pass down into the persistent entity(OAL metrics entity)
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IMetricsDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IMetricsDAO.java
index 1baee65e4cc6..c923f007a084 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IMetricsDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IMetricsDAO.java
@@ -18,15 +18,16 @@
 
 package org.apache.skywalking.oap.server.core.storage;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
 import org.apache.skywalking.oap.server.library.client.request.UpdateRequest;
 
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Metrics related DAO.
  */
@@ -39,7 +40,7 @@ public interface IMetricsDAO extends DAO {
      * @return the data of all given IDs. Only include existing data. Don't require to keep the same order of ids list.
      * @throws IOException when error occurs in data query.
      */
-    List<Metrics> multiGet(Model model, List<Metrics> metrics) throws IOException;
+    List<Metrics> multiGet(Model model, List<Metrics> metrics) throws Exception;
 
     /**
      * Transfer the given metrics to an executable insert statement.
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ShardingAlgorithm.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ShardingAlgorithm.java
deleted file mode 100644
index ad655cd0dd61..000000000000
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ShardingAlgorithm.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.skywalking.oap.server.core.storage;
-
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
-
-/**
- * The following algorithms represent different Table Sharding strategies.
- * Cooperate with tableShardingColumn and dataSourceShardingColumn which are defined in {@link SQLDatabase.Sharding}
- *
- * The DataSource sharding strategy are same:
- * If we have {dataSourceList = ds_0...ds_n} and {dataSourceShardingColumn.hashcode() % dataSourceList.size() = 2}
- * then the route target is ds_2
- *
- * The sharding number of the tables is according to TTL, One table per day:
- * {tableName = table_timeSeries}, {timeSeries = currentDate - TTL +1 ... currentDate + 1}
- * For example: if TTL=3, currentDate = 20220907, the sharding tables are:
- * Table_20220905
- * Table_20220906
- * Table_20220907
- * Table_20220908
- */
-public enum ShardingAlgorithm {
-    /**
-     * Wouldn't sharding Table nor DataSource, keep single Table.
-     */
-    NO_SHARDING,
-
-    /**
-     * Use the time_bucket inside the ID column to sharding by day.
-     * The precision of time_bucket could be second, minute, hour and day in the same table.
-     *
-     * For example, the single table `service_metrics`:
-     * ┌────────────────────────┬────────────┐
-     * │         id             │    value   │
-     * ├────────────────────────┼────────────┤
-     * │ 20220905_Service_A     │   300      │
-     * ├────────────────────────┼────────────┤
-     * │ 2022090512_Service_A   │   200      │
-     * ├────────────────────────┼────────────┤
-     * │ 202209051211_Service_A │   100      │
-     * ├────────────────────────┼────────────┤
-     * │ 20220906_Service_A     │   500      │
-     * ├────────────────────────┼────────────┤
-     * │ 2022090612_Service_A   │   300      │
-     * ├────────────────────────┼────────────┤
-     * │ 202209061211_Service_A │   100      │
-     * └────────────────────────┴────────────┘
-     *
-     * The sharding tables will be:
-     * `service_metrics_20220905`
-     * ┌────────────────────────┬────────────┐
-     * │         id             │    value   │
-     * ├────────────────────────┼────────────┤
-     * │ 20220905_Service_A     │   300      │
-     * ├────────────────────────┼────────────┤
-     * │ 2022090512_Service_A   │   200      │
-     * ├────────────────────────┼────────────┤
-     * │ 202209051211_Service_A │   100      │
-     * └────────────────────────┴────────────┘
-     * and `service_metrics_20220906`
-     * ┌────────────────────────┬────────────┐
-     * │         id             │    value   │
-     * ├────────────────────────┼────────────┤
-     * │ 20220906_Service_A     │   500      │
-     * ├────────────────────────┼────────────┤
-     * │ 2022090612_Service_A   │   300      │
-     * ├────────────────────────┼────────────┤
-     * │ 202209061211_Service_A │   100      │
-     * └────────────────────────┴────────────┘
-     *
-     */
-    TIME_RELATIVE_ID_SHARDING_ALGORITHM,
-
-    /**
-     * Use the time_bucket column to sharding by day.
-     * The precision of time_bucket should be `second`.
-     *
-     * For example, the single table `service_records`:
-     * ┌──────────────┬───────────────┬─────────┐
-     * │   Service    │  time_bucket  │  value  │
-     * ├──────────────┼───────────────┼─────────┤
-     * │   Service_A  │20220905121130 │ 300     │
-     * ├──────────────┼───────────────┼─────────┤
-     * │   Service_A  │20220906181233 │ 200     │
-     * └──────────────┴───────────────┴─────────┘
-     * The sharding tables will be:
-     * `service_records_20220905`
-     * ┌──────────────┬───────────────┬─────────┐
-     * │   Service    │  time_bucket  │  value  │
-     * ├──────────────┼───────────────┼─────────┤
-     * │   Service_A  │20220905121130 │ 300     │
-     * └──────────────┴───────────────┴─────────┘
-     * and `service_records_20220906`
-     * ┌──────────────┬───────────────┬─────────┐
-     * │   Service    │  time_bucket  │  value  │
-     * ├──────────────┼───────────────┼─────────┤
-     * │   Service_A  │20220906181233 │ 200     │
-     * └──────────────┴───────────────┴─────────┘
-     */
-    TIME_SEC_RANGE_SHARDING_ALGORITHM,
-
-    /**
-     * Use the time_bucket column to sharding by day.
-     * The precision of time_bucket should be `minute`.
-     *
-     * For example, the single table `endpoint_traffic`:
-     * ┌──────────────┬───────────────┐
-     * │   Endpoint   │  time_bucket  │
-     * ├──────────────┼───────────────┤
-     * │   Endpoint_A │202209051211   │
-     * ├──────────────┼───────────────┤
-     * │   Endpoint_B │202209061812   │
-     * └──────────────┴───────────────┘
-     * The sharding tables will be:
-     * `endpoint_traffic_20220905`
-     * ┌──────────────┬───────────────┐
-     * │   Endpoint   │  time_bucket  │
-     * ├──────────────┼───────────────┤
-     * │   Endpoint_A │202209051211   │
-     * └──────────────┴───────────────┘
-     * and `endpoint_traffic_20220906`
-     * ┌──────────────┬───────────────┐
-     * │   Endpoint   │  time_bucket  │
-     * ├──────────────┼───────────────┤
-     * │   Endpoint_B │202209061812   │
-     * └──────────────┴───────────────┘
-     */
-    TIME_MIN_RANGE_SHARDING_ALGORITHM,
-
-    /**
-     * Use the time_bucket column to sharding by day.
-     * The precision of time_bucket could be `second, minute, hour and day` in the same table.
-     * For example, the single table `service_relation`:
-     * ┌────────────────┬────────────────┐
-     * │   relation     │   time_bucket  │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 20220905       │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 2022090512     │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 202209051211   │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 20220906       │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 2022090612     │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 202209061211   │
-     * └────────────────┴────────────────┘
-     * The sharding tables will be:
-     * `service_relation_20220905`
-     * ┌────────────────┬────────────────┐
-     * │   relation     │   time_bucket  │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 20220905       │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 2022090512     │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 202209051211   │
-     * └────────────────┴────────────────┘
-     * and `endpoint_traffic_20220906`
-     * ┌────────────────┬────────────────┐
-     * │   relation     │   time_bucket  │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 20220906       │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 2022090612     │
-     * ├────────────────┼────────────────┤
-     * │   Service_A_B  │ 202209061211   │
-     * └────────────────┴────────────────┘
-     */
-    TIME_BUCKET_SHARDING_ALGORITHM
-}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/SQLDatabase.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/SQLDatabase.java
index 970cee049636..e1fdee208936 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/SQLDatabase.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/SQLDatabase.java
@@ -23,7 +23,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 
 /**
  * SQLDatabase annotation is a holder including all annotations for SQL-based RDBMS storage
@@ -32,13 +31,14 @@
  */
 public @interface SQLDatabase {
     /**
-     * QueryIndex defines the unified index is required in the query stage. This works only the storage supports this kind
-     * of index model. Mostly, work for the typical relational database, such as MySQL, TiDB.
+     * {@code CompositeIndex} defines the composite index required in the query stage.
+     * This works only when the storage supports this kind of index model, mostly,
+     * work for the typical relational database, such as MySQL, TiDB.
      */
     @Target({ElementType.FIELD})
     @Retention(RetentionPolicy.RUNTIME)
-    @Repeatable(MultipleQueryUnifiedIndex.class)
-    @interface QueryUnifiedIndex {
+    @Repeatable(CompositeIndices.class)
+    @interface CompositeIndex {
 
         /**
          * @return list of other column should be add into the unified index.
@@ -47,12 +47,12 @@
     }
 
     /**
-     * The support of the multiple {@link QueryUnifiedIndex}s on one field.
+     * The support of the multiple {@link CompositeIndex}s on one field.
      */
     @Target({ElementType.FIELD})
     @Retention(RetentionPolicy.RUNTIME)
-    @interface MultipleQueryUnifiedIndex {
-        QueryUnifiedIndex[] value();
+    @interface CompositeIndices {
+        CompositeIndex[] value();
     }
 
     /**
@@ -74,7 +74,7 @@
      * <p>
      * In H2TraceQueryDAO#queryBasicTraces query tags as condition from this additional table, could build sql like this:
      * <pre>{@code
-     *             if (!CollectionUtils.isEmpty(tags)) {
+     *         if (!CollectionUtils.isEmpty(tags)) {
      *             for (int i = 0; i < tags.size(); i++) {
      *                 sql.append(" inner join ").append(SegmentRecord.ADDITIONAL_TAG_TABLE).append(" ");
      *                 sql.append(SegmentRecord.ADDITIONAL_TAG_TABLE + i);
@@ -83,7 +83,7 @@
      *             }
      *         }
      *         ...
-     *             if (CollectionUtils.isNotEmpty(tags)) {
+     *         if (CollectionUtils.isNotEmpty(tags)) {
      *             for (int i = 0; i < tags.size(); i++) {
      *                 final int foundIdx = searchableTagKeys.indexOf(tags.get(i).getKey());
      *                 if (foundIdx > -1) {
@@ -96,11 +96,11 @@
      *                 }
      *             }
      *         }
-     *         }</pre>
+     * }</pre>
      * <p>
      * <ul>
      * <li>If no tags condition, only query segment table, the SQL should be: select
-     * column1, column2 ... from segment where 1=1 and colunm1=xx ...
+     * column1, column2 ... from segment where 1=1 and column1=xx ...
      *
      * <li> If 1 tag condition, query both segment and segment_tag tables, the SQL should be: select column1, column2 ...
      * from segment inner join segment_tag segment_tag0 on segment.id=segment_tag0.id where 1=1 and colunm1=xx ... and
@@ -108,7 +108,7 @@
      *
      * <li> If 2 or more tags condition, query both segment and segment_tag tables, the SQL should be: select column1,
      * column2 ... from segment inner join segment_tag segment_tag0 on segment.id=segment_tag0.id inner join segment_tag
-     * segment_tag1 on segment.id=segment_tag1.id ... where 1=1 and colunm1=xx ... and segment_tag0=tagString0 and
+     * segment_tag1 on segment.id=segment_tag1.id ... where 1=1 and column1=xx ... and segment_tag0=tagString0 and
      * segment_tag1=tagString1 ...
      * </ul>
      */
@@ -140,16 +140,4 @@
     @interface MultipleExtraColumn4AdditionalEntity {
         ExtraColumn4AdditionalEntity[] value();
     }
-
-    /**
-     * Support add sharding policy for a table model. Can be declared on the superclass and overridden by subclass..
-     * @since 9.3.0
-     */
-    @Target({ElementType.TYPE})
-    @Retention(RetentionPolicy.RUNTIME)
-    @interface Sharding {
-        ShardingAlgorithm shardingAlgorithm();
-        String dataSourceShardingColumn() default "";
-        String tableShardingColumn() default "";
-    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/Model.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/Model.java
index c346800d63c1..5ceb6294d26c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/Model.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/Model.java
@@ -18,52 +18,37 @@
 
 package org.apache.skywalking.oap.server.core.storage.model;
 
-import java.util.List;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
+import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
+import org.apache.skywalking.oap.server.core.analysis.record.Record;
+
+import java.util.List;
 
 /**
  * The model definition of a logic entity.
  */
 @Getter
 @EqualsAndHashCode
+@RequiredArgsConstructor
 public class Model {
     private final String name;
     private final List<ModelColumn> columns;
     private final int scopeId;
     private final DownSampling downsampling;
-    private final boolean record;
     private final boolean superDataset;
-    private final boolean isTimeSeries;
     private final Class<?> streamClass;
     private final boolean timeRelativeID;
     private final SQLDatabaseModelExtension sqlDBModelExtension;
     private final BanyanDBModelExtension banyanDBModelExtension;
     private final ElasticSearchModelExtension elasticSearchModelExtension;
 
-    public Model(final String name,
-                 final List<ModelColumn> columns,
-                 final int scopeId,
-                 final DownSampling downsampling,
-                 final boolean record,
-                 final boolean superDataset,
-                 final Class<?> streamClass,
-                 boolean timeRelativeID,
-                 final SQLDatabaseModelExtension sqlDBModelExtension,
-                 final BanyanDBModelExtension banyanDBModelExtension,
-                 final ElasticSearchModelExtension elasticSearchModelExtension) {
-        this.name = name;
-        this.columns = columns;
-        this.scopeId = scopeId;
-        this.downsampling = downsampling;
-        this.isTimeSeries = !DownSampling.None.equals(downsampling);
-        this.record = record;
-        this.superDataset = superDataset;
-        this.streamClass = streamClass;
-        this.timeRelativeID = timeRelativeID;
-        this.sqlDBModelExtension = sqlDBModelExtension;
-        this.banyanDBModelExtension = banyanDBModelExtension;
-        this.elasticSearchModelExtension = elasticSearchModelExtension;
-    }
+    @Getter(lazy = true)
+    private final boolean isMetric = Metrics.class.isAssignableFrom(getStreamClass());
+    @Getter(lazy = true)
+    private final boolean isRecord = Record.class.isAssignableFrom(getStreamClass());
+    @Getter(lazy = true)
+    private final boolean isTimeSeries = !DownSampling.None.equals(getDownsampling());
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelColumn.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelColumn.java
index 2683b9f93ebf..bfc5ba322193 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelColumn.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelColumn.java
@@ -18,11 +18,12 @@
 
 package org.apache.skywalking.oap.server.core.storage.model;
 
-import java.lang.reflect.Type;
 import lombok.Getter;
 import lombok.ToString;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 
+import java.lang.reflect.Type;
+
 @Getter
 @ToString
 public class ModelColumn {
@@ -49,19 +50,19 @@ public class ModelColumn {
      *
      * @since 9.1.0
      */
-    private SQLDatabaseExtension sqlDatabaseExtension;
+    private final SQLDatabaseExtension sqlDatabaseExtension;
     /**
      * Hold configurations especially for ElasticSearch
      *
      * @since 9.1.0
      */
-    private ElasticSearchExtension elasticSearchExtension;
+    private final ElasticSearchExtension elasticSearchExtension;
     /**
      * Hold configurations especially for BanyanDB relevant
      *
      * @since 9.1.0
      */
-    private BanyanDBExtension banyanDBExtension;
+    private final BanyanDBExtension banyanDBExtension;
 
     public ModelColumn(ColumnName columnName,
                        Class<?> type,
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelCreator.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelCreator.java
index 3f75a75401bd..f8d46e8ad144 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelCreator.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/ModelCreator.java
@@ -31,7 +31,7 @@ public interface ModelCreator extends Service {
      *
      * @return the created new model
      */
-    Model add(Class<?> aClass, int scopeId, Storage storage, boolean record) throws StorageException;
+    Model add(Class<?> aClass, int scopeId, Storage storage) throws StorageException;
 
     void addModelListener(CreatingListener listener) throws StorageException;
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/SQLDatabaseModelExtension.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/SQLDatabaseModelExtension.java
index b7c7313083e0..b826d7c1ff26 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/SQLDatabaseModelExtension.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/SQLDatabaseModelExtension.java
@@ -18,17 +18,15 @@
 
 package org.apache.skywalking.oap.server.core.storage.model;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
 import lombok.AccessLevel;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
-import lombok.Setter;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * @since 9.1.0
@@ -40,9 +38,6 @@ public class SQLDatabaseModelExtension {
     //exclude the columns from the main table
     private final List<ModelColumn> excludeColumns = new ArrayList<>(5);
 
-    @Setter
-    private Optional<Sharding> sharding = Optional.empty();
-
     public void appendAdditionalTable(String tableName, ModelColumn column) {
         additionalTables.computeIfAbsent(tableName, AdditionalTable::new)
                         .appendColumn(column);
@@ -52,10 +47,6 @@ public void appendExcludeColumns(ModelColumn column) {
         excludeColumns.add(column);
     }
 
-    public boolean isShardingTable() {
-        return this.sharding.isPresent() && !this.sharding.get().getShardingAlgorithm().equals(ShardingAlgorithm.NO_SHARDING);
-    }
-
     @Getter
     @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
     public static class AdditionalTable {
@@ -73,12 +64,4 @@ public void appendColumn(ModelColumn column) {
             columns.add(column);
         }
     }
-
-    @Getter
-    @RequiredArgsConstructor
-    public static class Sharding {
-        private final ShardingAlgorithm shardingAlgorithm;
-        private final String dataSourceShardingColumn;
-        private final String tableShardingColumn;
-    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java
index b9df523b5cf2..c76d820ae12c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java
@@ -17,15 +17,8 @@
 
 package org.apache.skywalking.oap.server.core.storage.model;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
 import org.apache.skywalking.oap.server.core.storage.StorageException;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
@@ -36,6 +29,14 @@
 import org.apache.skywalking.oap.server.core.storage.annotation.SuperDataset;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
 /**
  * StorageModels manages all models detected by the core.
  */
@@ -52,7 +53,7 @@ public StorageModels() {
     }
 
     @Override
-    public Model add(Class<?> aClass, int scopeId, Storage storage, boolean record) throws StorageException {
+    public Model add(Class<?> aClass, int scopeId, Storage storage) throws StorageException {
         // Check this scope id is valid.
         DefaultScopeDefine.nameOf(scopeId);
 
@@ -61,7 +62,7 @@ public Model add(Class<?> aClass, int scopeId, Storage storage, boolean record)
         SQLDatabaseModelExtension sqlDBModelExtension = new SQLDatabaseModelExtension();
         BanyanDBModelExtension banyanDBModelExtension = new BanyanDBModelExtension();
         ElasticSearchModelExtension elasticSearchModelExtension = new ElasticSearchModelExtension();
-        retrieval(aClass, storage.getModelName(), modelColumns, scopeId, checker, sqlDBModelExtension, record);
+        retrieval(aClass, storage.getModelName(), modelColumns, scopeId, checker, sqlDBModelExtension);
         // Add extra column for additional entities
         if (aClass.isAnnotationPresent(SQLDatabase.ExtraColumn4AdditionalEntity.class)
             || aClass.isAnnotationPresent(SQLDatabase.MultipleExtraColumn4AdditionalEntity.class)) {
@@ -107,7 +108,6 @@ public Model add(Class<?> aClass, int scopeId, Storage storage, boolean record)
             modelColumns,
             scopeId,
             storage.getDownsampling(),
-            record,
             isSuperDatasetModel(aClass),
             aClass,
             storage.isTimeRelativeID(),
@@ -130,7 +130,7 @@ private boolean isSuperDatasetModel(Class<?> aClass) {
     }
 
     /**
-     * CreatingListener listener could react when {@link #add(Class, int, Storage, boolean)} model happens. Also, the
+     * CreatingListener listener could react when {@link ModelCreator#add(Class, int, Storage)} model happens. Also, the
      * added models are being notified in this add operation.
      */
     @Override
@@ -149,8 +149,7 @@ private void retrieval(final Class<?> clazz,
                            final List<ModelColumn> modelColumns,
                            final int scopeId,
                            ShardingKeyChecker checker,
-                           final SQLDatabaseModelExtension sqlDBModelExtension,
-                           boolean record) {
+                           final SQLDatabaseModelExtension sqlDBModelExtension) {
         if (log.isDebugEnabled()) {
             log.debug("Analysis {} to generate Model.", clazz.getName());
         }
@@ -160,7 +159,7 @@ private void retrieval(final Class<?> clazz,
         for (Field field : fields) {
             if (field.isAnnotationPresent(Column.class)) {
                 if (field.isAnnotationPresent(SQLDatabase.AdditionalEntity.class)) {
-                    if (!record) {
+                    if (!Record.class.isAssignableFrom(clazz)) {
                         throw new IllegalStateException(
                             "Model [" + modelName + "] is not a Record, @SQLDatabase.AdditionalEntity only supports Record.");
                     }
@@ -173,14 +172,14 @@ private void retrieval(final Class<?> clazz,
 
                 // SQL Database extension
                 SQLDatabaseExtension sqlDatabaseExtension = new SQLDatabaseExtension();
-                List<SQLDatabase.QueryUnifiedIndex> indexDefinitions = new ArrayList<>();
-                if (field.isAnnotationPresent(SQLDatabase.QueryUnifiedIndex.class)) {
-                    indexDefinitions.add(field.getAnnotation(SQLDatabase.QueryUnifiedIndex.class));
+                List<SQLDatabase.CompositeIndex> indexDefinitions = new ArrayList<>();
+                if (field.isAnnotationPresent(SQLDatabase.CompositeIndex.class)) {
+                    indexDefinitions.add(field.getAnnotation(SQLDatabase.CompositeIndex.class));
                 }
 
-                if (field.isAnnotationPresent(SQLDatabase.MultipleQueryUnifiedIndex.class)) {
+                if (field.isAnnotationPresent(SQLDatabase.CompositeIndices.class)) {
                     Collections.addAll(
-                        indexDefinitions, field.getAnnotation(SQLDatabase.MultipleQueryUnifiedIndex.class).value());
+                        indexDefinitions, field.getAnnotation(SQLDatabase.CompositeIndices.class).value());
                 }
 
                 indexDefinitions.forEach(indexDefinition -> {
@@ -239,11 +238,12 @@ private void retrieval(final Class<?> clazz,
                 }
 
                 if (field.isAnnotationPresent(SQLDatabase.AdditionalEntity.class)) {
-                    String[] tableNames = field.getAnnotation(SQLDatabase.AdditionalEntity.class).additionalTables();
-                    for (final String tableName : tableNames) {
+                    final var additionalEntity = field.getAnnotation(SQLDatabase.AdditionalEntity.class);
+                    final var additionalTableNames = additionalEntity.additionalTables();
+                    for (final var tableName : additionalTableNames) {
                         sqlDBModelExtension.appendAdditionalTable(tableName, modelColumn);
                     }
-                    if (!field.getAnnotation(SQLDatabase.AdditionalEntity.class).reserveOriginalColumns()) {
+                    if (!additionalEntity.reserveOriginalColumns()) {
                         sqlDBModelExtension.appendExcludeColumns(modelColumn);
                     }
                 }
@@ -261,19 +261,8 @@ private void retrieval(final Class<?> clazz,
             }
         }
 
-        // For the annotation need to be declared on the superclass, the other annotation should be declared on the subclass.
-        if (!sqlDBModelExtension.getSharding().isPresent() && clazz.isAnnotationPresent(SQLDatabase.Sharding.class)) {
-            SQLDatabase.Sharding sharding = clazz.getAnnotation(SQLDatabase.Sharding.class);
-            sqlDBModelExtension.setSharding(
-                Optional.of(new SQLDatabaseModelExtension.Sharding(
-                    sharding.shardingAlgorithm(),
-                    sharding.dataSourceShardingColumn(),
-                    sharding.tableShardingColumn()
-                )));
-        }
-
         if (Objects.nonNull(clazz.getSuperclass())) {
-            retrieval(clazz.getSuperclass(), modelName, modelColumns, scopeId, checker, sqlDBModelExtension, record);
+            retrieval(clazz.getSuperclass(), modelName, modelColumns, scopeId, checker, sqlDBModelExtension);
         }
     }
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IZipkinQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IZipkinQueryDAO.java
index 0331f28babde..d7fb3b45ba11 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IZipkinQueryDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IZipkinQueryDAO.java
@@ -18,14 +18,15 @@
 
 package org.apache.skywalking.oap.server.core.storage.query;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.storage.DAO;
 import zipkin2.Span;
 import zipkin2.storage.QueryRequest;
 
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
 public interface IZipkinQueryDAO extends DAO {
     List<String> getServiceNames() throws IOException;
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ttl/DataTTLKeeperTimer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ttl/DataTTLKeeperTimer.java
index ebe5b45e0e0a..9d7d3627ef10 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ttl/DataTTLKeeperTimer.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/ttl/DataTTLKeeperTimer.java
@@ -18,13 +18,7 @@
 
 package org.apache.skywalking.oap.server.core.storage.ttl;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.server.library.util.RunnableWithExceptionProtection;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
@@ -37,6 +31,13 @@
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.library.util.RunnableWithExceptionProtection;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 /**
  * TTL = Time To Live
@@ -98,7 +99,8 @@ private void execute(Model model) {
             }
             if (log.isDebugEnabled()) {
                 log.debug(
-                    "Is record? {}. RecordDataTTL {}, MetricsDataTTL {}",
+                    "Model {}, is record? {}. RecordDataTTL {}, MetricsDataTTL {}",
+                    model.getName(),
                     model.isRecord(),
                     moduleConfig.getRecordDataTTL(),
                     moduleConfig.getMetricsDataTTL());
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceRelationTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceRelationTraffic.java
index f54b4e25ce25..30aeb407d240 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceRelationTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceRelationTraffic.java
@@ -27,11 +27,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -43,7 +41,6 @@
     "serviceName",
     "remoteServiceName"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ZipkinServiceRelationTraffic extends Metrics {
 
     public static final String INDEX_NAME = "zipkin_service_relation_traffic";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceSpanTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceSpanTraffic.java
index 1ca5f3ef09ae..2681815a1e70 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceSpanTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceSpanTraffic.java
@@ -28,11 +28,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -44,7 +42,6 @@
     "serviceName",
     "spanName"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ZipkinServiceSpanTraffic extends Metrics {
 
     public static final String INDEX_NAME = "zipkin_service_span_traffic";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceTraffic.java
index d8b1388406b1..338cb72fd7ab 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceTraffic.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinServiceTraffic.java
@@ -28,11 +28,9 @@
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
@@ -43,7 +41,6 @@
 @EqualsAndHashCode(of = {
     "serviceName"
 })
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
 public class ZipkinServiceTraffic extends Metrics {
     public static final String INDEX_NAME = "zipkin_service_traffic";
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinSpanRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinSpanRecord.java
index 01e8d5459027..2723fd16f85a 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinSpanRecord.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/zipkin/ZipkinSpanRecord.java
@@ -28,7 +28,6 @@
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
 import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
@@ -46,13 +45,11 @@
 import java.util.List;
 import java.util.Map;
 
-import static org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord.TRACE_ID;
 import static org.apache.skywalking.oap.server.core.analysis.record.Record.TIME_BUCKET;
 
 @SuperDataset
 @Stream(name = ZipkinSpanRecord.INDEX_NAME, scopeId = DefaultScopeDefine.ZIPKIN_SPAN, builder = ZipkinSpanRecord.Builder.class, processor = RecordStreamProcessor.class)
 @SQLDatabase.ExtraColumn4AdditionalEntity(additionalTable = ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE, parentColumn = TIME_BUCKET)
-@SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.TIME_SEC_RANGE_SHARDING_ALGORITHM, dataSourceShardingColumn = TRACE_ID, tableShardingColumn = TIME_BUCKET)
 @BanyanDB.TimestampColumn(ZipkinSpanRecord.TIMESTAMP_MILLIS)
 public class ZipkinSpanRecord extends Record {
     private static final Gson GSON = new Gson();
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/hikaricp/JDBCClient.java b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/hikaricp/JDBCClient.java
new file mode 100644
index 000000000000..49539fb62605
--- /dev/null
+++ b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/hikaricp/JDBCClient.java
@@ -0,0 +1,187 @@
+/*
+ * 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.skywalking.oap.server.library.client.jdbc.hikaricp;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.library.client.Client;
+import org.apache.skywalking.oap.server.library.client.healthcheck.DelegatedHealthChecker;
+import org.apache.skywalking.oap.server.library.client.healthcheck.HealthCheckable;
+import org.apache.skywalking.oap.server.library.util.HealthChecker;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * JDBC Client uses HikariCP connection management lib to execute SQL.
+ */
+@Slf4j
+public class JDBCClient implements Client, HealthCheckable {
+    private final HikariConfig hikariConfig;
+    private final DelegatedHealthChecker healthChecker;
+    private HikariDataSource dataSource;
+
+    public JDBCClient(Properties properties) {
+        hikariConfig = new HikariConfig(properties);
+        healthChecker = new DelegatedHealthChecker();
+    }
+
+    @Override
+    public void connect() {
+        dataSource = new HikariDataSource(hikariConfig);
+    }
+
+    @Override
+    public void shutdown() {
+        dataSource.close();
+    }
+
+    /**
+     * Default getConnection is set in auto-commit.
+     */
+    public Connection getConnection() throws SQLException {
+        return getConnection(true);
+    }
+
+    public Connection getConnection(boolean autoCommit) throws SQLException {
+        Connection connection = dataSource.getConnection();
+        connection.setAutoCommit(autoCommit);
+        return connection;
+    }
+
+    public void execute(String sql) throws SQLException {
+        if (log.isDebugEnabled()) {
+            log.debug("Executing SQL: {}", sql);
+        }
+
+        try (final var connection = getConnection();
+             final var statement = connection.createStatement()) {
+            statement.execute(sql);
+            statement.closeOnCompletion();
+            healthChecker.health();
+        } catch (SQLException e) {
+            healthChecker.unHealth(e);
+            throw e;
+        }
+    }
+
+    public int executeUpdate(String sql, Object... params) throws SQLException {
+        if (log.isDebugEnabled()) {
+            log.debug("Executing SQL: {}", sql);
+            log.debug("SQL parameters: {}", params);
+        }
+
+        try (final var connection = getConnection();
+             final var statement = connection.prepareStatement(sql)) {
+            setStatementParam(statement, params);
+            int result = statement.executeUpdate();
+            statement.closeOnCompletion();
+            healthChecker.health();
+            return result;
+        } catch (SQLException e) {
+            healthChecker.unHealth(e);
+            throw e;
+        }
+    }
+
+    public <T> T executeQuery(String sql, ResultHandler<T> resultHandler, Object... params) throws SQLException {
+        if (log.isDebugEnabled()) {
+            log.debug("Executing SQL: {}", sql);
+            log.debug("SQL parameters: {}", Arrays.toString(params));
+        }
+        try (final var connection = getConnection();
+             final var statement = connection.prepareStatement(sql)) {
+            setStatementParam(statement, params);
+            try (final var rs = statement.executeQuery()) {
+                healthChecker.health();
+                return resultHandler.handle(rs);
+            }
+        } catch (SQLException e) {
+            healthChecker.unHealth(e);
+            throw e;
+        }
+    }
+
+    private void setStatementParam(PreparedStatement statement, Object[] params) throws SQLException {
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                Object param = params[i];
+                if (param instanceof String) {
+                    statement.setString(i + 1, (String) param);
+                } else if (param instanceof Integer) {
+                    statement.setInt(i + 1, (int) param);
+                } else if (param instanceof Double) {
+                    statement.setDouble(i + 1, (double) param);
+                } else if (param instanceof Long) {
+                    statement.setLong(i + 1, (long) param);
+                } else {
+                    throw new SQLException("Unsupported data type, type=" + param.getClass().getName());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void registerChecker(HealthChecker healthChecker) {
+        this.healthChecker.register(healthChecker);
+    }
+
+    public boolean indexExists(final String table,
+                               final String index) throws SQLException {
+        try (final var connection = getConnection();
+             final var resultSet = connection.getMetaData().getIndexInfo(null, null, table, false, false)) {
+            while (resultSet.next()) {
+                if (resultSet.getString("INDEX_NAME").equalsIgnoreCase(index)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean tableExists(final String table) throws SQLException {
+        try (final var conn = getConnection();
+             final var result = conn.getMetaData().getTables(null, null, table, null)) {
+            return result.next();
+        }
+    }
+
+    public Set<String> getTableColumns(final String table) throws SQLException {
+        try (final var conn = getConnection();
+             final var result = conn.getMetaData().getColumns(null, null, table, null)) {
+            final var columns = new HashSet<String>();
+            while (result.next()) {
+                columns.add(result.getString("COLUMN_NAME").toLowerCase());
+            }
+            return columns;
+        }
+    }
+
+    @FunctionalInterface
+    public interface ResultHandler<T> {
+        T handle(ResultSet resultSet) throws SQLException;
+    }
+}
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/hikaricp/JDBCHikariCPClient.java b/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/hikaricp/JDBCHikariCPClient.java
deleted file mode 100644
index 03bc7416f85b..000000000000
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/hikaricp/JDBCHikariCPClient.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.skywalking.oap.server.library.client.jdbc.hikaricp;
-
-import com.zaxxer.hikari.HikariConfig;
-import com.zaxxer.hikari.HikariDataSource;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Properties;
-import org.apache.skywalking.oap.server.library.client.Client;
-import org.apache.skywalking.oap.server.library.client.healthcheck.DelegatedHealthChecker;
-import org.apache.skywalking.oap.server.library.client.healthcheck.HealthCheckable;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.util.HealthChecker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * JDBC Client uses HikariCP connection management lib to execute SQL.
- */
-public class JDBCHikariCPClient implements Client, HealthCheckable {
-    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCHikariCPClient.class);
-
-    private final HikariConfig hikariConfig;
-    private final DelegatedHealthChecker healthChecker;
-    private HikariDataSource dataSource;
-
-    public JDBCHikariCPClient(Properties properties) {
-        hikariConfig = new HikariConfig(properties);
-        this.healthChecker = new DelegatedHealthChecker();
-    }
-
-    @Override
-    public void connect() {
-        dataSource = new HikariDataSource(hikariConfig);
-    }
-
-    @Override
-    public void shutdown() {
-        dataSource.close();
-    }
-
-    /**
-     * Default getConnection is set in auto-commit.
-     */
-    public Connection getConnection() throws JDBCClientException {
-        return getConnection(true);
-    }
-
-    public Connection getConnection(boolean autoCommit) throws JDBCClientException {
-        try {
-            Connection connection = dataSource.getConnection();
-            connection.setAutoCommit(autoCommit);
-            return connection;
-        } catch (SQLException e) {
-            throw new JDBCClientException(e.getMessage(), e);
-        }
-    }
-
-    public void execute(Connection connection, String sql) throws JDBCClientException {
-        LOGGER.debug("execute sql: {}", sql);
-        try (Statement statement = connection.createStatement()) {
-            statement.execute(sql);
-            healthChecker.health();
-        } catch (SQLException e) {
-            healthChecker.unHealth(e);
-            throw new JDBCClientException(e.getMessage(), e);
-        }
-    }
-
-    public int executeUpdate(Connection connection, String sql, Object... params) throws JDBCClientException {
-        LOGGER.debug("execute query with result: {}", sql);
-        int result;
-        PreparedStatement statement = null;
-        try {
-            statement = connection.prepareStatement(sql);
-            setStatementParam(statement, params);
-            result = statement.executeUpdate();
-            statement.closeOnCompletion();
-            healthChecker.health();
-        } catch (SQLException e) {
-            if (statement != null) {
-                try {
-                    statement.close();
-                } catch (SQLException e1) {
-                }
-            }
-            healthChecker.unHealth(e);
-            throw new JDBCClientException(e.getMessage(), e);
-        }
-
-        return result;
-    }
-
-    public ResultSet executeQuery(Connection connection, String sql, Object... params) throws JDBCClientException {
-        LOGGER.debug("execute query with result: {}", sql);
-        ResultSet rs;
-        PreparedStatement statement = null;
-        try {
-            statement = connection.prepareStatement(sql);
-            setStatementParam(statement, params);
-            rs = statement.executeQuery();
-            statement.closeOnCompletion();
-            healthChecker.health();
-        } catch (SQLException e) {
-            if (statement != null) {
-                try {
-                    statement.close();
-                } catch (SQLException e1) {
-                }
-            }
-            healthChecker.unHealth(e);
-            throw new JDBCClientException(sql, e);
-        }
-
-        return rs;
-    }
-
-    private void setStatementParam(PreparedStatement statement,
-        Object[] params) throws SQLException, JDBCClientException {
-        if (params != null) {
-            for (int i = 0; i < params.length; i++) {
-                Object param = params[i];
-                if (param instanceof String) {
-                    statement.setString(i + 1, (String) param);
-                } else if (param instanceof Integer) {
-                    statement.setInt(i + 1, (int) param);
-                } else if (param instanceof Double) {
-                    statement.setDouble(i + 1, (double) param);
-                } else if (param instanceof Long) {
-                    statement.setLong(i + 1, (long) param);
-                } else {
-                    throw new JDBCClientException("Unsupported data type, type=" + param.getClass().getName());
-                }
-            }
-        }
-    }
-
-    @Override public void registerChecker(HealthChecker healthChecker) {
-        this.healthChecker.register(healthChecker);
-    }
-}
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java
index 47d2f8633fc3..8aaf9db95d43 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLExprQueryVisitor.java
@@ -287,7 +287,7 @@ private void queryTopN(String metricName,
                                                     Optional.ofNullable(selectedRecord.getName()), Optional.empty()
             );
             metricData.setMetric(metricInfo);
-            metricData.setValues(buildMatrixValues(duration, selectedRecord.getValue()));
+            metricData.setValues(buildMatrixValues(duration, String.valueOf(selectedRecord.getValue())));
             matrixResult.getMetricDataList().add(metricData);
         }
     }
@@ -306,7 +306,7 @@ private void queryRecords(String metricName,
                                                     Optional.ofNullable(record.getName())
             );
             metricData.setMetric(metricInfo);
-            metricData.setValues(buildMatrixValues(duration, record.getValue()));
+            metricData.setValues(buildMatrixValues(duration, String.valueOf(record.getValue())));
             matrixResult.getMetricDataList().add(metricData);
         }
     }
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/EBPFProcessProfilingQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/EBPFProcessProfilingQuery.java
index 80ffec376a55..f94f3b48f954 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/EBPFProcessProfilingQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/EBPFProcessProfilingQuery.java
@@ -66,7 +66,7 @@ public List<EBPFProfilingTask> queryEBPFProfilingTasks(String serviceId, String
         return getQueryService().queryEBPFProfilingTasks(serviceId, serviceInstanceId, targets);
     }
 
-    public List<EBPFProfilingSchedule> queryEBPFProfilingSchedules(String taskId) throws IOException {
+    public List<EBPFProfilingSchedule> queryEBPFProfilingSchedules(String taskId) throws Exception {
         return getQueryService().queryEBPFProfilingSchedules(taskId);
     }
 
@@ -75,4 +75,4 @@ public EBPFProfilingAnalyzation analysisEBPFProfilingResult(List<String> schedul
                                                                 EBPFProfilingAnalyzeAggregateType aggregateType) throws IOException {
         return getQueryService().getEBPFProfilingAnalyzation(scheduleIdList, timeRanges, aggregateType);
     }
-}
\ No newline at end of file
+}
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopNRecordsQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopNRecordsQuery.java
index d0ecb2ca3cc8..8c5945fe81bb 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopNRecordsQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopNRecordsQuery.java
@@ -19,9 +19,6 @@
 package org.apache.skywalking.oap.query.graphql.resolver;
 
 import graphql.kickstart.tools.GraphQLQueryResolver;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import org.apache.skywalking.oap.query.graphql.type.TopNRecordsCondition;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.query.input.TopNCondition;
@@ -29,6 +26,10 @@
 import org.apache.skywalking.oap.server.core.query.type.TopNRecord;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * @since 8.0.0 This query is replaced by {@link MetricsQuery}, all queries have been delegated to there.
  */
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java
index 853498588010..4c4b99aab5a6 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java
@@ -83,7 +83,7 @@ public EndpointTopology getEndpointDependencies(final String endpointId,
         return getQueryService().getEndpointDependencies(duration, endpointId);
     }
 
-    public ProcessTopology getProcessTopology(final String instanceId, final Duration duration) throws IOException {
+    public ProcessTopology getProcessTopology(final String instanceId, final Duration duration) throws Exception {
         return getQueryService().getProcessTopology(instanceId, duration);
     }
 }
diff --git a/oap-server/server-starter/pom.xml b/oap-server/server-starter/pom.xml
index f439fbfeb5bf..7a74feb531f9 100644
--- a/oap-server/server-starter/pom.xml
+++ b/oap-server/server-starter/pom.xml
@@ -192,21 +192,11 @@
             <artifactId>storage-jdbc-hikaricp-plugin</artifactId>
             <version>${project.version}</version>
         </dependency>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>storage-tidb-plugin</artifactId>
-            <version>${project.version}</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
             <artifactId>storage-banyandb-plugin</artifactId>
             <version>${project.version}</version>
         </dependency>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>storage-shardingsphere-plugin</artifactId>
-            <version>${project.version}</version>
-        </dependency>
         <!-- storage module -->
 
         <!-- queryBuild module -->
diff --git a/oap-server/server-starter/src/main/resources/application.yml b/oap-server/server-starter/src/main/resources/application.yml
index c69f7d92b9a6..9ec171eeea07 100644
--- a/oap-server/server-starter/src/main/resources/application.yml
+++ b/oap-server/server-starter/src/main/resources/application.yml
@@ -175,14 +175,14 @@ storage:
     enableCustomRouting: ${SW_STORAGE_ES_ENABLE_CUSTOM_ROUTING:false}
   h2:
     properties:
-      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1}
+      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE}
       dataSource.user: ${SW_STORAGE_H2_USER:sa}
     metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
     maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:100}
     asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:1}
   mysql:
     properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true"}
+      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true&allowMultiQueries=true"}
       dataSource.user: ${SW_DATA_SOURCE_USER:root}
       dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root@1234}
       dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
@@ -192,30 +192,6 @@ storage:
     metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
     maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
     asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}
-  mysql-sharding:
-    properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:13307/swtest?rewriteBatchedStatements=true"}
-      dataSource.user: ${SW_DATA_SOURCE_USER:root}
-      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}
-    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
-    maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
-    asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}
-    # The dataSources are configured in ShardingSphere-Proxy config-sharding.yaml.
-    # The dataSource name should include the prefix "ds_" and separated by "," and start from ds_0
-    dataSources: ${SW_JDBC_SHARDING_DATA_SOURCES:ds_0,ds_1}
-  tidb:
-    properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:4000/tidbswtest?rewriteBatchedStatements=true"}
-      dataSource.user: ${SW_DATA_SOURCE_USER:root}
-      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:""}
-      dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
-      dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
-      dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
-      dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
-      dataSource.useAffectedRows: ${SW_DATA_SOURCE_USE_AFFECTED_ROWS:true}
-    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
-    maxSizeOfBatchSql: ${SW_STORAGE_MAX_SIZE_OF_BATCH_SQL:2000}
-    asyncBatchPersistentPoolSize: ${SW_STORAGE_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4}
   postgresql:
     properties:
       jdbcUrl: ${SW_JDBC_URL:"jdbc:postgresql://localhost:5432/skywalking"}
diff --git a/oap-server/server-storage-plugin/pom.xml b/oap-server/server-storage-plugin/pom.xml
index c1fa68a95522..80c2cdd5e204 100644
--- a/oap-server/server-storage-plugin/pom.xml
+++ b/oap-server/server-storage-plugin/pom.xml
@@ -30,8 +30,6 @@
     <modules>
         <module>storage-jdbc-hikaricp-plugin</module>
         <module>storage-elasticsearch-plugin</module>
-        <module>storage-tidb-plugin</module>
         <module>storage-banyandb-plugin</module>
-        <module>storage-shardingsphere-plugin</module>
     </modules>
 </project>
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexController.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexController.java
index ee150027a36a..5a5b8cfa9bff 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexController.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/IndexController.java
@@ -18,23 +18,22 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
+import com.google.common.base.Strings;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.FunctionCategory;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
-import com.google.common.base.Strings;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
 
 /**
  * The metrics data, that generated by OAL or MAL, would be partitioned to storage by the functions of the OAL or MAL.
@@ -56,8 +55,8 @@ public enum IndexController {
 
     public String getTableName(Model model) {
         if (!logicSharding) {
-            return isMetricModel(model) ? "metrics-all" :
-                (isRecordModel(model) && !model.isSuperDataset() ? "records-all" : model.getName());
+            return model.isMetric() ? "metrics-all" :
+                (model.isRecord() && !model.isSuperDataset() ? "records-all" : model.getName());
         }
         String aggFuncName = FunctionCategory.uniqueFunctionName(model.getStreamClass());
         return StringUtil.isNotBlank(aggFuncName) ? aggFuncName : model.getName();
@@ -68,10 +67,10 @@ public String getTableName(Model model) {
      * to avoid conflicts.
      */
     public String generateDocId(Model model, String originalID) {
-        if (!logicSharding && isRecordModel(model) && !model.isSuperDataset()) {
+        if (!logicSharding && model.isRecord() && !model.isSuperDataset()) {
             return this.generateDocId(model.getName(), originalID);
         }
-        if (!isMetricModel(model)) {
+        if (!model.isMetric()) {
             return originalID;
         }
         if (logicSharding && !isFunctionMetric(model)) {
@@ -87,17 +86,6 @@ public String generateDocId(String logicTableName, String originalID) {
         return logicTableName + Const.ID_CONNECTOR + originalID;
     }
 
-    /**
-     * Check the mode of the Model definition.
-     */
-    public boolean isMetricModel(Model model) {
-        return Metrics.class.isAssignableFrom(model.getStreamClass());
-    }
-
-    public boolean isRecordModel(Model model) {
-        return Record.class.isAssignableFrom(model.getStreamClass());
-    }
-
     public boolean isFunctionMetric(Model model) {
         return StringUtil.isNotBlank(FunctionCategory.uniqueFunctionName(model.getStreamClass()));
     }
@@ -114,10 +102,10 @@ public boolean isFunctionMetric(Model model) {
      * The value of the column is the original table name in other storages.
      */
     public Map<String, Object> appendTableColumn(Model model, Map<String, Object> columns) {
-        if ((!isLogicSharding() && isMetricModel(model)) || (isLogicSharding() && isFunctionMetric(model))) {
+        if ((!isLogicSharding() && model.isMetric()) || (isLogicSharding() && isFunctionMetric(model))) {
             columns.put(LogicIndicesRegister.METRIC_TABLE_NAME, model.getName());
         }
-        if (!logicSharding && isRecordModel(model) && !model.isSuperDataset()) {
+        if (!logicSharding && model.isRecord() && !model.isSuperDataset()) {
             columns.put(LogicIndicesRegister.RECORD_TABLE_NAME, model.getName());
         }
         return columns;
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java
index 5252e3e1075d..5632d6d46e25 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsInstaller.java
@@ -18,6 +18,11 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base;
 
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.library.elasticsearch.response.Index;
 import org.apache.skywalking.library.elasticsearch.response.IndexTemplate;
 import org.apache.skywalking.library.elasticsearch.response.Mappings;
@@ -33,17 +38,13 @@
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.StorageModuleElasticsearchConfig;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.google.common.base.Strings;
-import com.google.gson.Gson;
+
 import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 public class StorageEsInstaller extends ModelInstaller {
@@ -267,7 +268,7 @@ protected Map<String, Object> createSetting(Model model) throws StorageException
     private Map getAnalyzerSetting(Model model) throws StorageException {
         if (config.isLogicSharding() || !model.isTimeSeries()) {
             return getAnalyzerSettingByColumn(model);
-        } else if (IndexController.INSTANCE.isRecordModel(model) && model.isSuperDataset()) {
+        } else if (model.isRecord() && model.isSuperDataset()) {
             //SuperDataset doesn't merge index, the analyzer follow the column config.
             return getAnalyzerSettingByColumn(model);
         } else {
@@ -338,13 +339,13 @@ protected Mappings createMapping(Model model) {
             }
         }
 
-        if ((IndexController.INSTANCE.isMetricModel(model) && !config.isLogicSharding())
+        if ((model.isMetric() && !config.isLogicSharding())
             || (config.isLogicSharding() && IndexController.INSTANCE.isFunctionMetric(model))) {
             Map<String, Object> column = new HashMap<>();
             column.put("type", "keyword");
             properties.put(IndexController.LogicIndicesRegister.METRIC_TABLE_NAME, column);
         }
-        if (!config.isLogicSharding() && IndexController.INSTANCE.isRecordModel(model) && !model.isSuperDataset()) {
+        if (!config.isLogicSharding() && model.isRecord() && !model.isSuperDataset()) {
             Map<String, Object> column = new HashMap<>();
             column.put("type", "keyword");
             properties.put(IndexController.LogicIndicesRegister.RECORD_TABLE_NAME, column);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
index e99d6a64175d..3fd19217ed00 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
@@ -18,9 +18,6 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
 import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
 import org.apache.skywalking.library.elasticsearch.requests.search.Query;
 import org.apache.skywalking.library.elasticsearch.requests.search.RangeQueryBuilder;
@@ -43,6 +40,10 @@
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.TimeRangeIndexNameGenerator;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 public class AggregationQueryEsDAO extends EsDAO implements IAggregationQueryDAO {
 
     public AggregationQueryEsDAO(ElasticSearchClient client) {
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java
index 5eaa18275f09..f2f61681088d 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ESEventQueryDAO.java
@@ -18,10 +18,6 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
 import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
 import org.apache.skywalking.library.elasticsearch.requests.search.Query;
 import org.apache.skywalking.library.elasticsearch.requests.search.Search;
@@ -30,6 +26,7 @@
 import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
 import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
+import org.apache.skywalking.oap.server.core.analysis.metrics.Event;
 import org.apache.skywalking.oap.server.core.query.PaginationUtils;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
@@ -37,13 +34,17 @@
 import org.apache.skywalking.oap.server.core.query.type.event.EventType;
 import org.apache.skywalking.oap.server.core.query.type.event.Events;
 import org.apache.skywalking.oap.server.core.query.type.event.Source;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Event;
 import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
 
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static java.util.Objects.isNull;
 
@@ -69,11 +70,10 @@ private Events getEventsResultByCurrentBuilder(final SearchBuilder searchBuilder
         final String index =
             IndexController.LogicIndicesRegister.getPhysicalTableName(Event.INDEX_NAME);
         final SearchResponse response = getClient().search(index, searchBuilder.build());
-        final Events events = new Events();
-        events.setEvents(response.getHits().getHits().stream()
-                                 .map(this::parseSearchHit)
-                                 .collect(Collectors.toList()));
-        return events;
+        return new Events(
+            response.getHits().getHits().stream()
+                    .map(this::parseSearchHit)
+                    .collect(Collectors.toList()));
     }
 
     private void buildMustQueryListByCondition(final EventQueryCondition condition,
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java
index dc25175c2ced..e2e0be0a6238 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java
@@ -18,13 +18,6 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.skywalking.oap.server.core.query.input.RecordCondition;
-import org.apache.skywalking.oap.server.core.query.type.Record;
 import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
 import org.apache.skywalking.library.elasticsearch.requests.search.Query;
 import org.apache.skywalking.library.elasticsearch.requests.search.Search;
@@ -35,12 +28,19 @@
 import org.apache.skywalking.oap.server.core.analysis.topn.TopN;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
+import org.apache.skywalking.oap.server.core.query.input.RecordCondition;
+import org.apache.skywalking.oap.server.core.query.type.Record;
 import org.apache.skywalking.oap.server.core.storage.query.IRecordsQueryDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 public class RecordsQueryEsDAO extends EsDAO implements IRecordsQueryDAO {
     public RecordsQueryEsDAO(ElasticSearchClient client) {
         super(client);
@@ -83,7 +83,7 @@ public List<Record> readRecords(final RecordCondition condition,
             final String refId = (String) sourceAsMap.get(TopN.TRACE_ID);
             record.setRefId(StringUtil.isEmpty(refId) ? "" : refId);
             record.setId(record.getRefId());
-            record.setValue(sourceAsMap.get(valueColumnName).toString());
+            record.setValue(sourceAsMap.getOrDefault(valueColumnName, "0").toString());
             results.add(record);
         }
 
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/pom.xml b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/pom.xml
index e73fb090c167..9bb11f774a4d 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/pom.xml
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/pom.xml
@@ -48,14 +48,15 @@
             <groupId>com.h2database</groupId>
             <artifactId>h2</artifactId>
         </dependency>
-<!--        <dependency>-->
-<!--        <groupId>mysql</groupId>-->
-<!--        <artifactId>mysql-connector-java</artifactId>-->
-<!--        <version>8.0.13</version>-->
-<!--        </dependency>-->
         <dependency>
             <groupId>org.postgresql</groupId>
             <artifactId>postgresql</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/BatchSQLExecutor.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/BatchSQLExecutor.java
index 4061ae7405d8..ea4993d9a94e 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/BatchSQLExecutor.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/BatchSQLExecutor.java
@@ -18,44 +18,50 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc;
 
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
 import org.apache.skywalking.oap.server.library.client.request.PrepareRequest;
 import org.apache.skywalking.oap.server.library.client.request.UpdateRequest;
 
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A Batch SQL executor.
  */
 @Slf4j
 @RequiredArgsConstructor
 public class BatchSQLExecutor implements InsertRequest, UpdateRequest {
-
+    private final JDBCClient jdbcClient;
     private final List<PrepareRequest> prepareRequests;
 
-    public void invoke(Connection connection, int maxBatchSqlSize) throws SQLException {
+    public void invoke(int maxBatchSqlSize) throws Exception {
         if (log.isDebugEnabled()) {
             log.debug("execute sql batch. sql by key size: {}", prepareRequests.size());
         }
         if (prepareRequests.size() == 0) {
             return;
         }
-        String sql = prepareRequests.get(0).toString();
-        List<PrepareRequest> bulkRequest = new ArrayList<>(maxBatchSqlSize);
-        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
-            int pendingCount = 0;
-            for (int k = 0; k < prepareRequests.size(); k++) {
-                SQLExecutor sqlExecutor = (SQLExecutor) prepareRequests.get(k);
+        final var sql = prepareRequests.get(0).toString();
+        final var bulkRequest = new ArrayList<PrepareRequest>(maxBatchSqlSize);
+        try (final var connection = jdbcClient.getConnection();
+             final var preparedStatement = connection.prepareStatement(sql)) {
+            var pendingCount = 0;
+            for (final var prepareRequest : prepareRequests) {
+                final var sqlExecutor = (SQLExecutor) prepareRequest;
+                if (log.isDebugEnabled()) {
+                    log.debug("Executing sql: {}", sql);
+                    log.debug("SQL parameters: {}", sqlExecutor.getParam());
+                }
                 sqlExecutor.setParameters(preparedStatement);
                 preparedStatement.addBatch();
                 bulkRequest.add(sqlExecutor);
-                if (k > 0 && k % maxBatchSqlSize == 0) {
+                if (bulkRequest.size() == maxBatchSqlSize) {
                     executeBatch(preparedStatement, maxBatchSqlSize, sql, bulkRequest);
                     bulkRequest.clear();
                     pendingCount = 0;
@@ -74,9 +80,9 @@ private void executeBatch(PreparedStatement preparedStatement,
                               int pendingCount,
                               String sql,
                               List<PrepareRequest> bulkRequest) throws SQLException {
-        long start = System.currentTimeMillis();
-        final int[] executeBatchResults = preparedStatement.executeBatch();
-        boolean isInsert = bulkRequest.get(0) instanceof InsertRequest;
+        final var start = System.currentTimeMillis();
+        final var executeBatchResults = preparedStatement.executeBatch();
+        final var isInsert = bulkRequest.get(0) instanceof InsertRequest;
         for (int i = 0; i < executeBatchResults.length; i++) {
             if (executeBatchResults[i] == 1 && isInsert) {
                 // Insert successfully.
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLBuilder.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLBuilder.java
index c3456805921d..7c60ffe2f49b 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLBuilder.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLBuilder.java
@@ -22,17 +22,16 @@
  * SQLBuilder
  */
 public class SQLBuilder {
-    private static String LINE_END = System.lineSeparator();
+    private static final String LINE_END = System.lineSeparator();
 
-    private StringBuilder text;
+    private final StringBuilder text;
 
     public SQLBuilder() {
-        this.text = new StringBuilder();
+        text = new StringBuilder();
     }
 
-    public SQLBuilder(String initLine) {
-        this();
-        this.appendLine(initLine);
+    public SQLBuilder(String initText) {
+        text = new StringBuilder(initText);
     }
 
     public SQLBuilder append(String fragment) {
@@ -45,10 +44,6 @@ public SQLBuilder appendLine(String line) {
         return this;
     }
 
-    public String toStringInNewLine() {
-        return LINE_END + toString();
-    }
-
     @Override
     public String toString() {
         return text.toString();
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLExecutor.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLExecutor.java
index 266350eb457c..f6b2ef037b23 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLExecutor.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/SQLExecutor.java
@@ -18,11 +18,6 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc;
 
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
@@ -31,6 +26,12 @@
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
 import org.apache.skywalking.oap.server.library.client.request.UpdateRequest;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A SQL executor.
  */
@@ -39,16 +40,17 @@
 @Slf4j
 public class SQLExecutor implements InsertRequest, UpdateRequest {
     private final String sql;
+    @Getter
     private final List<Object> param;
     private final SessionCacheCallback callback;
     @Getter
     private List<SQLExecutor> additionalSQLs;
 
     public void invoke(Connection connection) throws SQLException {
-        PreparedStatement preparedStatement = connection.prepareStatement(sql);
+        final var preparedStatement = connection.prepareStatement(sql);
         setParameters(preparedStatement);
         if (log.isDebugEnabled()) {
-            log.debug("execute sql in batch: {}, parameters: {}", sql, param);
+            log.debug("Executing sql in batch: {}, parameters: {}", sql, param);
         }
         preparedStatement.execute();
         if (additionalSQLs != null) {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/TableMetaInfo.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/TableMetaInfo.java
index 0df86b272c44..559d7cf391a8 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/TableMetaInfo.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/TableMetaInfo.java
@@ -18,16 +18,17 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc;
 
+import org.apache.skywalking.oap.server.core.storage.model.Model;
+
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
 
 /**
  * Consider there additional table columns need to remove from model columns, SQL storage implementation
  * should get model from here.
  */
 public class TableMetaInfo {
-    private static Map<String, Model> TABLES = new HashMap<>();
+    private static final Map<String, Model> TABLES = new HashMap<>();
 
     public static void addModel(Model model) {
         // remove exclude columns according to @SQLDatabase.AdditionalEntity
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/mysql/MySQLShardingStorageConfig.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCEntityConverters.java
similarity index 53%
rename from oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/mysql/MySQLShardingStorageConfig.java
rename to oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCEntityConverters.java
index 984071584ac5..61084c5ad949 100644
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/mysql/MySQLShardingStorageConfig.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCEntityConverters.java
@@ -16,24 +16,27 @@
  *
  */
 
-package org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.mysql;
+package org.apache.skywalking.oap.server.storage.plugin.jdbc.common;
 
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.skywalking.oap.server.core.Const;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCStorageConfig;
-import com.google.common.base.Splitter;
-import lombok.Setter;
+import lombok.SneakyThrows;
+import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
 
-@Setter
-public class MySQLShardingStorageConfig extends JDBCStorageConfig {
-    private String dataSources = Const.EMPTY_STRING;
+import java.sql.ResultSet;
 
-    public Set<String> getDataSources() {
-        if (StringUtils.isEmpty(this.dataSources)) {
-            return null;
-        }
-        return new HashSet<>(Splitter.on(",").splitToList(this.dataSources));
+public class JDBCEntityConverters {
+    public static Convert2Entity toEntity(ResultSet resultSet) {
+        return new Convert2Entity() {
+            @Override
+            @SneakyThrows
+            public Object get(String fieldName) {
+                return resultSet.getObject(fieldName);
+            }
+
+            @Override
+            @SneakyThrows
+            public byte[] getBytes(String fieldName) {
+                return resultSet.getBytes(fieldName);
+            }
+        };
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCStorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCStorageProvider.java
index 8a8a10815ca0..669b1a7075db 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCStorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCStorageProvider.java
@@ -43,13 +43,13 @@
 import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IRecordsQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.ISpanAttachedEventQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.ITagAutoCompleteQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.IRecordsQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.ITopologyQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.ITraceQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.query.IZipkinQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.module.ModuleDefine;
 import org.apache.skywalking.oap.server.library.module.ModuleProvider;
 import org.apache.skywalking.oap.server.library.module.ModuleStartException;
@@ -84,10 +84,13 @@
 import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
 import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
 
+import java.time.Clock;
+
 public abstract class JDBCStorageProvider extends ModuleProvider {
     protected JDBCStorageConfig config;
-    protected JDBCHikariCPClient jdbcClient;
-    protected ModelInstaller modelInstaller;
+    protected JDBCClient jdbcClient;
+    protected JDBCTableInstaller modelInstaller;
+    protected TableHelper tableHelper;
 
     /**
      * Different storage implementations have different ways to create the tables/indices,
@@ -117,8 +120,9 @@ public void onInitialized(final JDBCStorageConfig initialized) {
 
     @Override
     public void prepare() throws ServiceNotProvidedException, ModuleStartException {
-        jdbcClient = new JDBCHikariCPClient(config.getProperties());
-        modelInstaller = createModelInstaller();
+        jdbcClient = new JDBCClient(config.getProperties());
+        modelInstaller = (JDBCTableInstaller) createModelInstaller();
+        tableHelper = new TableHelper(getManager(), jdbcClient);
 
         this.registerServiceImplementation(
             StorageBuilderFactory.class,
@@ -136,77 +140,77 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
 
         this.registerServiceImplementation(
             INetworkAddressAliasDAO.class,
-            new JDBCNetworkAddressAliasDAO(jdbcClient));
+            new JDBCNetworkAddressAliasDAO(jdbcClient, getManager()));
 
         this.registerServiceImplementation(
             ITopologyQueryDAO.class,
-            new JDBCTopologyQueryDAO(jdbcClient));
+            new JDBCTopologyQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IMetricsQueryDAO.class,
-            new JDBCMetricsQueryDAO(jdbcClient));
+            new JDBCMetricsQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             ITraceQueryDAO.class,
-            new JDBCTraceQueryDAO(getManager(), jdbcClient));
+            new JDBCTraceQueryDAO(getManager(), jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IBrowserLogQueryDAO.class,
-            new JDBCBrowserLogQueryDAO(jdbcClient));
+            new JDBCBrowserLogQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IMetadataQueryDAO.class,
-            new JDBCMetadataQueryDAO(jdbcClient, config.getMetadataQueryMaxSize()));
+            new JDBCMetadataQueryDAO(jdbcClient, config.getMetadataQueryMaxSize(), getManager()));
         this.registerServiceImplementation(
             IAggregationQueryDAO.class,
-            new JDBCAggregationQueryDAO(jdbcClient));
+            new JDBCAggregationQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IAlarmQueryDAO.class,
-            new JDBCAlarmQueryDAO(jdbcClient, getManager()));
+            new JDBCAlarmQueryDAO(jdbcClient, getManager(), tableHelper));
         this.registerServiceImplementation(
             IHistoryDeleteDAO.class,
-            new JDBCHistoryDeleteDAO(jdbcClient));
+            new JDBCHistoryDeleteDAO(jdbcClient, tableHelper, modelInstaller, Clock.systemDefaultZone()));
         this.registerServiceImplementation(
             IRecordsQueryDAO.class,
-            new JDBCRecordsQueryDAO(jdbcClient));
+            new JDBCRecordsQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             ILogQueryDAO.class,
-            new JDBCLogQueryDAO(jdbcClient, getManager()));
+            new JDBCLogQueryDAO(jdbcClient, getManager(), tableHelper));
 
         this.registerServiceImplementation(
             IProfileTaskQueryDAO.class,
-            new JDBCProfileTaskQueryDAO(jdbcClient));
+            new JDBCProfileTaskQueryDAO(jdbcClient, getManager()));
         this.registerServiceImplementation(
             IProfileTaskLogQueryDAO.class,
-            new JDBCProfileTaskLogQueryDAO(jdbcClient));
+            new JDBCProfileTaskLogQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IProfileThreadSnapshotQueryDAO.class,
-            new JDBCProfileThreadSnapshotQueryDAO(jdbcClient));
+            new JDBCProfileThreadSnapshotQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             UITemplateManagementDAO.class,
-            new JDBCUITemplateManagementDAO(jdbcClient));
+            new JDBCUITemplateManagementDAO(jdbcClient, tableHelper));
 
         this.registerServiceImplementation(
             IEventQueryDAO.class,
-            new JDBCEventQueryDAO(jdbcClient));
+            new JDBCEventQueryDAO(jdbcClient, tableHelper));
 
         this.registerServiceImplementation(
             IEBPFProfilingTaskDAO.class,
-            new JDBCEBPFProfilingTaskDAO(jdbcClient));
+            new JDBCEBPFProfilingTaskDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IEBPFProfilingScheduleDAO.class,
-            new JDBCEBPFProfilingScheduleDAO(jdbcClient));
+            new JDBCEBPFProfilingScheduleDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IEBPFProfilingDataDAO.class,
-            new JDBCEBPFProfilingDataDAO(jdbcClient));
+            new JDBCEBPFProfilingDataDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IServiceLabelDAO.class,
-            new JDBCServiceLabelQueryDAO(jdbcClient));
+            new JDBCServiceLabelQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             ITagAutoCompleteQueryDAO.class,
-            new JDBCTagAutoCompleteQueryDAO(jdbcClient));
+            new JDBCTagAutoCompleteQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IZipkinQueryDAO.class,
-            new JDBCZipkinQueryDAO(jdbcClient));
+            new JDBCZipkinQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             ISpanAttachedEventQueryDAO.class,
-            new JDBCSpanAttachedEventQueryDAO(jdbcClient));
+            new JDBCSpanAttachedEventQueryDAO(jdbcClient, tableHelper));
     }
 
     @Override
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java
new file mode 100644
index 000000000000..956aec65853c
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/JDBCTableInstaller.java
@@ -0,0 +1,277 @@
+/*
+ * 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.skywalking.oap.server.storage.plugin.jdbc.common;
+
+import com.google.gson.JsonObject;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.analysis.Layer;
+import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
+import org.apache.skywalking.oap.server.core.storage.model.ColumnName;
+import org.apache.skywalking.oap.server.core.storage.model.Model;
+import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
+import org.apache.skywalking.oap.server.core.storage.model.ModelInstaller;
+import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
+import org.apache.skywalking.oap.server.library.client.Client;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import static java.util.function.Predicate.not;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+
+/**
+ * JDBC table installer, uses standard SQL to create tables, indices, and views.
+ */
+@Slf4j
+public class JDBCTableInstaller extends ModelInstaller {
+    public static final String ID_COLUMN = Metrics.ID;
+    public static final String TABLE_COLUMN = "table_name";
+
+    public JDBCTableInstaller(Client client, ModuleManager moduleManager) {
+        super(client, moduleManager);
+    }
+
+    @Override
+    @SneakyThrows
+    public boolean isExists(Model model) {
+        TableMetaInfo.addModel(model);
+
+        final var table = TableHelper.getLatestTableForWrite(model);
+
+        final var jdbcClient = (JDBCClient) client;
+        if (!jdbcClient.tableExists(table)) {
+            return false;
+        }
+
+        final var databaseColumns = getDatabaseColumns(table);
+        final var isAnyColumnNotCreated =
+            model
+                .getColumns().stream()
+                .map(ModelColumn::getColumnName)
+                .map(ColumnName::getStorageName)
+                .anyMatch(not(databaseColumns::contains));
+
+        return !isAnyColumnNotCreated;
+    }
+
+    @Override
+    @SneakyThrows
+    public void createTable(Model model) {
+        final var table = TableHelper.getLatestTableForWrite(model);
+        createTable(model, table);
+    }
+
+    @SneakyThrows
+    public void createTable(Model model, String table) {
+        createOrUpdateTable(table, model.getColumns(), false);
+        createOrUpdateTableIndexes(table, model.getColumns(), false);
+        createAdditionalTable(model);
+    }
+
+    public String getColumnDefinition(ModelColumn column) {
+        return getColumnDefinition(column, column.getType(), column.getGenericType());
+    }
+
+    protected String getColumnDefinition(ModelColumn column, Class<?> type, Type genericType) {
+        final String storageName = column.getColumnName().getStorageName();
+        if (Integer.class.equals(type) || int.class.equals(type) || Layer.class.equals(type)) {
+            return storageName + " INT";
+        } else if (Long.class.equals(type) || long.class.equals(type)) {
+            return storageName + " BIGINT";
+        } else if (Double.class.equals(type) || double.class.equals(type)) {
+            return storageName + " DOUBLE";
+        } else if (String.class.equals(type)) {
+            return storageName + " VARCHAR(" + column.getLength() + ")";
+        } else if (StorageDataComplexObject.class.isAssignableFrom(type)) {
+            return storageName + " VARCHAR(20000)";
+        } else if (byte[].class.equals(type)) {
+            return storageName + " MEDIUMTEXT";
+        } else if (JsonObject.class.equals(type)) {
+            return storageName + " VARCHAR(" + column.getLength() + ")";
+        } else if (List.class.isAssignableFrom(type)) {
+            final Type elementType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
+            return getColumnDefinition(column, (Class<?>) elementType, elementType);
+        } else {
+            throw new IllegalArgumentException("Unsupported data type: " + type.getName());
+        }
+    }
+
+    public void createOrUpdateTableIndexes(String table, List<ModelColumn> columns,
+                                           boolean isAdditionalTable) throws SQLException {
+        final var jdbcClient = (JDBCClient) client;
+
+        // Additional table's id is a many-to-one relation to the main table's id,
+        // and thus can not be primary key, but a simple index.
+        if (isAdditionalTable) {
+            final var index = "idx_" + Math.abs((table + "_" + JDBCTableInstaller.ID_COLUMN).hashCode());
+            if (!jdbcClient.indexExists(table, index)) {
+                executeSQL(
+                    new SQLBuilder("CREATE INDEX ")
+                        .append(index)
+                        .append(" ON ").append(table)
+                        .append("(")
+                        .append(ID_COLUMN)
+                        .append(")")
+                );
+            }
+        }
+
+        if (!isAdditionalTable) {
+            final var index = "idx_" + Math.abs((table + "_" + JDBCTableInstaller.TABLE_COLUMN).hashCode());
+            if (!jdbcClient.indexExists(table, index)) {
+                executeSQL(
+                    new SQLBuilder("CREATE INDEX ")
+                        .append(index)
+                        .append(" ON ")
+                        .append(table)
+                        .append("(")
+                        .append(JDBCTableInstaller.TABLE_COLUMN)
+                        .append(")")
+                );
+            }
+        }
+
+        final var columnsMissingIndex =
+            columns
+                .stream()
+                .filter(ModelColumn::shouldIndex)
+                .filter(it -> it.getLength() < 256)
+                .map(ModelColumn::getColumnName)
+                .map(ColumnName::getStorageName)
+                .collect(toList());
+        for (var column : columnsMissingIndex) {
+            final var index = "idx_" + Math.abs((table + "_" + column).hashCode());
+            if (!jdbcClient.indexExists(table, index)) {
+                executeSQL(
+                    new SQLBuilder("CREATE INDEX ")
+                        .append(index)
+                        .append(" ON ").append(table).append("(")
+                        .append(column)
+                        .append(")")
+                );
+            }
+        }
+
+        final var columnNames =
+            columns
+                .stream()
+                .map(ModelColumn::getColumnName)
+                .map(ColumnName::getStorageName)
+                .collect(toSet());
+        for (final var modelColumn : columns) {
+            for (final var compositeIndex : modelColumn.getSqlDatabaseExtension().getIndices()) {
+                final var multiColumns = Arrays.asList(compositeIndex.getColumns());
+                // Don't create composite index on the additional table if it doesn't contain all needed columns.
+                if (isAdditionalTable && !columnNames.containsAll(multiColumns)) {
+                    continue;
+                }
+                final var index = "idx_" + Math.abs((table + "_" + String.join("_", multiColumns)).hashCode());
+                if (jdbcClient.indexExists(table, index)) {
+                    continue;
+                }
+                executeSQL(
+                    new SQLBuilder("CREATE INDEX ")
+                        .append(index)
+                        .append(" ON ")
+                        .append(table)
+                        .append(multiColumns.stream().collect(joining(", ", " (", ")")))
+                );
+            }
+        }
+    }
+
+    public void executeSQL(SQLBuilder sql) throws SQLException {
+        final var c = (JDBCClient) client;
+        c.execute(sql.toString());
+    }
+
+    public void createAdditionalTable(Model model) throws SQLException {
+        final var additionalTables = model.getSqlDBModelExtension().getAdditionalTables();
+        for (final var table : additionalTables.values()) {
+            final var tableName = TableHelper.getLatestTableForWrite(table.getName());
+            createOrUpdateTable(tableName, table.getColumns(), true);
+            createOrUpdateTableIndexes(tableName, table.getColumns(), true);
+        }
+    }
+
+    @SneakyThrows
+    public void createOrUpdateTable(String table, List<ModelColumn> columns, boolean isAdditionalTable) {
+        // Some SQL implementations don't have the syntax "alter table <table> add column if not exists",
+        // we have to query the columns and filter out the existing ones.
+        final var columnsToBeAdded = new ArrayList<>(columns);
+        final var existingColumns = getDatabaseColumns(table);
+        columnsToBeAdded.removeIf(it -> existingColumns.contains(it.getColumnName().getStorageName()));
+
+        final var jdbcClient = (JDBCClient) client;
+        if (!jdbcClient.tableExists(table)) {
+            createTable(table, columnsToBeAdded, isAdditionalTable);
+        } else {
+            updateTable(table, columnsToBeAdded);
+        }
+    }
+
+    protected Set<String> getDatabaseColumns(String table) throws SQLException {
+        final var jdbcClient = (JDBCClient) client;
+        return jdbcClient.getTableColumns(table);
+    }
+
+    private void updateTable(String table, List<ModelColumn> columns) throws SQLException {
+        final var alterSqls =
+            columns
+                .stream()
+                .map(this::getColumnDefinition)
+                .map(definition -> "ALTER TABLE " + table + " ADD COLUMN " + definition + "; ")
+                .collect(toList());
+
+        for (String alterSql : alterSqls) {
+            executeSQL(new SQLBuilder(alterSql));
+        }
+    }
+
+    private void createTable(String table, List<ModelColumn> columns, boolean isAdditionalTable) throws SQLException {
+        final var columnDefinitions = new ArrayList<String>();
+        columnDefinitions.add(ID_COLUMN + " VARCHAR(512)" + (!isAdditionalTable ? " PRIMARY KEY" : ""));
+        if (!isAdditionalTable) {
+            columnDefinitions.add(TABLE_COLUMN + " VARCHAR(512)");
+        }
+        columns
+            .stream()
+            .map(this::getColumnDefinition)
+            .collect(toCollection(() -> columnDefinitions));
+
+        final var sql =
+            new SQLBuilder("CREATE TABLE IF NOT EXISTS " + table)
+                .append(columnDefinitions.stream().collect(joining(", ", " (", ");")));
+
+        executeSQL(sql);
+    }
+}
diff --git a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/JDBCClientException.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/SQLAndParameters.java
similarity index 63%
rename from oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/JDBCClientException.java
rename to oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/SQLAndParameters.java
index d88a85e16f2e..15c3c4df0941 100644
--- a/oap-server/server-library/library-client/src/main/java/org/apache/skywalking/oap/server/library/client/jdbc/JDBCClientException.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/SQLAndParameters.java
@@ -16,18 +16,24 @@
  *
  */
 
-package org.apache.skywalking.oap.server.library.client.jdbc;
+package org.apache.skywalking.oap.server.storage.plugin.jdbc.common;
 
-import java.io.IOException;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.experimental.Accessors;
 
-public class JDBCClientException extends IOException {
+import java.util.List;
 
-    public JDBCClientException(String message) {
-        super(message);
-    }
+@Accessors(fluent = true)
+@RequiredArgsConstructor
+public class SQLAndParameters {
+    @Getter
+    private final String sql;
+    @NonNull
+    private final List<Object> parameters;
 
-    public JDBCClientException(String message, Throwable cause) {
-        super(message, cause);
+    public Object[] parameters() {
+        return parameters.toArray();
     }
 }
-
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/TableHelper.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/TableHelper.java
new file mode 100644
index 000000000000..cac5de380e09
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/TableHelper.java
@@ -0,0 +1,183 @@
+/*
+ * 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.skywalking.oap.server.storage.plugin.jdbc.common;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Range;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.DownSampling;
+import org.apache.skywalking.oap.server.core.analysis.FunctionCategory;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
+import org.apache.skywalking.oap.server.core.config.ConfigService;
+import org.apache.skywalking.oap.server.core.storage.model.Model;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.LongStream;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Utility class to get table name for a given model.
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class TableHelper {
+    private final ModuleManager moduleManager;
+    private final JDBCClient jdbcClient;
+
+    @Getter(lazy = true, value = AccessLevel.PRIVATE)
+    private final ConfigService configService = moduleManager.find(CoreModule.NAME).provider().getService(ConfigService.class);
+
+    private final LoadingCache<String, Boolean> tableExistence =
+        CacheBuilder.newBuilder()
+                    .expireAfterAccess(Duration.ofMinutes(10))
+                    .build(new CacheLoader<>() {
+                        @Override
+                        public @NonNull Boolean load(@NonNull String tableName) throws Exception {
+                            return jdbcClient.tableExists(tableName);
+                        }
+                    });
+
+    public static String getTableName(Model model) {
+        final var aggFuncName = FunctionCategory.uniqueFunctionName(model.getStreamClass()).replaceAll("-", "_");
+        return StringUtil.isNotBlank(aggFuncName) ? aggFuncName : model.getName();
+    }
+
+    public static String getLatestTableForWrite(Model model) {
+        final var tableName = getTableName(model);
+
+        if (!model.isTimeSeries()) {
+            return tableName;
+        }
+
+        final var dayTimeBucket = TimeBucket.getTimeBucket(System.currentTimeMillis(), DownSampling.Day);
+        return tableName + Const.UNDERSCORE + dayTimeBucket;
+    }
+
+    /**
+     * @param rawTableName the table name without time bucket suffix.
+     * @return the table name with time bucket.
+     */
+    public static String getLatestTableForWrite(String rawTableName) {
+        final var dayTimeBucket = TimeBucket.getTimeBucket(System.currentTimeMillis(), DownSampling.Day);
+        return rawTableName + Const.UNDERSCORE + dayTimeBucket;
+    }
+
+    public static String getTable(Model model, long timeBucket) {
+        final var tableName = getTableName(model);
+        if (timeBucket == 0) {
+            timeBucket = TimeBucket.getTimeBucket(System.currentTimeMillis(), DownSampling.Day);
+        }
+
+        if (!model.isTimeSeries()) {
+            return tableName;
+        }
+
+        return tableName + Const.UNDERSCORE + TimeBucket.getTimeBucket(TimeBucket.getTimestamp(timeBucket), DownSampling.Day);
+    }
+
+    public static String getTable(String rawTableName, long timeBucket) {
+        if (timeBucket == 0) {
+            timeBucket = TimeBucket.getTimeBucket(System.currentTimeMillis(), DownSampling.Day);
+        }
+
+        return rawTableName + Const.UNDERSCORE + TimeBucket.getTimeBucket(TimeBucket.getTimestamp(timeBucket), DownSampling.Day);
+    }
+
+    public List<String> getTablesForRead(String modelName, long timeBucketStart, long timeBucketEnd) {
+        final var model = TableMetaInfo.get(modelName);
+        final var tableName = getTableName(model);
+
+        if (!model.isTimeSeries()) {
+            return Collections.singletonList(tableName);
+        }
+
+        timeBucketStart = TimeBucket.getTimeBucket(TimeBucket.getTimestamp(timeBucketStart), DownSampling.Day);
+        timeBucketEnd = TimeBucket.getTimeBucket(TimeBucket.getTimestamp(timeBucketEnd), DownSampling.Day);
+
+        final var ttlTimeBucketRange = getTTLTimeBucketRange(model);
+
+        return LongStream
+            .rangeClosed(timeBucketStart, timeBucketEnd)
+            .distinct()
+            .filter(ttlTimeBucketRange::contains)
+            .mapToObj(it -> tableName + "_" + it)
+            .filter(table -> {
+                try {
+                    return tableExistence.get(table);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            })
+            .collect(toList());
+    }
+
+    public List<String> getTablesWithinTTL(String modelName) {
+        final var model = TableMetaInfo.get(modelName);
+        final var range = getTTLTimeBucketRange(model);
+        return getTablesForRead(modelName, range.lowerEndpoint(), range.upperEndpoint());
+    }
+
+    public static String generateId(Model model, String originalID) {
+        if (model.isRecord() && !model.isSuperDataset()) {
+            return generateId(model.getName(), originalID);
+        }
+        if (!model.isMetric() || !isFunctionMetric(model)) {
+            return originalID;
+        }
+        return generateId(model.getName(), originalID);
+    }
+
+    public static String generateId(String modelName, String originalID) {
+        return modelName + Const.ID_CONNECTOR + originalID;
+    }
+
+    public static boolean isFunctionMetric(Model model) {
+        return StringUtil.isNotBlank(FunctionCategory.uniqueFunctionName(model.getStreamClass()));
+    }
+
+    public static long getTimeBucket(String table) {
+        final var split = table.split("_");
+        return Long.parseLong(split[split.length - 1]);
+    }
+
+    Range<Long> getTTLTimeBucketRange(Model model) {
+        final var ttl = model.isRecord() ?
+            getConfigService().getRecordDataTTL() :
+            getConfigService().getMetricsDataTTL();
+        final var timeBucketEnd = TimeBucket.getTimeBucket(System.currentTimeMillis(), DownSampling.Day);
+        final var timeBucketStart = TimeBucket.getTimeBucket(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(ttl), DownSampling.Day);
+        return Range.closed(timeBucketStart, timeBucketEnd);
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAggregationQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAggregationQueryDAO.java
index 61925653e352..53b138a3b622 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAggregationQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAggregationQueryDAO.java
@@ -18,13 +18,8 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
@@ -32,60 +27,103 @@
 import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.query.type.SelectedRecord;
 import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.comparing;
+import static java.util.stream.Collectors.groupingBy;
 
 @RequiredArgsConstructor
 public class JDBCAggregationQueryDAO implements IAggregationQueryDAO {
-    protected final JDBCHikariCPClient jdbcClient;
+    protected final JDBCClient jdbcClient;
+    protected final TableHelper tableHelper;
 
     @Override
+    @SneakyThrows
     public List<SelectedRecord> sortMetrics(final TopNCondition metrics,
                                             final String valueColumnName,
                                             final Duration duration,
-                                            List<KeyValue> additionalConditions) throws IOException {
-        List<Object> conditions = new ArrayList<>(10);
-        StringBuilder sql = buildMetricsValueSql(valueColumnName, metrics.getName());
-        sql.append(Metrics.TIME_BUCKET).append(" >= ? and ").append(Metrics.TIME_BUCKET).append(" <= ?");
-        conditions.add(duration.getStartTimeBucket());
-        conditions.add(duration.getEndTimeBucket());
-        if (additionalConditions != null) {
-            additionalConditions.forEach(condition -> {
-                sql.append(" and ").append(condition.getKey()).append("=?");
-                conditions.add(condition.getValue());
+                                            final List<KeyValue> additionalConditions) {
+        final var results = new ArrayList<SelectedRecord>();
+        final var tables = tableHelper.getTablesForRead(
+            metrics.getName(), duration.getStartTimeBucket(), duration.getEndTimeBucket()
+        );
+
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQL(metrics, valueColumnName, duration, additionalConditions, table);
+
+            jdbcClient.executeQuery(sqlAndParameters.sql(), resultSet -> {
+                while (resultSet.next()) {
+                    final var topNEntity = new SelectedRecord();
+                    topNEntity.setId(resultSet.getString(Metrics.ENTITY_ID));
+                    topNEntity.setValue(String.valueOf(resultSet.getInt("result")));
+                    results.add(topNEntity);
+                }
+                return null;
+            }, sqlAndParameters.parameters());
+        }
+
+        final var comparator =
+            Order.ASC.equals(metrics.getOrder()) ?
+                comparing((SelectedRecord it) -> Long.parseLong(it.getValue())) :
+                comparing((SelectedRecord it) -> Long.parseLong(it.getValue())).reversed();
+        return results
+            .stream()
+            .collect(groupingBy(SelectedRecord::getId))
+            .entrySet()
+            .stream()
+            .map(entry -> {
+                final var selectedRecord = new SelectedRecord();
+                final var average = (int) entry.getValue().stream().map(SelectedRecord::getValue).mapToLong(Long::parseLong).average().orElse(0);
+                selectedRecord.setId(entry.getKey());
+                selectedRecord.setValue(String.valueOf(average));
+                return selectedRecord;
+            })
+            .sorted(comparator)
+            .limit(metrics.getTopN())
+            .collect(Collectors.toList());
+    }
+
+    protected SQLAndParameters buildSQL(
+        final TopNCondition metrics,
+        final String valueColumnName,
+        final Duration duration,
+        final List<KeyValue> queries,
+        final String table) {
+
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>(10);
+        sql.append("select result, ").append(Metrics.ENTITY_ID)
+           .append(" from (select avg(").append(valueColumnName).append(") as result,")
+           .append(Metrics.ENTITY_ID)
+           .append(" from ").append(table)
+           .append(" where ")
+           .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?")
+           .append(" and ")
+           .append(Metrics.TIME_BUCKET).append(" >= ? ")
+           .append(" and ")
+           .append(Metrics.TIME_BUCKET).append(" <= ?");
+
+        parameters.add(metrics.getName());
+        parameters.add(duration.getStartTimeBucket());
+        parameters.add(duration.getEndTimeBucket());
+        if (queries != null) {
+            queries.forEach(query -> {
+                sql.append(" and ").append(query.getKey()).append(" = ?");
+                parameters.add(query.getValue());
             });
         }
         sql.append(" group by ").append(Metrics.ENTITY_ID);
         sql.append(")  as T order by result")
-           .append(metrics.getOrder().equals(Order.ASC) ? " asc" : " desc")
+           .append(Order.ASC.equals(metrics.getOrder()) ? " asc" : " desc")
            .append(" limit ")
            .append(metrics.getTopN());
-        List<SelectedRecord> topNEntities = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection();
-             ResultSet resultSet = jdbcClient.executeQuery(
-                 connection, sql.toString(), conditions.toArray(new Object[0]))) {
-            while (resultSet.next()) {
-                SelectedRecord topNEntity = new SelectedRecord();
-                topNEntity.setId(resultSet.getString(Metrics.ENTITY_ID));
-                topNEntity.setValue(resultSet.getString("result"));
-                topNEntities.add(topNEntity);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-        return topNEntities;
-    }
-
-    protected StringBuilder buildMetricsValueSql(String valueColumnName, String metricsName) {
-        StringBuilder sql = new StringBuilder();
-        sql.append("select result,")
-           .append(Metrics.ENTITY_ID)
-           .append(" from (select avg(")
-           .append(valueColumnName)
-           .append(") result,")
-           .append(Metrics.ENTITY_ID)
-           .append(" from ")
-           .append(metricsName)
-           .append(" where ");
-        return sql;
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAlarmQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAlarmQueryDAO.java
index 3ee3a038a4ac..588f393af144 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAlarmQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCAlarmQueryDAO.java
@@ -19,14 +19,9 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
 import com.google.common.base.Strings;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.alarm.AlarmRecord;
@@ -37,66 +32,125 @@
 import org.apache.skywalking.oap.server.core.query.type.AlarmMessage;
 import org.apache.skywalking.oap.server.core.query.type.Alarms;
 import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 
+import static java.util.Comparator.comparing;
 import static java.util.Objects.nonNull;
-import static org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller.ID_COLUMN;
+import static java.util.function.Predicate.not;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
 
+@Slf4j
+@RequiredArgsConstructor
 public class JDBCAlarmQueryDAO implements IAlarmQueryDAO {
-    protected final JDBCHikariCPClient jdbcClient;
+    protected final JDBCClient jdbcClient;
+    protected final ModuleManager manager;
+    protected final TableHelper tableHelper;
 
-    private final ModuleManager manager;
+    private Set<String> searchableTagKeys;
 
-    private List<String> searchableTagKeys;
+    @Override
+    @SneakyThrows
+    public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from,
+                           Duration duration, final List<Tag> tags) {
+        if (searchableTagKeys == null) {
+            final ConfigService configService = manager.find(CoreModule.NAME)
+                                                       .provider()
+                                                       .getService(ConfigService.class);
+            searchableTagKeys = new HashSet<>(Arrays.asList(configService.getSearchableAlarmTags().split(Const.COMMA)));
+        }
+        // If the tag is not searchable, but is required, then we don't need to run the real query.
+        if (tags != null && !searchableTagKeys.containsAll(tags.stream().map(Tag::getKey).collect(toSet()))) {
+            log.warn(
+                "Searching tags that are not searchable: {}",
+                tags.stream().map(Tag::getKey).filter(not(searchableTagKeys::contains)).collect(toSet()));
+            return new Alarms();
+        }
+
+        final var tables = tableHelper.getTablesForRead(
+            AlarmRecord.INDEX_NAME, duration.getStartTimeBucket(), duration.getEndTimeBucket()
+        );
+        final var alarmMsgs = new ArrayList<AlarmMessage>();
 
-    public JDBCAlarmQueryDAO(final JDBCHikariCPClient jdbcClient,
-                             final ModuleManager manager) {
-        this.jdbcClient = jdbcClient;
-        this.manager = manager;
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQL(scopeId, keyword, limit, from, duration, tags, table);
+            jdbcClient.executeQuery(sqlAndParameters.sql(), resultSet -> {
+                while (resultSet.next()) {
+                    final var message = new AlarmMessage();
+                    message.setId(resultSet.getString(AlarmRecord.ID0));
+                    message.setId1(resultSet.getString(AlarmRecord.ID1));
+                    message.setMessage(resultSet.getString(AlarmRecord.ALARM_MESSAGE));
+                    message.setStartTime(resultSet.getLong(AlarmRecord.START_TIME));
+                    message.setScope(Scope.Finder.valueOf(resultSet.getInt(AlarmRecord.SCOPE)));
+                    message.setScopeId(resultSet.getInt(AlarmRecord.SCOPE));
+                    String dataBinaryBase64 = resultSet.getString(AlarmRecord.TAGS_RAW_DATA);
+                    if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+                        parserDataBinaryBase64(dataBinaryBase64, message.getTags());
+                    }
+                    alarmMsgs.add(message);
+                }
+                return null;
+            }, sqlAndParameters.parameters());
+        }
+        return new Alarms(
+            alarmMsgs
+                .stream()
+                .sorted(comparing(AlarmMessage::getStartTime).reversed())
+                .skip(from)
+                .limit(limit)
+                .collect(toList())
+        );
     }
 
-    @Override
-    public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from,
-                           Duration duration, final List<Tag> tags) throws IOException {
+    protected SQLAndParameters buildSQL(Integer scopeId, String keyword, int limit, int from,
+                                        Duration duration, List<Tag> tags, String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>();
+
         long startTB = 0;
         long endTB = 0;
         if (nonNull(duration)) {
             startTB = duration.getStartTimeBucketInSec();
             endTB = duration.getEndTimeBucketInSec();
         }
-        if (searchableTagKeys == null) {
-            final ConfigService configService = manager.find(CoreModule.NAME)
-                    .provider()
-                    .getService(ConfigService.class);
-            searchableTagKeys = Arrays.asList(configService.getSearchableAlarmTags().split(Const.COMMA));
-        }
-        StringBuilder sql = new StringBuilder();
-        List<Object> parameters = new ArrayList<>(10);
-        sql.append("from ").append(AlarmRecord.INDEX_NAME);
-        /**
+        sql.append("select * from ").append(table);
+        /*
          * This is an AdditionalEntity feature, see:
          * {@link org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase.AdditionalEntity}
          */
+        final var timeBucket = TableHelper.getTimeBucket(table);
+        final var tagTable = TableHelper.getTable(AlarmRecord.ADDITIONAL_TAG_TABLE, timeBucket);
         if (!CollectionUtils.isEmpty(tags)) {
             for (int i = 0; i < tags.size(); i++) {
-                sql.append(" inner join ").append(AlarmRecord.ADDITIONAL_TAG_TABLE).append(" ");
-                sql.append(AlarmRecord.ADDITIONAL_TAG_TABLE + i);
-                sql.append(" on ").append(AlarmRecord.INDEX_NAME).append(".").append(ID_COLUMN).append(" = ");
-                sql.append(AlarmRecord.ADDITIONAL_TAG_TABLE + i).append(".").append(ID_COLUMN);
+                sql.append(" inner join ").append(tagTable).append(" ");
+                sql.append(tagTable + i);
+                sql.append(" on ").append(table).append(".").append(JDBCTableInstaller.ID_COLUMN).append(" = ");
+                sql.append(tagTable + i).append(".").append(JDBCTableInstaller.ID_COLUMN);
             }
         }
-        sql.append(" where ");
-        sql.append(" 1=1 ");
+        sql.append(" where ")
+           .append(table).append(".").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        parameters.add(AlarmRecord.INDEX_NAME);
         if (Objects.nonNull(scopeId)) {
             sql.append(" and ").append(AlarmRecord.SCOPE).append(" = ?");
-            parameters.add(scopeId.intValue());
+            parameters.add(scopeId);
         }
         if (startTB != 0 && endTB != 0) {
-            sql.append(" and ").append(AlarmRecord.INDEX_NAME).append(".").append(AlarmRecord.TIME_BUCKET).append(" >= ?");
+            sql.append(" and ").append(table).append(".").append(AlarmRecord.TIME_BUCKET).append(" >= ?");
             parameters.add(startTB);
-            sql.append(" and ").append(AlarmRecord.INDEX_NAME).append(".").append(AlarmRecord.TIME_BUCKET).append(" <= ?");
+            sql.append(" and ").append(table).append(".").append(AlarmRecord.TIME_BUCKET).append(" <= ?");
             parameters.add(endTB);
         }
 
@@ -106,49 +160,14 @@ public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from,
         }
         if (CollectionUtils.isNotEmpty(tags)) {
             for (int i = 0; i < tags.size(); i++) {
-                final int foundIdx = searchableTagKeys.indexOf(tags.get(i).getKey());
-                if (foundIdx > -1) {
-                    sql.append(" and ").append(AlarmRecord.ADDITIONAL_TAG_TABLE + i).append(".");
-                    sql.append(AlarmRecord.TAGS).append(" = ?");
-                    parameters.add(tags.get(i).toString());
-                } else {
-                    //If the tag is not searchable, but is required, then don't need to run the real query.
-                    return new Alarms();
-                }
+                sql.append(" and ").append(tagTable + i).append(".");
+                sql.append(AlarmRecord.TAGS).append(" = ?");
+                parameters.add(tags.get(i).toString());
             }
         }
         sql.append(" order by ").append(AlarmRecord.START_TIME).append(" desc ");
+        sql.append(" limit ").append(from + limit);
 
-        Alarms alarms = new Alarms();
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            this.buildLimit(sql, from, limit);
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(connection, "select * " + sql.toString(), parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    AlarmMessage message = new AlarmMessage();
-                    message.setId(resultSet.getString(AlarmRecord.ID0));
-                    message.setId1(resultSet.getString(AlarmRecord.ID1));
-                    message.setMessage(resultSet.getString(AlarmRecord.ALARM_MESSAGE));
-                    message.setStartTime(resultSet.getLong(AlarmRecord.START_TIME));
-                    message.setScope(Scope.Finder.valueOf(resultSet.getInt(AlarmRecord.SCOPE)));
-                    message.setScopeId(resultSet.getInt(AlarmRecord.SCOPE));
-                    String dataBinaryBase64 = resultSet.getString(AlarmRecord.TAGS_RAW_DATA);
-                    if (!com.google.common.base.Strings.isNullOrEmpty(dataBinaryBase64)) {
-                        parserDataBinaryBase64(dataBinaryBase64, message.getTags());
-                    }
-                    alarms.getMsgs().add(message);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-
-        return alarms;
-    }
-
-    protected void buildLimit(StringBuilder sql, int from, int limit) {
-        sql.append(" LIMIT ").append(limit);
-        sql.append(" OFFSET ").append(from);
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBatchDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBatchDAO.java
index d5aceebcd26f..563859eb89d7 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBatchDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBatchDAO.java
@@ -18,18 +18,9 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.Function;
-import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.storage.IBatchDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
 import org.apache.skywalking.oap.server.library.client.request.PrepareRequest;
 import org.apache.skywalking.oap.server.library.datacarrier.DataCarrier;
@@ -38,13 +29,19 @@
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.BatchSQLExecutor;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 @Slf4j
 public class JDBCBatchDAO implements IBatchDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final DataCarrier<PrepareRequest> dataCarrier;
     private final int maxBatchSqlSize;
 
-    public JDBCBatchDAO(JDBCHikariCPClient jdbcClient, int maxBatchSqlSize, int asyncBatchPersistentPoolSize) {
+    public JDBCBatchDAO(JDBCClient jdbcClient, int maxBatchSqlSize, int asyncBatchPersistentPoolSize) {
         this.jdbcClient = jdbcClient;
         String name = "H2_ASYNCHRONOUS_BATCH_PERSISTENT";
         if (log.isDebugEnabled()) {
@@ -52,7 +49,7 @@ public JDBCBatchDAO(JDBCHikariCPClient jdbcClient, int maxBatchSqlSize, int asyn
         }
         this.maxBatchSqlSize = maxBatchSqlSize;
         this.dataCarrier = new DataCarrier<>(name, asyncBatchPersistentPoolSize, 10000);
-        this.dataCarrier.consume(new JDBCBatchDAO.H2BatchConsumer(this), asyncBatchPersistentPoolSize, 20);
+        this.dataCarrier.consume(new H2BatchConsumer(this), asyncBatchPersistentPoolSize, 20);
     }
 
     @Override
@@ -74,22 +71,16 @@ public CompletableFuture<Void> flush(List<PrepareRequest> prepareRequests) {
             log.debug("to execute sql statements execute, data size: {}, maxBatchSqlSize: {}", sqls.size(), maxBatchSqlSize);
         }
 
-        final Map<PrepareRequest, List<PrepareRequest>> batchRequestMap =
-            sqls.stream().collect(Collectors.groupingBy(Function.identity()));
-        try (Connection connection = jdbcClient.getConnection()) {
-            batchRequestMap.forEach((key, requests) -> {
-                try {
-                    BatchSQLExecutor batchSQLExecutor =
-                            new BatchSQLExecutor(requests);
-                    batchSQLExecutor.invoke(connection, maxBatchSqlSize);
-                } catch (SQLException e) {
-                    // Just avoid one execution failure makes the rest of batch failure.
-                    log.error(e.getMessage(), e);
-                }
-            });
-        } catch (SQLException | JDBCClientException e) {
-            log.warn("execute sql failed, discard data size: {}", prepareRequests.size(), e);
-        }
+        final var batchRequestsOfSql = sqls.stream().collect(Collectors.groupingBy(Function.identity()));
+        batchRequestsOfSql.forEach((sql, requests) -> {
+            try {
+                final var batchSQLExecutor = new BatchSQLExecutor(jdbcClient, requests);
+                batchSQLExecutor.invoke(maxBatchSqlSize);
+            } catch (Exception e) {
+                // Just to avoid one execution failure makes the rest of batch failure.
+                log.error(e.getMessage(), e);
+            }
+        });
         if (log.isDebugEnabled()) {
             log.debug("execute sql statements done, data size: {}, maxBatchSqlSize: {}", prepareRequests.size(), maxBatchSqlSize);
         }
@@ -101,7 +92,7 @@ public void insert(InsertRequest insertRequest) {
         this.dataCarrier.produce(insertRequest);
     }
 
-    private class H2BatchConsumer implements IConsumer<PrepareRequest> {
+    private static class H2BatchConsumer implements IConsumer<PrepareRequest> {
 
         private final JDBCBatchDAO h2BatchDAO;
 
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBrowserLogQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBrowserLogQueryDAO.java
index 03b6bb3b9b63..2dbb1ca95387 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBrowserLogQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCBrowserLogQueryDAO.java
@@ -17,48 +17,92 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import lombok.RequiredArgsConstructor;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.browser.manual.errorlog.BrowserErrorLogRecord;
 import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
 import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
 import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
 
+import static java.util.Comparator.comparing;
 import static java.util.Objects.nonNull;
+import static java.util.stream.Collectors.toList;
 
 @RequiredArgsConstructor
 public class JDBCBrowserLogQueryDAO implements IBrowserLogQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    protected final JDBCClient jdbcClient;
+    protected final TableHelper tableHelper;
 
     @Override
+    @SneakyThrows
     public BrowserErrorLogs queryBrowserErrorLogs(String serviceId,
                                                   String serviceVersionId,
                                                   String pagePathId,
                                                   BrowserErrorCategory category,
                                                   Duration duration,
                                                   int limit,
-                                                  int from) throws IOException {
+                                                  int from) {
+        final var logs = new ArrayList<BrowserErrorLog>();
+        final var tables = tableHelper.getTablesForRead(
+            BrowserErrorLogRecord.INDEX_NAME, duration.getStartTimeBucket(), duration.getEndTimeBucket()
+        );
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQL(
+                serviceId, serviceVersionId, pagePathId,
+                category, duration, limit, from, table);
+
+            jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        String dataBinaryBase64 = resultSet.getString(BrowserErrorLogRecord.DATA_BINARY);
+                        if (nonNull(dataBinaryBase64)) {
+                            BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
+                            logs.add(log);
+                        }
+                    }
+
+                    return null;
+                },
+                sqlAndParameters.parameters()
+            );
+        }
+
+        return new BrowserErrorLogs(
+            logs
+                .stream()
+                .sorted(comparing(BrowserErrorLog::getTime).reversed())
+                .skip(from)
+                .limit(limit)
+                .collect(toList())
+        );
+    }
+
+    protected SQLAndParameters buildSQL(
+        String serviceId, String serviceVersionId, String pagePathId,
+        BrowserErrorCategory category, Duration duration, int limit, int from,
+        String table) {
+        final var sql = new StringBuilder("select " + BrowserErrorLogRecord.DATA_BINARY);
+        final var parameters = new ArrayList<>(9);
+        sql.append(" from ").append(table)
+           .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        parameters.add(BrowserErrorLogRecord.INDEX_NAME);
+
         long startSecondTB = 0, endSecondTB = 0;
         if (nonNull(duration)) {
             startSecondTB = duration.getStartTimeBucketInSec();
             endSecondTB = duration.getEndTimeBucketInSec();
         }
-        StringBuilder sql = new StringBuilder();
-
-        List<Object> parameters = new ArrayList<>(9);
-
-        sql.append("from ").append(BrowserErrorLogRecord.INDEX_NAME)
-           .append(" where ").append(" 1=1 ");
-
         if (startSecondTB != 0 && endSecondTB != 0) {
             sql.append(" and ").append(BrowserErrorLogRecord.TIME_BUCKET).append(" >= ?");
             parameters.add(startSecondTB);
@@ -84,32 +128,8 @@ public BrowserErrorLogs queryBrowserErrorLogs(String serviceId,
         }
 
         sql.append(" order by ").append(BrowserErrorLogRecord.TIMESTAMP).append(" DESC ");
+        sql.append(" limit ").append(from + limit);
 
-        BrowserErrorLogs logs = new BrowserErrorLogs();
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            buildLimit(sql, from, limit);
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, "select " + BrowserErrorLogRecord.DATA_BINARY + " " + sql.toString(),
-                parameters.toArray(new Object[0])
-            )) {
-                while (resultSet.next()) {
-                    String dataBinaryBase64 = resultSet.getString(BrowserErrorLogRecord.DATA_BINARY);
-                    if (nonNull(dataBinaryBase64)) {
-                        BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
-                        logs.getLogs().add(log);
-                    }
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-        return logs;
-    }
-
-    protected void buildLimit(StringBuilder sql, int from, int limit) {
-        sql.append(" limit ").append(limit);
-        sql.append(" offset ").append(from);
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingDataDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingDataDAO.java
index 348b2b2448a8..efe96ec90f79 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingDataDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingDataDAO.java
@@ -18,47 +18,74 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import org.apache.skywalking.oap.server.core.analysis.DownSampling;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.profiling.ebpf.storage.EBPFProfilingDataRecord;
 import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IEBPFProfilingDataDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
-import java.io.IOException;
-import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.List;
 
-@AllArgsConstructor
+import static java.util.stream.Collectors.joining;
+
+@RequiredArgsConstructor
 public class JDBCEBPFProfilingDataDAO implements IEBPFProfilingDataDAO {
-    private JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<EBPFProfilingDataRecord> queryData(List<String> scheduleIdList, long beginTime, long endTime) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        final StringBuilder conditionSql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(scheduleIdList.size() + 2);
-        sql.append("select * from ").append(EBPFProfilingDataRecord.INDEX_NAME);
-
-        appendListCondition(conditionSql, condition, EBPFProfilingDataRecord.SCHEDULE_ID, scheduleIdList);
-        appendCondition(conditionSql, condition, EBPFProfilingDataRecord.UPLOAD_TIME, ">=", beginTime);
-        appendCondition(conditionSql, condition, EBPFProfilingDataRecord.UPLOAD_TIME, "<", endTime);
+    @SneakyThrows
+    public List<EBPFProfilingDataRecord> queryData(List<String> scheduleIdList, long beginTime, long endTime) {
+        final var tables = tableHelper.getTablesForRead(
+            EBPFProfilingDataRecord.INDEX_NAME,
+            TimeBucket.getTimeBucket(beginTime, DownSampling.Day),
+            TimeBucket.getTimeBucket(endTime, DownSampling.Day)
+        );
+        final var results = new ArrayList<EBPFProfilingDataRecord>();
 
-        if (conditionSql.length() > 0) {
-            sql.append(" where ").append(conditionSql);
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQL(scheduleIdList, beginTime, endTime, table);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildDataList,
+                    sqlAndParameters.parameters()
+                )
+            );
         }
+        return results;
+    }
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                    connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildDataList(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+    protected SQLAndParameters buildSQL(
+        final List<String> scheduleIdList,
+        final long beginTime,
+        final long endTime,
+        final String table) {
+        final var sql = new StringBuilder();
+        final var conditions = new StringBuilder();
+        final var parameters = new ArrayList<>(scheduleIdList.size() + 3);
+        sql.append("select * from ").append(table);
+        conditions.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        parameters.add(EBPFProfilingDataRecord.INDEX_NAME);
+
+        appendConditions(conditions, parameters, EBPFProfilingDataRecord.SCHEDULE_ID, scheduleIdList);
+        appendCondition(conditions, parameters, EBPFProfilingDataRecord.UPLOAD_TIME, ">=", beginTime);
+        appendCondition(conditions, parameters, EBPFProfilingDataRecord.UPLOAD_TIME, "<", endTime);
+
+        if (conditions.length() > 0) {
+            sql.append(conditions);
         }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     private List<EBPFProfilingDataRecord> buildDataList(ResultSet resultSet) throws SQLException {
@@ -80,26 +107,20 @@ private List<EBPFProfilingDataRecord> buildDataList(ResultSet resultSet) throws
         return dataList;
     }
 
-    private void appendCondition(StringBuilder conditionSql, List<Object> condition, String filed, String compare, Object data) {
+    private void appendCondition(StringBuilder conditionSql, List<Object> condition, String field, String compare, Object data) {
         if (conditionSql.length() > 0) {
             conditionSql.append(" and ");
         }
-        conditionSql.append(filed).append(compare).append("?");
+        conditionSql.append(field).append(compare).append("?");
         condition.add(data);
     }
 
-    private <T> void appendListCondition(StringBuilder conditionSql, List<Object> condition, String filed, List<T> data) {
+    private <T> void appendConditions(StringBuilder conditionSql, List<Object> condition, String field, List<T> data) {
         if (conditionSql.length() > 0) {
             conditionSql.append(" and ");
         }
-        conditionSql.append(filed).append(" in (");
-        for (int i = 0; i < data.size(); i++) {
-            if (i > 0) {
-                conditionSql.append(", ");
-            }
-            conditionSql.append("?");
-            condition.add(data.get(i));
-        }
-        conditionSql.append(")");
+        conditionSql.append(field).append(" in ")
+                    .append(data.stream().map(it -> "?").collect(joining(", ", "(", ")")));
+        condition.addAll(data);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingScheduleDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingScheduleDAO.java
index 269642c9d047..3520fad1bdb1 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingScheduleDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingScheduleDAO.java
@@ -18,55 +18,73 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.profiling.ebpf.storage.EBPFProfilingScheduleRecord;
 import org.apache.skywalking.oap.server.core.query.type.EBPFProfilingSchedule;
 import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IEBPFProfilingScheduleDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller;
-import java.io.IOException;
-import java.sql.Connection;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCEntityConverters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class JDBCEBPFProfilingScheduleDAO implements IEBPFProfilingScheduleDAO {
-    private JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<EBPFProfilingSchedule> querySchedules(String taskId) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        final StringBuilder conditionSql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(4);
-        sql.append("select * from ").append(EBPFProfilingScheduleRecord.INDEX_NAME);
+    @SneakyThrows
+    public List<EBPFProfilingSchedule> querySchedules(String taskId) {
+        final var tables = tableHelper.getTablesWithinTTL(EBPFProfilingScheduleRecord.INDEX_NAME);
+        final var schedules = new ArrayList<EBPFProfilingSchedule>();
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQL(taskId, table);
+            schedules.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildSchedules,
+                    sqlAndParameters.parameters()
+                )
+            );
+        }
+        return schedules;
+    }
 
-        appendCondition(conditionSql, condition, EBPFProfilingScheduleRecord.TASK_ID, "=", taskId);
+    protected SQLAndParameters buildSQL(
+        final String taskId,
+        final String table) {
+        final var sql = new StringBuilder();
+        final var conditions = new StringBuilder();
+        final var parameters = new ArrayList<>(4);
+        sql.append("select * from ").append(table);
+        conditions.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(EBPFProfilingScheduleRecord.INDEX_NAME);
 
-        if (conditionSql.length() > 0) {
-            sql.append(" where ").append(conditionSql);
-        }
+        appendCondition(conditions, parameters, EBPFProfilingScheduleRecord.TASK_ID, "=", taskId);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                    connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildSchedules(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+        if (conditions.length() > 0) {
+            sql.append(" where ").append(conditions);
         }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     private List<EBPFProfilingSchedule> buildSchedules(ResultSet resultSet) throws SQLException {
         List<EBPFProfilingSchedule> schedules = new ArrayList<>();
         while (resultSet.next()) {
+            final var r = new EBPFProfilingScheduleRecord.Builder().storage2Entity(JDBCEntityConverters.toEntity(resultSet));
             EBPFProfilingSchedule schedule = new EBPFProfilingSchedule();
-            schedule.setScheduleId(resultSet.getString(H2TableInstaller.ID_COLUMN));
-            schedule.setTaskId(resultSet.getString(EBPFProfilingScheduleRecord.TASK_ID));
-            schedule.setProcessId(resultSet.getString(EBPFProfilingScheduleRecord.PROCESS_ID));
-            schedule.setStartTime(resultSet.getLong(EBPFProfilingScheduleRecord.START_TIME));
-            schedule.setEndTime(resultSet.getLong(EBPFProfilingScheduleRecord.END_TIME));
+            schedule.setScheduleId(r.getScheduleId());
+            schedule.setTaskId(r.getTaskId());
+            schedule.setProcessId(r.getProcessId());
+            schedule.setStartTime(r.getStartTime());
+            schedule.setEndTime(r.getEndTime());
 
             schedules.add(schedule);
         }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingTaskDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingTaskDAO.java
index 897a8d9ee7c7..33a7ec5ba9f2 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingTaskDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEBPFProfilingTaskDAO.java
@@ -19,7 +19,8 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
 import com.google.gson.Gson;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.profiling.ebpf.storage.EBPFProfilingTargetType;
 import org.apache.skywalking.oap.server.core.profiling.ebpf.storage.EBPFProfilingTaskRecord;
@@ -27,12 +28,12 @@
 import org.apache.skywalking.oap.server.core.query.type.EBPFProfilingTask;
 import org.apache.skywalking.oap.server.core.query.type.EBPFProfilingTaskExtension;
 import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IEBPFProfilingTaskDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
-import java.io.IOException;
-import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -40,103 +41,140 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class JDBCEBPFProfilingTaskDAO implements IEBPFProfilingTaskDAO {
     private static final Gson GSON = new Gson();
-    private JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<EBPFProfilingTask> queryTasksByServices(List<String> serviceIdList, long taskStartTime, long latestUpdateTime) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>();
-        sql.append("select * from ").append(EBPFProfilingTaskRecord.INDEX_NAME);
+    @SneakyThrows
+    public List<EBPFProfilingTask> queryTasksByServices(List<String> serviceIdList, long taskStartTime, long latestUpdateTime) {
+        final var tables = tableHelper.getTablesWithinTTL(EBPFProfilingTaskRecord.INDEX_NAME);
+        final var results = new ArrayList<EBPFProfilingTask>();
+
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQLForQueryTasksByServices(serviceIdList, taskStartTime, latestUpdateTime, table);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildTasks,
+                    sqlAndParameters.parameters()
+                )
+            );
+        }
+        return results;
+    }
+
+    protected SQLAndParameters buildSQLForQueryTasksByServices(
+        final List<String> serviceIdList,
+        final long taskStartTime,
+        final long latestUpdateTime,
+        final String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>();
+        sql.append("select * from ").append(table);
 
-        StringBuilder conditionSql = new StringBuilder();
+        final var conditionSql = new StringBuilder();
+        conditionSql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(EBPFProfilingTaskRecord.INDEX_NAME);
 
-        appendListCondition(conditionSql, condition, EBPFProfilingTaskRecord.SERVICE_ID, serviceIdList);
+        appendListCondition(conditionSql, parameters, EBPFProfilingTaskRecord.SERVICE_ID, serviceIdList);
         if (taskStartTime > 0) {
-            appendCondition(conditionSql, condition,
+            appendCondition(conditionSql, parameters,
                 EBPFProfilingTaskRecord.START_TIME, ">=", taskStartTime);
         }
         if (latestUpdateTime > 0) {
-            appendCondition(conditionSql, condition,
+            appendCondition(conditionSql, parameters,
                 EBPFProfilingTaskRecord.LAST_UPDATE_TIME, ">", latestUpdateTime);
         }
 
         if (conditionSql.length() > 0) {
             sql.append(" where ").append(conditionSql);
         }
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildTasks(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     @Override
-    public List<EBPFProfilingTask> queryTasksByTargets(String serviceId, String serviceInstanceId, List<EBPFProfilingTargetType> targetTypes, long taskStartTime, long latestUpdateTime) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>();
-        sql.append("select * from ").append(EBPFProfilingTaskRecord.INDEX_NAME);
+    @SneakyThrows
+    public List<EBPFProfilingTask> queryTasksByTargets(String serviceId, String serviceInstanceId, List<EBPFProfilingTargetType> targetTypes, long taskStartTime, long latestUpdateTime) {
+        final var results = new ArrayList<EBPFProfilingTask>();
+        final var tables = tableHelper.getTablesWithinTTL(EBPFProfilingTaskRecord.INDEX_NAME);
+
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQLForQueryTasksByTargets(
+                serviceId, serviceInstanceId, targetTypes, taskStartTime, latestUpdateTime, table
+            );
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildTasks,
+                    sqlAndParameters.parameters()
+                )
+            );
+        }
+        return results;
+    }
 
-        StringBuilder conditionSql = new StringBuilder();
+    protected SQLAndParameters buildSQLForQueryTasksByTargets(
+        final String serviceId,
+        final String serviceInstanceId,
+        final List<EBPFProfilingTargetType> targetTypes,
+        final long taskStartTime,
+        final long latestUpdateTime,
+        final String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>();
+        final var conditions = new StringBuilder();
+
+        sql.append("select * from ").append(table);
+        conditions.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(EBPFProfilingTaskRecord.INDEX_NAME);
 
         if (StringUtil.isNotEmpty(serviceId)) {
-            appendCondition(conditionSql, condition, EBPFProfilingTaskRecord.SERVICE_ID, serviceId);
+            appendCondition(conditions, parameters, EBPFProfilingTaskRecord.SERVICE_ID, serviceId);
         }
         if (StringUtil.isNotEmpty(serviceInstanceId)) {
-            appendCondition(conditionSql, condition, EBPFProfilingTaskRecord.INSTANCE_ID, serviceInstanceId);
+            appendCondition(conditions, parameters, EBPFProfilingTaskRecord.INSTANCE_ID, serviceInstanceId);
         }
-        appendListCondition(conditionSql, condition, EBPFProfilingTaskRecord.TARGET_TYPE, targetTypes.stream()
-            .map(EBPFProfilingTargetType::value).collect(Collectors.toList()));
+        appendListCondition(conditions, parameters, EBPFProfilingTaskRecord.TARGET_TYPE,
+            targetTypes.stream().map(EBPFProfilingTargetType::value).collect(Collectors.toList()));
         if (taskStartTime > 0) {
-            appendCondition(conditionSql, condition,
+            appendCondition(conditions, parameters,
                 EBPFProfilingTaskRecord.START_TIME, ">=", taskStartTime);
         }
         if (latestUpdateTime > 0) {
-            appendCondition(conditionSql, condition,
+            appendCondition(conditions, parameters,
                 EBPFProfilingTaskRecord.LAST_UPDATE_TIME, ">", latestUpdateTime);
         }
 
-        if (conditionSql.length() > 0) {
-            sql.append(" where ").append(conditionSql);
+        if (conditions.length() > 0) {
+            sql.append(" where ").append(conditions);
         }
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildTasks(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     @Override
-    public EBPFProfilingTask queryById(String id) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        sql.append("select * from ").append(EBPFProfilingTaskRecord.INDEX_NAME)
-            .append(" where ").append(EBPFProfilingTaskRecord.LOGICAL_ID).append("=?");
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), id)) {
-                final List<EBPFProfilingTask> tasks = buildTasks(resultSet);
-                if (CollectionUtils.isEmpty(tasks)) {
-                    return null;
-                }
-                EBPFProfilingTask result = tasks.get(0);
-                for (int i = 1; i < tasks.size(); i++) {
-                    result = result.combine(tasks.get(i));
-                }
+    @SneakyThrows
+    public EBPFProfilingTask queryById(String id) {
+        final var tables = tableHelper.getTablesWithinTTL(EBPFProfilingTaskRecord.INDEX_NAME);
+        for (final var table : tables) {
+            final var sql = new StringBuilder();
+            sql.append("select * from ").append(table)
+               .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?")
+               .append(EBPFProfilingTaskRecord.LOGICAL_ID).append(" = ?");
+
+            final var result = jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> buildTasks(resultSet).stream().reduce(EBPFProfilingTask::combine).orElse(null),
+                EBPFProfilingTaskRecord.INDEX_NAME, id
+            );
+            if (result != null) {
                 return result;
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
         }
+        return null;
     }
 
     private List<EBPFProfilingTask> buildTasks(ResultSet resultSet) throws SQLException {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEventQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEventQueryDAO.java
index 34b5153d6133..45c7dacd324e 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEventQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCEventQueryDAO.java
@@ -20,15 +20,10 @@
 
 import io.vavr.Tuple;
 import io.vavr.Tuple2;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
+import org.apache.skywalking.oap.server.core.analysis.metrics.Event;
 import org.apache.skywalking.oap.server.core.query.PaginationUtils;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
@@ -36,91 +31,130 @@
 import org.apache.skywalking.oap.server.core.query.type.event.EventType;
 import org.apache.skywalking.oap.server.core.query.type.event.Events;
 import org.apache.skywalking.oap.server.core.query.type.event.Source;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Event;
 import org.apache.skywalking.oap.server.core.storage.query.IEventQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
-import static java.util.Objects.isNull;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.util.Comparator.comparing;
+import static java.util.Objects.isNull;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
 
 @Slf4j
 @RequiredArgsConstructor
 public class JDBCEventQueryDAO implements IEventQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
     public Events queryEvents(final EventQueryCondition condition) throws Exception {
         final Tuple2<Stream<String>, Stream<Object>> conditionsParametersPair = buildQuery(condition);
         final Stream<String> conditions = conditionsParametersPair._1();
         final Object[] parameters = conditionsParametersPair._2().toArray();
-        final String whereClause = conditions.collect(Collectors.joining(" and ", " where ", ""));
+        final String whereClause = conditions.collect(joining(" and ", " where ", ""));
 
-        final Events result = new Events();
+        final var tables = tableHelper.getTablesWithinTTL(Event.INDEX_NAME);
+        final var queryOrder = isNull(condition.getOrder()) ? Order.DES : condition.getOrder();
+        final var page = PaginationUtils.INSTANCE.exchange(condition.getPaging());
+        final var events = new ArrayList<org.apache.skywalking.oap.server.core.query.type.event.Event>();
 
-        try (final Connection connection = jdbcClient.getConnection()) {
-            final Order queryOrder = isNull(condition.getOrder()) ? Order.DES : condition.getOrder();
-            final PaginationUtils.Page page = PaginationUtils.INSTANCE.exchange(condition.getPaging());
-            String sql = "select * from " + Event.INDEX_NAME + whereClause;
+        for (String table : tables) {
+            String sql = "select * from " + table + whereClause;
             if (Order.DES.equals(queryOrder)) {
                 sql += " order by " + Event.START_TIME + " desc";
             } else {
                 sql += " order by " + Event.START_TIME + " asc";
             }
-            sql += " limit " + page.getLimit() + " offset " + page.getFrom();
+            sql += " limit " + (page.getLimit() + page.getFrom());
             if (log.isDebugEnabled()) {
                 log.debug("Query SQL: {}, parameters: {}", sql, parameters);
             }
-            try (final ResultSet resultSet = jdbcClient.executeQuery(connection, sql, parameters)) {
+
+            jdbcClient.executeQuery(sql, resultSet -> {
                 while (resultSet.next()) {
-                    result.getEvents().add(parseResultSet(resultSet));
+                    events.add(parseResultSet(resultSet));
                 }
-            }
+                return null;
+            }, parameters);
         }
 
-        return result;
+        final var comparator = Order.DES.equals(queryOrder) ?
+            comparing(org.apache.skywalking.oap.server.core.query.type.event.Event::getStartTime).reversed() :
+            comparing(org.apache.skywalking.oap.server.core.query.type.event.Event::getStartTime);
+        return new Events(
+            events
+                .stream()
+                .sorted(comparator)
+                .skip(page.getFrom())
+                .limit(page.getLimit())
+                .collect(toList())
+        );
     }
 
     @Override
     public Events queryEvents(List<EventQueryCondition> conditions) throws Exception {
-        final List<Tuple2<Stream<String>, Stream<Object>>> conditionsParametersPair = conditions.stream()
-                                                                                                .map(this::buildQuery)
-                                                                                                .collect(Collectors.toList());
-        final Object[] parameters = conditionsParametersPair.stream()
-                                                            .map(Tuple2::_2)
-                                                            .reduce(Stream.empty(), Stream::concat)
-                                                            .toArray();
-        final String whereClause = conditionsParametersPair.stream()
-                                                       .map(Tuple2::_1)
-                                                       .map(it -> it.collect(Collectors.joining(" and ")))
-                                                       .collect(Collectors.joining(" or ", " where ", ""));
-
-        final Events result = new Events();
-        try (final Connection connection = jdbcClient.getConnection()) {
-            EventQueryCondition condition = conditions.get(0);
-            final Order queryOrder = isNull(condition.getOrder()) ? Order.DES : condition.getOrder();
-            final PaginationUtils.Page page = PaginationUtils.INSTANCE.exchange(condition.getPaging());
-            String sql = "select * from " + Event.INDEX_NAME + whereClause;
+        final var conditionsParametersPair = conditions.stream()
+                                                       .map(this::buildQuery)
+                                                       .collect(toList());
+        final var parameters = conditionsParametersPair.stream()
+                                                       .map(Tuple2::_2)
+                                                       .reduce(Stream.empty(), Stream::concat)
+                                                       .toArray();
+        final var whereClause = conditionsParametersPair.stream()
+                                                        .map(Tuple2::_1)
+                                                        .map(it -> it.collect(joining(" and ")))
+                                                        .collect(joining(" or ", " where ", ""));
+
+        EventQueryCondition condition = conditions.get(0);
+        final Order queryOrder = isNull(condition.getOrder()) ? Order.DES : condition.getOrder();
+        final PaginationUtils.Page page = PaginationUtils.INSTANCE.exchange(condition.getPaging());
+
+        final var tables = tableHelper.getTablesWithinTTL(Event.INDEX_NAME);
+        final var events = new ArrayList<org.apache.skywalking.oap.server.core.query.type.event.Event>();
+
+        for (String table : tables) {
+            String sql = "select * from " + table + whereClause;
             if (Order.DES.equals(queryOrder)) {
                 sql += " order by " + Event.START_TIME + " desc";
             } else {
                 sql += " order by " + Event.START_TIME + " asc";
             }
-            sql += " limit " + page.getLimit() + " offset " + page.getFrom();
+            sql += " limit " + (page.getLimit() + page.getFrom());
             if (log.isDebugEnabled()) {
                 log.debug("Query SQL: {}, parameters: {}", sql, parameters);
             }
-            try (final ResultSet resultSet = jdbcClient.executeQuery(connection, sql, parameters)) {
+            jdbcClient.executeQuery(sql, resultSet -> {
                 while (resultSet.next()) {
-                    result.getEvents().add(parseResultSet(resultSet));
+                    events.add(parseResultSet(resultSet));
                 }
-            }
+
+                return null;
+            }, parameters);
         }
-        return result;
+
+        final var comparator = Order.DES.equals(queryOrder) ?
+            comparing(org.apache.skywalking.oap.server.core.query.type.event.Event::getStartTime).reversed() :
+            comparing(org.apache.skywalking.oap.server.core.query.type.event.Event::getStartTime);
+        return new Events(
+            events
+                .stream()
+                .sorted(comparator)
+                .skip(page.getFrom())
+                .limit(page.getLimit())
+                .collect(toList())
+        );
     }
 
     protected org.apache.skywalking.oap.server.core.query.type.event.Event parseResultSet(final ResultSet resultSet) throws SQLException {
-        final org.apache.skywalking.oap.server.core.query.type.event.Event event = new org.apache.skywalking.oap.server.core.query.type.event.Event();
+        final var event = new org.apache.skywalking.oap.server.core.query.type.event.Event();
 
         event.setUuid(resultSet.getString(Event.UUID));
 
@@ -143,6 +177,9 @@ protected Tuple2<Stream<String>, Stream<Object>> buildQuery(final EventQueryCond
         final Stream.Builder<String> conditions = Stream.builder();
         final Stream.Builder<Object> parameters = Stream.builder();
 
+        conditions.add(JDBCTableInstaller.TABLE_COLUMN + " = ?");
+        parameters.add(Event.INDEX_NAME);
+
         if (!isNullOrEmpty(condition.getUuid())) {
             conditions.add(Event.UUID + "=?");
             parameters.add(condition.getUuid());
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAO.java
index 7a2124e4f422..fe174f977bb9 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAO.java
@@ -18,66 +18,93 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.analysis.DownSampling;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.storage.IHistoryDeleteDAO;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 import org.joda.time.DateTime;
-import lombok.RequiredArgsConstructor;
 
+import java.time.Clock;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
 @RequiredArgsConstructor
 public class JDBCHistoryDeleteDAO implements IHistoryDeleteDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
+    private final JDBCTableInstaller modelInstaller;
+    private final Clock clock;
+
+    private final Map<String, Long> lastDeletedTimeBucket = new ConcurrentHashMap<>();
 
     @Override
-    public void deleteHistory(Model model, String timeBucketColumnName, int ttl) throws IOException {
-        SQLBuilder dataDeleteSQL = new SQLBuilder("delete from " + model.getName() + " where ")
-            .append(timeBucketColumnName).append("<= ? ")
-            .append(" and ")
-            .append(timeBucketColumnName).append(">= ? ");
+    @SneakyThrows
+    public void deleteHistory(Model model, String timeBucketColumnName, int ttl) {
+        final var endTimeBucket = TimeBucket.getTimeBucket(clock.millis(), DownSampling.Day);
+        final var startTimeBucket = endTimeBucket - ttl;
+        log.info(
+            "Deleting history data, ttl: {}, now: {}. Keep [{}, {}]",
+            ttl,
+            clock.millis(),
+            startTimeBucket,
+            endTimeBucket
+        );
+
+        final var deadline = Long.parseLong(new DateTime().minusDays(ttl).toString("yyyyMMdd"));
+        final var lastSuccessDeadline = lastDeletedTimeBucket.getOrDefault(model.getName(), 0L);
+        if (deadline <= lastSuccessDeadline) {
+            if (log.isDebugEnabled()) {
+                log.debug(
+                    "The deadline {} is less than the last success deadline {}, skip deleting history data",
+                    deadline,
+                    lastSuccessDeadline
+                );
+            }
+            return;
+        }
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            long deadline;
-            long minTime;
-            if (model.isRecord()) {
-                deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMddHHmmss"));
-                minTime = 1000_00_00_00_00_00L;
-            } else {
-                switch (model.getDownsampling()) {
-                    case Minute:
-                        deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMddHHmm"));
-                        minTime = 1000_00_00_00_00L;
-                        break;
-                    case Hour:
-                        deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMddHH"));
-                        minTime = 1000_00_00_00L;
-                        break;
-                    case Day:
-                        deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMdd"));
-                        minTime = 1000_00_00L;
-                        break;
-                    default:
-                        return;
-                }
+        final var ttlTables = tableHelper.getTablesForRead(model.getName(), startTimeBucket, endTimeBucket);
+        final var tablesToDrop = new HashSet<String>();
+
+        try (final var conn = jdbcClient.getConnection();
+             final var result = conn.getMetaData().getTables(null, null, TableHelper.getTableName(model) + "%", new String[]{"TABLE"})) {
+            while (result.next()) {
+                tablesToDrop.add(result.getString("TABLE_NAME"));
             }
-            jdbcClient.executeUpdate(connection, dataDeleteSQL.toString(), deadline, minTime);
-            // Delete additional tables
-            for (SQLDatabaseModelExtension.AdditionalTable additionalTable : model.getSqlDBModelExtension()
-                                                                                  .getAdditionalTables()
-                                                                                  .values()) {
-                SQLBuilder additionalTableDeleteSQL = new SQLBuilder("delete from " + additionalTable.getName() + " where ")
-                    .append(timeBucketColumnName).append("<= ? ")
-                    .append(" and ")
-                    .append(timeBucketColumnName).append(">= ? ");
-                jdbcClient.executeUpdate(connection, additionalTableDeleteSQL.toString(), deadline, minTime);
+        }
+
+        ttlTables.forEach(tablesToDrop::remove);
+        tablesToDrop.removeIf(it -> !it.matches(".*_\\d{8}$"));
+        for (final var table : tablesToDrop) {
+            final var dropSql = new SQLBuilder("drop table if exists ").append(table);
+            jdbcClient.executeUpdate(dropSql.toString());
+        }
+
+        // Drop additional tables
+        for (final var table : tablesToDrop) {
+            final var timeBucket = TableHelper.getTimeBucket(table);
+            for (final var additionalTable : model.getSqlDBModelExtension().getAdditionalTables().values()) {
+                final var additionalTableToDrop = TableHelper.getTable(additionalTable.getName(), timeBucket);
+                final var dropSql = new SQLBuilder("drop table if exists ").append(additionalTableToDrop);
+                jdbcClient.executeUpdate(dropSql.toString());
             }
-        } catch (JDBCClientException | SQLException e) {
-            throw new IOException(e.getMessage(), e);
         }
+
+        // Create tables for the next day.
+        final var nextTimeBucket = TimeBucket.getTimeBucket(clock.millis() + TimeUnit.DAYS.toMillis(1), DownSampling.Day);
+        final var table = TableHelper.getTable(model, nextTimeBucket);
+        modelInstaller.createTable(model, table);
+
+        lastDeletedTimeBucket.put(model.getName(), deadline);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCLogQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCLogQueryDAO.java
index 6a575875651e..52dc2cbc969b 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCLogQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCLogQueryDAO.java
@@ -20,15 +20,8 @@
 
 import com.google.common.base.Strings;
 import lombok.RequiredArgsConstructor;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
@@ -37,15 +30,33 @@
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
 import org.apache.skywalking.oap.server.core.config.ConfigService;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
+import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.input.TraceScopeCondition;
 import org.apache.skywalking.oap.server.core.query.type.ContentType;
 import org.apache.skywalking.oap.server.core.query.type.Log;
 import org.apache.skywalking.oap.server.core.query.type.Logs;
 import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static java.util.Comparator.comparing;
 import static java.util.Objects.nonNull;
+import static java.util.function.Predicate.not;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
 import static org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord.CONTENT;
 import static org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord.CONTENT_TYPE;
 import static org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord.ENDPOINT_ID;
@@ -56,15 +67,17 @@
 import static org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord.TIMESTAMP;
 import static org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord.TRACE_ID;
 import static org.apache.skywalking.oap.server.core.analysis.manual.log.AbstractLogRecord.TRACE_SEGMENT_ID;
-import static org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller.ID_COLUMN;
 
+@Slf4j
 @RequiredArgsConstructor
 public class JDBCLogQueryDAO implements ILogQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final ModuleManager manager;
-    private List<String> searchableTagKeys;
+    private final TableHelper tableHelper;
+    private Set<String> searchableTagKeys;
 
     @Override
+    @SneakyThrows
     public Logs queryLogs(String serviceId,
                           String serviceInstanceId,
                           String endpointId,
@@ -75,46 +88,127 @@ public Logs queryLogs(String serviceId,
                           final Duration duration,
                           final List<Tag> tags,
                           final List<String> keywordsOfContent,
-                          final List<String> excludingKeywordsOfContent) throws IOException {
+                          final List<String> excludingKeywordsOfContent) {
+        if (searchableTagKeys == null) {
+            final ConfigService configService = manager.find(CoreModule.NAME)
+                                                       .provider()
+                                                       .getService(ConfigService.class);
+            searchableTagKeys = new HashSet<>(Arrays.asList(configService.getSearchableLogsTags().split(Const.COMMA)));
+        }
+        if (tags != null && !searchableTagKeys.containsAll(tags.stream().map(Tag::getKey).collect(toSet()))) {
+            log.warn(
+                "Searching tags that are not searchable: {}",
+                tags.stream().map(Tag::getKey).filter(not(searchableTagKeys::contains)).collect(toSet()));
+            return new Logs();
+        }
+
+        final var tables = tableHelper.getTablesForRead(
+            LogRecord.INDEX_NAME,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var logs = new ArrayList<Log>();
+
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQL(
+                serviceId, serviceInstanceId, endpointId, relatedTrace, queryOrder,
+                from, limit, duration, tags, keywordsOfContent, excludingKeywordsOfContent, table);
+
+            logs.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::parseResults,
+                    sqlAndParameters.parameters()
+                )
+            );
+        }
+        final var comparator = Order.DES.equals(queryOrder) ?
+            comparing(Log::getTimestamp) :
+            comparing(Log::getTimestamp).reversed();
+
+        return new Logs(
+            logs
+                .stream()
+                .sorted(comparator)
+                .skip(from)
+                .limit(limit)
+                .collect(toList())
+        );
+    }
+
+    protected ArrayList<Log> parseResults(ResultSet resultSet) throws SQLException {
+        final var logs = new ArrayList<Log>();
+        while (resultSet.next()) {
+            Log log = new Log();
+            log.setServiceId(resultSet.getString(SERVICE_ID));
+            log.setServiceInstanceId(resultSet.getString(SERVICE_INSTANCE_ID));
+            log.setEndpointId(resultSet.getString(ENDPOINT_ID));
+            if (log.getEndpointId() != null) {
+                log.setEndpointName(IDManager.EndpointID.analysisId(log.getEndpointId()).getEndpointName());
+            }
+            log.setTraceId(resultSet.getString(TRACE_ID));
+            log.setTimestamp(resultSet.getLong(TIMESTAMP));
+            log.setContentType(ContentType.instanceOf(resultSet.getInt(CONTENT_TYPE)));
+            log.setContent(resultSet.getString(CONTENT));
+            String dataBinaryBase64 = resultSet.getString(TAGS_RAW_DATA);
+            if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+                parserDataBinary(dataBinaryBase64, log.getTags());
+            }
+            logs.add(log);
+        }
+
+        return logs;
+    }
+
+    protected SQLAndParameters buildSQL(
+        String serviceId,
+        String serviceInstanceId,
+        String endpointId,
+        TraceScopeCondition relatedTrace,
+        Order queryOrder,
+        int from,
+        int limit,
+        final Duration duration,
+        final List<Tag> tags,
+        final List<String> keywordsOfContent,
+        final List<String> excludingKeywordsOfContent,
+        final String table) {
         long startSecondTB = 0;
         long endSecondTB = 0;
         if (nonNull(duration)) {
             startSecondTB = duration.getStartTimeBucketInSec();
             endSecondTB = duration.getEndTimeBucketInSec();
         }
-        if (searchableTagKeys == null) {
-            final ConfigService configService = manager.find(CoreModule.NAME)
-                                                       .provider()
-                                                       .getService(ConfigService.class);
-            searchableTagKeys = Arrays.asList(configService.getSearchableLogsTags().split(Const.COMMA));
-        }
         StringBuilder sql = new StringBuilder();
         List<Object> parameters = new ArrayList<>(10);
 
-        sql.append("from ").append(LogRecord.INDEX_NAME);
-        /**
+        sql.append("select * from ").append(table);
+        /*
          * This is an AdditionalEntity feature, see:
          * {@link org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase.AdditionalEntity}
          */
+        final var timeBucket = TableHelper.getTimeBucket(table);
+        final var tagTable = TableHelper.getTable(AbstractLogRecord.ADDITIONAL_TAG_TABLE, timeBucket);
         if (!CollectionUtils.isEmpty(tags)) {
             for (int i = 0; i < tags.size(); i++) {
-                sql.append(" inner join ").append(AbstractLogRecord.ADDITIONAL_TAG_TABLE).append(" ");
-                sql.append(AbstractLogRecord.ADDITIONAL_TAG_TABLE + i);
-                sql.append(" on ").append(LogRecord.INDEX_NAME).append(".").append(ID_COLUMN).append(" = ");
-                sql.append(AbstractLogRecord.ADDITIONAL_TAG_TABLE + i).append(".").append(ID_COLUMN);
+                sql.append(" inner join ").append(tagTable).append(" ");
+                sql.append(tagTable + i);
+                sql.append(" on ").append(table).append(".").append(JDBCTableInstaller.ID_COLUMN).append(" = ");
+                sql.append(tagTable + i).append(".").append(JDBCTableInstaller.ID_COLUMN);
             }
         }
         sql.append(" where ");
-        sql.append(" 1=1 ");
+        sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(LogRecord.INDEX_NAME);
         if (startSecondTB != 0 && endSecondTB != 0) {
-            sql.append(" and ").append(LogRecord.INDEX_NAME).append(".").append(AbstractLogRecord.TIME_BUCKET).append(" >= ?");
+            sql.append(" and ").append(table).append(".").append(AbstractLogRecord.TIME_BUCKET).append(" >= ?");
             parameters.add(startSecondTB);
-            sql.append(" and ").append(LogRecord.INDEX_NAME).append(".").append(AbstractLogRecord.TIME_BUCKET).append(" <= ?");
+            sql.append(" and ").append(table).append(".").append(AbstractLogRecord.TIME_BUCKET).append(" <= ?");
             parameters.add(endSecondTB);
         }
 
         if (StringUtil.isNotEmpty(serviceId)) {
-            sql.append(" and ").append(LogRecord.INDEX_NAME).append(".").append(SERVICE_ID).append(" = ?");
+            sql.append(" and ").append(table).append(".").append(SERVICE_ID).append(" = ?");
             parameters.add(serviceId);
         }
         if (StringUtil.isNotEmpty(serviceInstanceId)) {
@@ -142,58 +236,18 @@ public Logs queryLogs(String serviceId,
 
         if (CollectionUtils.isNotEmpty(tags)) {
             for (int i = 0; i < tags.size(); i++) {
-                final int foundIdx = searchableTagKeys.indexOf(tags.get(i).getKey());
-                if (foundIdx > -1) {
-                    sql.append(" and ").append(AbstractLogRecord.ADDITIONAL_TAG_TABLE + i).append(".");
-                    sql.append(AbstractLogRecord.TAGS).append(" = ?");
-                    parameters.add(tags.get(i).toString());
-                } else {
-                    //If the tag is not searchable, but is required, then don't need to run the real query.
-                    return new Logs();
-                }
+                sql.append(" and ").append(tagTable + i).append(".");
+                sql.append(AbstractLogRecord.TAGS).append(" = ?");
+                parameters.add(tags.get(i).toString());
             }
         }
-
         sql.append(" order by ")
            .append(TIMESTAMP)
            .append(" ")
            .append(Order.DES.equals(queryOrder) ? "desc" : "asc");
 
-        Logs logs = new Logs();
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            buildLimit(sql, from, limit);
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, "select * " + sql.toString(), parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    Log log = new Log();
-                    log.setServiceId(resultSet.getString(SERVICE_ID));
-                    log.setServiceInstanceId(resultSet.getString(SERVICE_INSTANCE_ID));
-                    log.setEndpointId(resultSet.getString(ENDPOINT_ID));
-                    if (log.getEndpointId() != null) {
-                        log.setEndpointName(IDManager.EndpointID.analysisId(log.getEndpointId()).getEndpointName());
-                    }
-                    log.setTraceId(resultSet.getString(TRACE_ID));
-                    log.setTimestamp(resultSet.getLong(TIMESTAMP));
-                    log.setContentType(ContentType.instanceOf(resultSet.getInt(CONTENT_TYPE)));
-                    log.setContent(resultSet.getString(CONTENT));
-                    String dataBinaryBase64 = resultSet.getString(TAGS_RAW_DATA);
-                    if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
-                        parserDataBinary(dataBinaryBase64, log.getTags());
-                    }
-                    logs.getLogs().add(log);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-
-        return logs;
-    }
+        sql.append(" limit ").append(from + limit);
 
-    protected void buildLimit(StringBuilder sql, int from, int limit) {
-        sql.append(" LIMIT ").append(limit);
-        sql.append(" OFFSET ").append(from);
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCManagementDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCManagementDAO.java
index 1a335a6d61a8..b19e899ad1c6 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCManagementDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCManagementDAO.java
@@ -18,25 +18,26 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
+import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.oap.server.core.analysis.management.ManagementData;
 import org.apache.skywalking.oap.server.core.storage.IManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageData;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
-import lombok.RequiredArgsConstructor;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
 
 /**
  * Synchronize storage H2 implements
  */
 @RequiredArgsConstructor
 public class JDBCManagementDAO extends JDBCSQLExecutor implements IManagementDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final StorageBuilder<ManagementData> storageBuilder;
 
     @Override
@@ -47,7 +48,7 @@ public void insert(Model model, ManagementData storageData) throws IOException {
                 return;
             }
 
-            SQLExecutor insertExecutor = getInsertExecutor(model.getName(), storageData, storageBuilder,
+            SQLExecutor insertExecutor = getInsertExecutor(model, storageData, 0, storageBuilder,
                                                            new HashMapConverter.ToStorage(), null);
             insertExecutor.invoke(connection);
         } catch (IOException | SQLException e) {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetadataQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetadataQueryDAO.java
index cc3647f2c5f3..9db398be28a4 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetadataQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetadataQueryDAO.java
@@ -22,15 +22,8 @@
 import com.google.gson.Gson;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
-import lombok.RequiredArgsConstructor;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
@@ -48,249 +41,406 @@
 import org.apache.skywalking.oap.server.core.query.type.Service;
 import org.apache.skywalking.oap.server.core.query.type.ServiceInstance;
 import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCEntityConverters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.stream.Collectors.toList;
+import static org.apache.skywalking.oap.server.core.analysis.manual.instance.InstanceTraffic.PropertyUtil.LANGUAGE;
 
-@RequiredArgsConstructor
 public class JDBCMetadataQueryDAO implements IMetadataQueryDAO {
     private static final Gson GSON = new Gson();
 
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final int metadataQueryMaxSize;
+    private final TableHelper tableHelper;
+
+    public JDBCMetadataQueryDAO(JDBCClient jdbcClient, int metadataQueryMaxSize, ModuleManager moduleManager) {
+        this.jdbcClient = jdbcClient;
+        this.metadataQueryMaxSize = metadataQueryMaxSize;
+        this.tableHelper = new TableHelper(moduleManager, jdbcClient);
+    }
 
     @Override
-    public List<Service> listServices(final String layer, final String group) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(ServiceTraffic.INDEX_NAME);
-        if (StringUtil.isNotEmpty(layer) || StringUtil.isNotEmpty(group)) {
-            sql.append(" where ");
+    @SneakyThrows
+    public List<Service> listServices(final String layer, final String group) {
+        final var results = new ArrayList<Service>();
+        final var tables = tableHelper.getTablesWithinTTL(ServiceTraffic.INDEX_NAME);
+
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQLForListServices(layer, group, table);
+            results.addAll(jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                this::buildServices,
+                sqlAndParameters.parameters())
+            );
         }
+        return results
+            .stream()
+            .limit(metadataQueryMaxSize)
+            .collect(toList());
+    }
+
+    protected SQLAndParameters buildSQLForListServices(String layer, String group, String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>(5);
+        sql.append("select * from ").append(table)
+           .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        parameters.add(ServiceTraffic.INDEX_NAME);
 
         if (StringUtil.isNotEmpty(layer)) {
-            sql.append(ServiceTraffic.LAYER).append("=?");
-            condition.add(Layer.valueOf(layer).value());
-        }
-        if (StringUtil.isNotEmpty(layer) && StringUtil.isNotEmpty(group)) {
-            sql.append(" and ");
+            sql.append(" and ").append(ServiceTraffic.LAYER).append(" = ?");
+            parameters.add(Layer.valueOf(layer).value());
         }
         if (StringUtil.isNotEmpty(group)) {
-            sql.append(ServiceTraffic.GROUP).append("=?");
-            condition.add(group);
+            sql.append(" and ").append(ServiceTraffic.GROUP).append(" = ?");
+            parameters.add(group);
         }
 
         sql.append(" limit ").append(metadataQueryMaxSize);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildServices(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     @Override
-    public List<Service> getServices(final String serviceId) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(ServiceTraffic.INDEX_NAME).append(" where ");
-        sql.append(ServiceTraffic.SERVICE_ID).append(" = ?");
-        condition.add(serviceId);
-        sql.append(" limit ").append(metadataQueryMaxSize);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]));
-            return buildServices(resultSet);
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public List<Service> getServices(final String serviceId) {
+        final var tables = tableHelper.getTablesWithinTTL(ServiceTraffic.INDEX_NAME);
+        final var results = new ArrayList<Service>();
+
+        for (String table : tables) {
+            final SQLAndParameters sqlAndParameters = buildSQLForGetServices(serviceId, table);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildServices,
+                    sqlAndParameters.parameters()
+                )
+            );
         }
+        return results
+            .stream()
+            .limit(metadataQueryMaxSize)
+            .collect(toList());
     }
 
-    @Override
-    public List<ServiceInstance> listInstances(Duration duration,
-                                               String serviceId) throws IOException {
-        final long minuteTimeBucket = TimeBucket.getMinuteTimeBucket(duration.getStartTimestamp());
-
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(InstanceTraffic.INDEX_NAME).append(" where ");
-        sql.append(InstanceTraffic.LAST_PING_TIME_BUCKET).append(" >= ?");
-        condition.add(minuteTimeBucket);
-        sql.append(" and ").append(InstanceTraffic.SERVICE_ID).append("=?");
-        condition.add(serviceId);
+    protected SQLAndParameters buildSQLForGetServices(String serviceId, String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>(5);
+        sql.append("select * from ").append(table)
+           .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?")
+           .append(" and ").append(ServiceTraffic.SERVICE_ID).append(" = ?");
+        parameters.add(ServiceTraffic.INDEX_NAME);
+        parameters.add(serviceId);
         sql.append(" limit ").append(metadataQueryMaxSize);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]));
-            return buildInstances(resultSet);
+        return new SQLAndParameters(sql.toString(), parameters);
+    }
 
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @Override
+    @SneakyThrows
+    public List<ServiceInstance> listInstances(Duration duration,
+                                               String serviceId) {
+        final var results = new ArrayList<ServiceInstance>();
+
+        final var minuteTimeBucket = TimeBucket.getMinuteTimeBucket(duration.getStartTimestamp());
+
+        final var tables = tableHelper.getTablesForRead(
+            InstanceTraffic.INDEX_NAME,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQLForListInstances(serviceId, minuteTimeBucket, table);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildInstances,
+                    sqlAndParameters.parameters()
+                )
+            );
         }
+
+        return results
+            .stream()
+            .limit(metadataQueryMaxSize)
+            .collect(toList());
     }
 
-    @Override
-    public ServiceInstance getInstance(final String instanceId) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(InstanceTraffic.INDEX_NAME).append(" where ");
-        sql.append(H2TableInstaller.ID_COLUMN).append(" = ?");
-        condition.add(instanceId);
+    protected SQLAndParameters buildSQLForListInstances(String serviceId, long minuteTimeBucket, String table) {
+        final var  sql = new StringBuilder();
+        final var parameters = new ArrayList<>(5);
+        sql.append("select * from ").append(table).append(" where ")
+            .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(InstanceTraffic.INDEX_NAME);
+        sql.append(" and ").append(InstanceTraffic.LAST_PING_TIME_BUCKET).append(" >= ?");
+        parameters.add(minuteTimeBucket);
+        sql.append(" and ").append(InstanceTraffic.SERVICE_ID).append("=?");
+        parameters.add(serviceId);
         sql.append(" limit ").append(metadataQueryMaxSize);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]));
-            final List<ServiceInstance> instances = buildInstances(resultSet);
-            return instances.size() > 0 ? instances.get(0) : null;
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     @Override
-    public List<Endpoint> findEndpoint(String keyword, String serviceId, int limit) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(EndpointTraffic.INDEX_NAME).append(" where ");
-        sql.append(EndpointTraffic.SERVICE_ID).append("=?");
-        condition.add(serviceId);
-        if (!Strings.isNullOrEmpty(keyword)) {
-            sql.append(" and ").append(EndpointTraffic.NAME).append(" like concat('%',?,'%') ");
-            condition.add(keyword);
-        }
-        sql.append(" limit ").append(limit);
-
-        List<Endpoint> endpoints = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-
-                while (resultSet.next()) {
-                    Endpoint endpoint = new Endpoint();
-                    endpoint.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));
-                    endpoint.setName(resultSet.getString(EndpointTraffic.NAME));
-                    endpoints.add(endpoint);
-                }
+    @SneakyThrows
+    public ServiceInstance getInstance(final String instanceId) {
+        final var tables = tableHelper.getTablesWithinTTL(InstanceTraffic.INDEX_NAME);
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(5);
+            sql.append("select * from ").append(table).append(" where ")
+                .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(InstanceTraffic.INDEX_NAME);
+            sql.append(" and ").append(JDBCTableInstaller.ID_COLUMN).append(" = ?");
+            condition.add(instanceId);
+            sql.append(" limit ").append(metadataQueryMaxSize);
+
+            final var result = jdbcClient.executeQuery(sql.toString(), resultSet -> {
+                final List<ServiceInstance> instances = buildInstances(resultSet);
+                return instances.size() > 0 ? instances.get(0) : null;
+            }, condition.toArray(new Object[0]));
+            if (result != null) {
+                return result;
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
         }
-        return endpoints;
+
+        return null;
     }
 
     @Override
-    public List<Process> listProcesses(String serviceId, ProfilingSupportStatus supportStatus, long lastPingStartTimeBucket, long lastPingEndTimeBucket) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>();
-        sql.append("select * from ").append(ProcessTraffic.INDEX_NAME);
-        appendProcessWhereQuery(sql, condition, serviceId, null, null, supportStatus, lastPingStartTimeBucket, lastPingEndTimeBucket, false);
-        sql.append(" limit ").append(metadataQueryMaxSize);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildProcesses(resultSet);
+    @SneakyThrows
+    public List<Endpoint> findEndpoint(String keyword, String serviceId, int limit) {
+        final var results = new ArrayList<Endpoint>();
+        final var tables = tableHelper.getTablesWithinTTL(EndpointTraffic.INDEX_NAME);
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(5);
+            sql.append("select * from ").append(table).append(" where ")
+                .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(EndpointTraffic.INDEX_NAME);
+            sql.append(" and ").append(EndpointTraffic.SERVICE_ID).append("=?");
+            condition.add(serviceId);
+            sql.append(" and ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(EndpointTraffic.INDEX_NAME);
+            if (!Strings.isNullOrEmpty(keyword)) {
+                sql.append(" and ").append(EndpointTraffic.NAME).append(" like concat('%',?,'%') ");
+                condition.add(keyword);
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            sql.append(" limit ").append(limit);
+
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sql.toString(), resultSet -> {
+                        List<Endpoint> endpoints = new ArrayList<>();
+
+                        while (resultSet.next()) {
+                            final var endpointTraffic = new EndpointTraffic.Builder().storage2Entity(JDBCEntityConverters.toEntity(resultSet));
+
+                            Endpoint endpoint = new Endpoint();
+                            endpoint.setId(endpointTraffic.id().build());
+                            endpoint.setName(endpointTraffic.getName());
+                            endpoints.add(endpoint);
+                        }
+                        return endpoints;
+                    }, condition.toArray(new Object[0])));
         }
+        return results.stream().limit(limit).collect(toList());
     }
 
     @Override
-    public List<Process> listProcesses(String serviceInstanceId, Duration duration, boolean includeVirtual) throws IOException {
-        long lastPingStartTimeBucket = duration.getStartTimeBucket();
-        long lastPingEndTimeBucket = duration.getEndTimeBucket();
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>();
-        sql.append("select * from ").append(ProcessTraffic.INDEX_NAME);
-        appendProcessWhereQuery(sql, condition, null, serviceInstanceId, null, null, lastPingStartTimeBucket, lastPingEndTimeBucket, includeVirtual);
+    @SneakyThrows
+    public List<Process> listProcesses(String serviceId, ProfilingSupportStatus supportStatus, long lastPingStartTimeBucket, long lastPingEndTimeBucket) {
+        final var tables = tableHelper.getTablesForRead(
+            ProcessTraffic.INDEX_NAME,
+            lastPingStartTimeBucket,
+            lastPingEndTimeBucket
+        );
+        final var results = new ArrayList<Process>();
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQLForListProcesses(serviceId, supportStatus, lastPingStartTimeBucket, lastPingEndTimeBucket, table);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildProcesses,
+                    sqlAndParameters.parameters()
+                )
+            );
+        }
+
+        return results
+            .stream()
+            .limit(metadataQueryMaxSize)
+            .collect(toList());
+    }
+
+    protected SQLAndParameters buildSQLForListProcesses(
+        final String serviceId,
+        final ProfilingSupportStatus supportStatus,
+        final long lastPingStartTimeBucket,
+        final long lastPingEndTimeBucket,
+        final String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>();
+        sql.append("select * from ").append(table);
+        sql.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        parameters.add(ProcessTraffic.INDEX_NAME);
+        appendProcessWhereQuery(sql, parameters, serviceId, null, null, supportStatus, lastPingStartTimeBucket, lastPingEndTimeBucket, false);
         sql.append(" limit ").append(metadataQueryMaxSize);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildProcesses(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     @Override
-    public List<Process> listProcesses(String agentId) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(2);
-        sql.append("select * from ").append(ProcessTraffic.INDEX_NAME);
-        appendProcessWhereQuery(sql, condition, null, null, agentId, null, 0, 0, false);
+    @SneakyThrows
+    public List<Process> listProcesses(String serviceInstanceId, Duration duration, boolean includeVirtual) {
+        final var tables = tableHelper.getTablesForRead(
+            ProcessTraffic.INDEX_NAME,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var results = new ArrayList<Process>();
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQLForListProcesses(serviceInstanceId, duration, includeVirtual, table);
+
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    this::buildProcesses,
+                    sqlAndParameters.parameters()
+                )
+            );
+        }
+
+        return results
+            .stream()
+            .limit(metadataQueryMaxSize)
+            .collect(toList());
+    }
+
+    protected SQLAndParameters buildSQLForListProcesses(String serviceInstanceId, Duration duration, boolean includeVirtual, String table) {
+        final var lastPingStartTimeBucket = duration.getStartTimeBucket();
+        final var lastPingEndTimeBucket = duration.getEndTimeBucket();
+        final var sql = new StringBuilder();
+        final var condition = new ArrayList<>();
+        sql.append("select * from ").append(table);
+        sql.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        condition.add(ProcessTraffic.INDEX_NAME);
+        appendProcessWhereQuery(sql, condition, null, serviceInstanceId, null, null, lastPingStartTimeBucket, lastPingEndTimeBucket, includeVirtual);
         sql.append(" limit ").append(metadataQueryMaxSize);
+        return new SQLAndParameters(sql.toString(), condition);
+    }
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return buildProcesses(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @Override
+    @SneakyThrows
+    public List<Process> listProcesses(String agentId) {
+        final var tables = tableHelper.getTablesWithinTTL(ProcessTraffic.INDEX_NAME);
+        final var results = new ArrayList<Process>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(2);
+            sql.append("select * from ").append(table);
+            sql.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+            condition.add(ProcessTraffic.INDEX_NAME);
+            appendProcessWhereQuery(sql, condition, null, null, agentId, null, 0, 0, false);
+            sql.append(" limit ").append(metadataQueryMaxSize);
+
+            results.addAll(
+                jdbcClient.executeQuery(sql.toString(), this::buildProcesses, condition.toArray(new Object[0]))
+            );
         }
+
+        return results
+            .stream()
+            .limit(metadataQueryMaxSize)
+            .collect(toList());
     }
 
     @Override
-    public long getProcessCount(String serviceId, ProfilingSupportStatus profilingSupportStatus, long lastPingStartTimeBucket, long lastPingEndTimeBucket) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select count(1) total from ").append(ProcessTraffic.INDEX_NAME);
-        appendProcessWhereQuery(sql, condition, serviceId, null, null, profilingSupportStatus,
-            lastPingStartTimeBucket, lastPingEndTimeBucket, false);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
+    @SneakyThrows
+    public long getProcessCount(String serviceId, ProfilingSupportStatus profilingSupportStatus, long lastPingStartTimeBucket, long lastPingEndTimeBucket) {
+        final var tables = tableHelper.getTablesForRead(
+            ProcessTraffic.INDEX_NAME,
+            lastPingStartTimeBucket,
+            lastPingEndTimeBucket
+        );
+        long total = 0;
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(5);
+            sql.append("select count(1) total from ").append(table);
+            sql.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+            condition.add(ProcessTraffic.INDEX_NAME);
+
+            appendProcessWhereQuery(sql, condition, serviceId, null, null, profilingSupportStatus,
+                lastPingStartTimeBucket, lastPingEndTimeBucket, false);
+
+            total += jdbcClient.executeQuery(sql.toString(), resultSet -> {
                 if (!resultSet.next()) {
-                    return 0;
+                    return 0L;
                 }
                 return resultSet.getLong("total");
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            }, condition.toArray(new Object[0]));
         }
+
+        return total;
     }
 
     @Override
-    public long getProcessCount(String instanceId) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(3);
-        sql.append("select count(1) total from ").append(ProcessTraffic.INDEX_NAME);
-        appendProcessWhereQuery(sql, condition, null, instanceId, null, null, 0, 0, false);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
+    @SneakyThrows
+    public long getProcessCount(String instanceId) {
+        final var tables = tableHelper.getTablesWithinTTL(ProcessTraffic.INDEX_NAME);
+        long total = 0;
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(3);
+            sql.append("select count(1) total from ").append(table);
+            sql.append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+            condition.add(ProcessTraffic.INDEX_NAME);
+
+            appendProcessWhereQuery(sql, condition, null, instanceId, null, null, 0, 0, false);
+
+            total += jdbcClient.executeQuery(sql.toString(), resultSet -> {
                 if (!resultSet.next()) {
-                    return 0;
+                    return 0L;
                 }
                 return resultSet.getLong("total");
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            }, condition.toArray(new Object[0]));
         }
+
+        return total;
     }
 
     private List<Service> buildServices(ResultSet resultSet) throws SQLException {
         List<Service> services = new ArrayList<>();
         while (resultSet.next()) {
-            String serviceName = resultSet.getString(ServiceTraffic.NAME);
+            final var serviceTraffic = new ServiceTraffic.Builder().storage2Entity(JDBCEntityConverters.toEntity(resultSet));
+
+            String serviceName = serviceTraffic.getName();
             Service service = new Service();
-            service.setId(resultSet.getString(ServiceTraffic.SERVICE_ID));
+            service.setId(serviceTraffic.getServiceId());
             service.setName(serviceName);
-            service.setShortName(resultSet.getString(ServiceTraffic.SHORT_NAME));
-            service.setGroup(resultSet.getString(ServiceTraffic.GROUP));
-            service.getLayers().add(Layer.valueOf(resultSet.getInt(ServiceTraffic.LAYER)).name());
+            service.setShortName(serviceTraffic.getShortName());
+            service.setGroup(serviceTraffic.getGroup());
+            service.getLayers().add(serviceTraffic.getLayer().name());
             services.add(service);
         }
         return services;
@@ -300,28 +450,28 @@ private List<ServiceInstance> buildInstances(ResultSet resultSet) throws SQLExce
         List<ServiceInstance> serviceInstances = new ArrayList<>();
 
         while (resultSet.next()) {
+            final var instanceTraffic =
+                new InstanceTraffic.Builder().storage2Entity(JDBCEntityConverters.toEntity(resultSet));
+
             ServiceInstance serviceInstance = new ServiceInstance();
-            serviceInstance.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));
-            serviceInstance.setName(resultSet.getString(InstanceTraffic.NAME));
+            serviceInstance.setId(instanceTraffic.id().build());
+            serviceInstance.setName(instanceTraffic.getName());
             serviceInstance.setInstanceUUID(serviceInstance.getId());
 
-            String propertiesString = resultSet.getString(InstanceTraffic.PROPERTIES);
-            if (!Strings.isNullOrEmpty(propertiesString)) {
-                JsonObject properties = GSON.fromJson(propertiesString, JsonObject.class);
+            JsonObject properties = instanceTraffic.getProperties();
+            if (properties != null) {
                 for (Map.Entry<String, JsonElement> property : properties.entrySet()) {
                     String key = property.getKey();
                     String value = property.getValue().getAsString();
-                    if (key.equals(InstanceTraffic.PropertyUtil.LANGUAGE)) {
+                    if (key.equals(LANGUAGE)) {
                         serviceInstance.setLanguage(Language.value(value));
                     } else {
                         serviceInstance.getAttributes().add(new Attribute(key, value));
                     }
-
                 }
             } else {
                 serviceInstance.setLanguage(Language.UNKNOWN);
             }
-
             serviceInstances.add(serviceInstance);
         }
         return serviceInstances;
@@ -331,12 +481,8 @@ private void appendProcessWhereQuery(StringBuilder sql, List<Object> condition,
                                          String agentId, final ProfilingSupportStatus profilingSupportStatus,
                                          final long lastPingStartTimeBucket, final long lastPingEndTimeBucket,
                                          boolean includeVirtual) {
-        if (StringUtil.isNotEmpty(serviceId) || StringUtil.isNotEmpty(instanceId) || StringUtil.isNotEmpty(agentId)) {
-            sql.append(" where ");
-        }
-
         if (StringUtil.isNotEmpty(serviceId)) {
-            sql.append(ProcessTraffic.SERVICE_ID).append("=?");
+            sql.append(" and ").append(ProcessTraffic.SERVICE_ID).append("=?");
             condition.add(serviceId);
         }
         if (StringUtil.isNotEmpty(instanceId)) {
@@ -377,56 +523,65 @@ private void appendProcessWhereQuery(StringBuilder sql, List<Object> condition,
     }
 
     @Override
-    public Process getProcess(String processId) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(ProcessTraffic.INDEX_NAME).append(" where ");
-        sql.append(H2TableInstaller.ID_COLUMN).append(" = ?");
-        condition.add(processId);
-        sql.append(" limit ").append(metadataQueryMaxSize);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(
-                    connection, sql.toString(), condition.toArray(new Object[0]));
-            final List<Process> processes = buildProcesses(resultSet);
-            return processes.size() > 0 ? processes.get(0) : null;
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public Process getProcess(String processId) {
+        final var tables = tableHelper.getTablesWithinTTL(ProcessTraffic.INDEX_NAME);
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(5);
+            sql.append("select * from ").append(table).append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+            condition.add(ProcessTraffic.INDEX_NAME);
+            sql.append(" and ").append(JDBCTableInstaller.ID_COLUMN).append(" = ?");
+            condition.add(processId);
+            sql.append(" limit ").append(metadataQueryMaxSize);
+
+            final var result = jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> {
+                    final List<Process> processes = buildProcesses(resultSet);
+                    return processes.size() > 0 ? processes.get(0) : null;
+                },
+                condition.toArray(new Object[0]));
+            if (result != null) {
+                return result;
+            }
         }
+        return null;
     }
 
     private List<Process> buildProcesses(ResultSet resultSet) throws SQLException {
         List<Process> processes = new ArrayList<>();
         while (resultSet.next()) {
-            final Process process = new Process();
-            process.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));
-            process.setName(resultSet.getString(ProcessTraffic.NAME));
-            final String serviceId = resultSet.getString(ProcessTraffic.SERVICE_ID);
+            final var processTraffic = new ProcessTraffic.Builder().storage2Entity(JDBCEntityConverters.toEntity(resultSet));
+
+            Process process = new Process();
+            process.setId(processTraffic.id().build());
+            process.setName(processTraffic.getName());
+            final String serviceId = processTraffic.getServiceId();
             process.setServiceId(serviceId);
-            final IDManager.ServiceID.ServiceIDDefinition serviceIDDefinition = IDManager.ServiceID.analysisId(serviceId);
-            process.setServiceName(serviceIDDefinition.getName());
-            final String instanceId = resultSet.getString(ProcessTraffic.INSTANCE_ID);
+            process.setServiceName(IDManager.ServiceID.analysisId(serviceId).getName());
+            final String instanceId = processTraffic.getInstanceId();
             process.setInstanceId(instanceId);
-            final IDManager.ServiceInstanceID.InstanceIDDefinition instanceIDDefinition = IDManager.ServiceInstanceID.analysisId(instanceId);
-            process.setInstanceName(instanceIDDefinition.getName());
-            process.setAgentId(resultSet.getString(ProcessTraffic.AGENT_ID));
-            process.setDetectType(ProcessDetectType.valueOf(resultSet.getInt(ProcessTraffic.DETECT_TYPE)).name());
-            process.setProfilingSupportStatus(ProfilingSupportStatus.valueOf(resultSet.getInt(ProcessTraffic.PROFILING_SUPPORT_STATUS)).name());
-            String propertiesString = resultSet.getString(ProcessTraffic.PROPERTIES);
-            if (!Strings.isNullOrEmpty(propertiesString)) {
-                JsonObject properties = GSON.fromJson(propertiesString, JsonObject.class);
+            process.setInstanceName(IDManager.ServiceInstanceID.analysisId(instanceId).getName());
+            process.setAgentId(processTraffic.getAgentId());
+            process.setDetectType(ProcessDetectType.valueOf(processTraffic.getDetectType()).name());
+            process.setProfilingSupportStatus(ProfilingSupportStatus.valueOf(processTraffic.getProfilingSupportStatus()).name());
+
+            JsonObject properties = processTraffic.getProperties();
+            if (properties != null) {
                 for (Map.Entry<String, JsonElement> property : properties.entrySet()) {
                     String key = property.getKey();
                     String value = property.getValue().getAsString();
                     process.getAttributes().add(new Attribute(key, value));
                 }
             }
-            final String labelJsonString = resultSet.getString(ProcessTraffic.LABELS_JSON);
-            if (!Strings.isNullOrEmpty(labelJsonString)) {
-                List<String> labels = GSON.<List<String>>fromJson(labelJsonString, ArrayList.class);
+            final String labelsJson = processTraffic.getLabelsJson();
+            if (StringUtils.isNotEmpty(labelsJson)) {
+                final List<String> labels = GSON.<List<String>>fromJson(labelsJson, ArrayList.class);
                 process.getLabels().addAll(labels);
             }
-
             processes.add(process);
         }
         return processes;
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsDAO.java
index 082bf2d9137f..db036e86c2d5 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsDAO.java
@@ -18,10 +18,7 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.storage.IMetricsDAO;
 import org.apache.skywalking.oap.server.core.storage.SessionCacheCallback;
@@ -29,20 +26,26 @@
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
-import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
 
 @RequiredArgsConstructor
 public class JDBCMetricsDAO extends JDBCSQLExecutor implements IMetricsDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final StorageBuilder<Metrics> storageBuilder;
 
     @Override
-    public List<Metrics> multiGet(Model model, List<Metrics> metrics) throws IOException {
-        String[] ids = metrics.stream().map(m -> m.id().build()).collect(Collectors.toList()).toArray(new String[] {});
-        List<StorageData> storageDataList = getByIDs(jdbcClient, model.getName(), ids, storageBuilder);
-        List<Metrics> result = new ArrayList<>(storageDataList.size());
+    public List<Metrics> multiGet(Model model, List<Metrics> metrics) throws Exception {
+        final var ids = metrics.stream().map(m -> TableHelper.generateId(model, m.id().build())).collect(toList());
+        final var storageDataList = getByIDs(jdbcClient, model.getName(), ids, storageBuilder);
+        final var result = new ArrayList<Metrics>(storageDataList.size());
         for (StorageData storageData : storageDataList) {
             result.add((Metrics) storageData);
         }
@@ -51,11 +54,11 @@ public List<Metrics> multiGet(Model model, List<Metrics> metrics) throws IOExcep
 
     @Override
     public SQLExecutor prepareBatchInsert(Model model, Metrics metrics, SessionCacheCallback callback) throws IOException {
-        return getInsertExecutor(model.getName(), metrics, storageBuilder, new HashMapConverter.ToStorage(), callback);
+        return getInsertExecutor(model, metrics, metrics.getTimeBucket(), storageBuilder, new HashMapConverter.ToStorage(), callback);
     }
 
     @Override
-    public SQLExecutor prepareBatchUpdate(Model model, Metrics metrics, SessionCacheCallback callback) throws IOException {
-        return getUpdateExecutor(model.getName(), metrics, storageBuilder, callback);
+    public SQLExecutor prepareBatchUpdate(Model model, Metrics metrics, SessionCacheCallback callback) {
+        return getUpdateExecutor(model, metrics, metrics.getTimeBucket(), storageBuilder, callback);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsQueryDAO.java
index 303c4c304a62..19edf4bb2d03 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCMetricsQueryDAO.java
@@ -18,45 +18,52 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.query.PointOfTime;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.input.MetricsCondition;
 import org.apache.skywalking.oap.server.core.query.sql.Function;
 import org.apache.skywalking.oap.server.core.query.type.HeatMap;
-import org.apache.skywalking.oap.server.core.query.type.IntValues;
 import org.apache.skywalking.oap.server.core.query.type.KVInt;
 import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
 import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @RequiredArgsConstructor
 public class JDBCMetricsQueryDAO extends JDBCSQLExecutor implements IMetricsQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
+    @SneakyThrows
     public long readMetricsValue(final MetricsCondition condition,
                                 String valueColumnName,
-                                final Duration duration) throws IOException {
-        final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
-        List<String> ids = new ArrayList<>(pointOfTimes.size());
-        final String entityId = condition.getEntity().buildId();
-        pointOfTimes.forEach(pointOfTime -> {
-            ids.add(pointOfTime.id(entityId));
-        });
-        int defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
-        final Function function = ValueColumnMetadata.INSTANCE.getValueFunction(condition.getName());
+                                final Duration duration) {
+        final var tables = tableHelper.getTablesForRead(
+            condition.getName(),
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+
+        final var pointOfTimes = duration.assembleDurationPoints();
+        final var entityId = condition.getEntity().buildId();
+        final var ids =
+            pointOfTimes
+                .stream()
+                .map(pointOfTime -> TableHelper.generateId(condition.getName(), pointOfTime.id(entityId)))
+                .collect(Collectors.toList());
+        final var defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
+        final var function = ValueColumnMetadata.INSTANCE.getValueFunction(condition.getName());
         if (function == Function.Latest) {
             return readMetricsValues(condition, valueColumnName, duration).getValues().latestValue(defaultValue);
         }
@@ -68,38 +75,37 @@ public long readMetricsValue(final MetricsCondition condition,
             default:
                 op = "sum";
         }
-        StringBuilder sql = buildMetricsValueSql(op, valueColumnName, condition.getName());
-        List<Object> parameters = new ArrayList();
-        if (entityId != null) {
-            sql.append(Metrics.ENTITY_ID + " = ? and ");
-            parameters.add(entityId);
-        }
-        sql.append("id in (");
-        for (int i = 0; i < ids.size(); i++) {
-            if (i == 0) {
-                sql.append("?");
-            } else {
-                sql.append(",?");
+
+        final var results = new ArrayList<Long>();
+        for (String table : tables) {
+            final var sql = buildMetricsValueSql(op, valueColumnName, table);
+            final var parameters = new ArrayList<>();
+            if (entityId != null) {
+                sql.append(Metrics.ENTITY_ID + " = ? and ");
+                parameters.add(entityId);
             }
-            parameters.add(ids.get(i));
-        }
-        sql.append(")");
-        sql.append(" group by " + Metrics.ENTITY_ID);
+            sql.append("id in ");
+            sql.append(ids.stream().map(it -> "?").collect(Collectors.joining(", ", "(", ")")));
+            parameters.addAll(ids);
+            sql.append(" and ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            parameters.add(condition.getName());
+            sql.append(" group by " + Metrics.ENTITY_ID);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection,
+            results.add(jdbcClient.executeQuery(
                 sql.toString(),
+                resultSet -> {
+                    if (resultSet.next()) {
+                        return resultSet.getLong("result");
+                    }
+                    return (long) defaultValue;
+                },
                 parameters.toArray(new Object[0])
-            )) {
-                if (resultSet.next()) {
-                    return resultSet.getLong("result");
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            ));
         }
-        return defaultValue;
+        if (op.equals("avg")) {
+            return results.stream().mapToLong(it -> it).sum() / results.size();
+        }
+        return results.stream().mapToLong(it -> it).sum();
     }
 
     protected StringBuilder buildMetricsValueSql(String op, String valueColumnName, String conditionName) {
@@ -108,48 +114,51 @@ protected StringBuilder buildMetricsValueSql(String op, String valueColumnName,
     }
 
     @Override
+    @SneakyThrows
     public MetricsValues readMetricsValues(final MetricsCondition condition,
                                            final String valueColumnName,
-                                           final Duration duration) throws IOException {
-        final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
-        List<String> ids = new ArrayList<>(pointOfTimes.size());
-        final String entityId = condition.getEntity().buildId();
-        pointOfTimes.forEach(pointOfTime -> {
-            ids.add(pointOfTime.id(entityId));
-        });
-
-        StringBuilder sql = new StringBuilder(
-            "select id, " + valueColumnName + " from " + condition.getName() + " where id in (");
-        List<Object> parameters = new ArrayList();
-        for (int i = 0; i < ids.size(); i++) {
-            if (i == 0) {
-                sql.append("?");
-            } else {
-                sql.append(",?");
-            }
-            parameters.add(ids.get(i));
-        }
-        sql.append(")");
+                                           final Duration duration) {
+        final var metricsValues = new MetricsValues();
+        // Label is null, because in readMetricsValues, no label parameter.
+        final var intValues = metricsValues.getValues();
+
+        final var tables = tableHelper.getTablesForRead(
+            condition.getName(),
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
 
-        buildShardingCondition(sql, parameters, entityId);
+        final var pointOfTimes = duration.assembleDurationPoints();
+        final var entityId = condition.getEntity().buildId();
+        final var ids =
+            pointOfTimes
+                .stream()
+                .map(pointOfTime -> TableHelper.generateId(condition.getName(), pointOfTime.id(entityId)))
+                .collect(Collectors.toList());
 
-        MetricsValues metricsValues = new MetricsValues();
-        // Label is null, because in readMetricsValues, no label parameter.
-        final IntValues intValues = metricsValues.getValues();
-
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    KVInt kv = new KVInt();
-                    kv.setId(resultSet.getString("id"));
-                    kv.setValue(resultSet.getLong(valueColumnName));
-                    intValues.addKVInt(kv);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+        for (final var table : tables) {
+            final var sql = new StringBuilder("select id, " + valueColumnName + " from " + table)
+                .append(" where id in ")
+                .append(
+                    ids.stream()
+                       .map(it -> "?")
+                       .collect(Collectors.joining(", ", "(", ")"))
+                );
+
+            buildShardingCondition(sql, ids, entityId);
+
+            jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        final var kv = new KVInt();
+                        kv.setId(resultSet.getString("id"));
+                        kv.setValue(resultSet.getLong(valueColumnName));
+                        intValues.addKVInt(kv);
+                    }
+                    return null;
+                },
+                ids.toArray(new Object[0]));
         }
 
         metricsValues.setValues(
@@ -159,49 +168,52 @@ public MetricsValues readMetricsValues(final MetricsCondition condition,
     }
 
     @Override
+    @SneakyThrows
     public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condition,
                                                         final String valueColumnName,
                                                         final List<String> labels,
-                                                        final Duration duration) throws IOException {
-        final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
-        List<String> ids = new ArrayList<>(pointOfTimes.size());
-        final String entityId = condition.getEntity().buildId();
-        pointOfTimes.forEach(pointOfTime -> {
-            ids.add(pointOfTime.id(entityId));
-        });
-
-        StringBuilder sql = new StringBuilder(
-            "select id, " + valueColumnName + " from " + condition.getName() + " where id in (");
-
-        List<Object> parameters = new ArrayList();
-        for (int i = 0; i < ids.size(); i++) {
-            if (i == 0) {
-                sql.append("?");
-            } else {
-                sql.append(",?");
-            }
-            parameters.add(ids.get(i));
-        }
-        sql.append(")");
+                                                        final Duration duration) {
+        final var idMap = new HashMap<String, DataTable>();
+        final var tables = tableHelper.getTablesForRead(
+            condition.getName(),
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
 
-        buildShardingCondition(sql, parameters, entityId);
+        final var pointOfTimes = duration.assembleDurationPoints();
+        final var entityId = condition.getEntity().buildId();
+        final var ids =
+            pointOfTimes
+                .stream()
+                .map(pointOfTime -> TableHelper.generateId(condition.getName(), pointOfTime.id(entityId)))
+                .collect(Collectors.toList());
 
-        Map<String, DataTable> idMap = new HashMap<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    String id = resultSet.getString("id");
+        for (final var table : tables) {
+            final var sql = new StringBuilder("select id, " + valueColumnName + " from " + table)
+                .append(" where id in ")
+                .append(
+                    ids.stream().map(it -> "?")
+                       .collect(Collectors.joining(", ", "(", ")"))
+                );
 
-                    DataTable multipleValues = new DataTable(5);
-                    multipleValues.toObject(resultSet.getString(valueColumnName));
+            buildShardingCondition(sql, ids, entityId);
 
-                   idMap.put(id, multipleValues);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        String id = resultSet.getString("id");
+
+                        DataTable multipleValues = new DataTable(5);
+                        multipleValues.toObject(resultSet.getString(valueColumnName));
+
+                        idMap.put(id, multipleValues);
+                    }
+                    return null;
+                },
+                ids.toArray(new Object[0]));
         }
+
         return Util.sortValues(
             Util.composeLabelValue(condition, labels, ids, idMap),
             ids,
@@ -210,52 +222,55 @@ public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condi
     }
 
     @Override
+    @SneakyThrows
     public HeatMap readHeatMap(final MetricsCondition condition,
                                final String valueColumnName,
-                               final Duration duration) throws IOException {
-        final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
-        List<String> ids = new ArrayList<>(pointOfTimes.size());
-        final String entityId = condition.getEntity().buildId();
-        pointOfTimes.forEach(pointOfTime -> {
-            ids.add(pointOfTime.id(entityId));
-        });
-
-        StringBuilder sql = new StringBuilder(
-            "select id, " + valueColumnName + " dataset, id from " + condition.getName() + " where id in (");
-        List<Object> parameters = new ArrayList();
-        for (int i = 0; i < ids.size(); i++) {
-            if (i == 0) {
-                sql.append("?");
-            } else {
-                sql.append(",?");
-            }
-            parameters.add(ids.get(i));
-        }
-        sql.append(")");
+                               final Duration duration) {
+        final var tables = tableHelper.getTablesForRead(
+            condition.getName(),
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var heatMap = new HeatMap();
 
-        buildShardingCondition(sql, parameters, entityId);
+        for (String table : tables) {
+            final var pointOfTimes = duration.assembleDurationPoints();
+            final var entityId = condition.getEntity().buildId();
+            final var ids =
+                pointOfTimes
+                    .stream()
+                    .map(pointOfTime -> TableHelper.generateId(condition.getName(), pointOfTime.id(entityId)))
+                    .collect(Collectors.toList());
 
-        final int defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
+            final var sql = new StringBuilder("select id, " + valueColumnName + " dataset, id from " + table)
+                .append(" where id in ")
+                .append(
+                    ids.stream()
+                       .map(it -> "?")
+                       .collect(Collectors.joining(", ", "(", ")"))
+                );
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            HeatMap heatMap = new HeatMap();
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), parameters.toArray(new Object[0]))) {
+            buildShardingCondition(sql, ids, entityId);
 
-                while (resultSet.next()) {
-                    heatMap.buildColumn(
-                        resultSet.getString("id"), resultSet.getString("dataset"), defaultValue);
-                }
-            }
+            final int defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
 
-            heatMap.fixMissingColumns(ids, defaultValue);
+            jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        heatMap.buildColumn(
+                            resultSet.getString("id"), resultSet.getString("dataset"), defaultValue);
+                    }
+                    heatMap.fixMissingColumns(ids, defaultValue);
 
-            return heatMap;
-        } catch (SQLException e) {
-            throw new IOException(e);
+                    return null;
+                },
+                ids.toArray(new Object[0]));
         }
+
+        return heatMap;
     }
 
-    protected void buildShardingCondition(StringBuilder sql, List<Object> parameters, String entityId) {
+    protected void buildShardingCondition(StringBuilder sql, List<String> parameters, String entityId) {
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNetworkAddressAliasDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNetworkAddressAliasDAO.java
index 63e638ff5b58..e12be5eb25e8 100755
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNetworkAddressAliasDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNetworkAddressAliasDAO.java
@@ -18,50 +18,60 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.analysis.manual.networkalias.NetworkAddressAlias;
 import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @Slf4j
-@RequiredArgsConstructor
 public class JDBCNetworkAddressAliasDAO extends JDBCSQLExecutor implements INetworkAddressAliasDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
+
+    public JDBCNetworkAddressAliasDAO(JDBCClient jdbcClient, ModuleManager moduleManager) {
+        this.jdbcClient = jdbcClient;
+        this.tableHelper = new TableHelper(moduleManager, jdbcClient);
+    }
 
     @Override
+    @SneakyThrows
     public List<NetworkAddressAlias> loadLastUpdate(long lastUpdateTime) {
-        List<NetworkAddressAlias> networkAddressAliases = new ArrayList<>();
+        final var tables = tableHelper.getTablesWithinTTL(NetworkAddressAlias.INDEX_NAME);
+        final var results = new ArrayList<NetworkAddressAlias>();
 
-        try {
-            StringBuilder sql = new StringBuilder("select * from ");
-            sql.append(NetworkAddressAlias.INDEX_NAME);
-            sql.append(" where ").append(NetworkAddressAlias.LAST_UPDATE_TIME_BUCKET).append(">?");
+        for (final var table : tables) {
+            final var sql = new StringBuilder()
+                .append("select * from ").append(table)
+                .append(" where ")
+                .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ")
+                .append(" and ").append(NetworkAddressAlias.LAST_UPDATE_TIME_BUCKET).append(">?");
 
-            try (Connection connection = jdbcClient.getConnection()) {
-                try (ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), lastUpdateTime)) {
-                    NetworkAddressAlias networkAddressAlias;
-                    do {
-                        networkAddressAlias = (NetworkAddressAlias) toStorageData(
-                            resultSet, NetworkAddressAlias.INDEX_NAME, new NetworkAddressAlias.Builder());
-                        if (networkAddressAlias != null) {
-                            networkAddressAliases.add(networkAddressAlias);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sql.toString(),
+                    resultSet -> {
+                        List<NetworkAddressAlias> networkAddressAliases = new ArrayList<>();
+                        NetworkAddressAlias networkAddressAlias;
+                        do {
+                            networkAddressAlias = (NetworkAddressAlias) toStorageData(
+                                resultSet, NetworkAddressAlias.INDEX_NAME, new NetworkAddressAlias.Builder());
+                            if (networkAddressAlias != null) {
+                                networkAddressAliases.add(networkAddressAlias);
+                            }
                         }
-                    }
-                    while (networkAddressAlias != null);
-                }
-            } catch (SQLException e) {
-                throw new IOException(e);
-            }
-        } catch (Throwable t) {
-            log.error(t.getMessage(), t);
+                        while (networkAddressAlias != null);
+                        return networkAddressAliases;
+                    },
+                    NetworkAddressAlias.INDEX_NAME, lastUpdateTime)
+            );
         }
-        return networkAddressAliases;
+        return results;
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNoneStreamDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNoneStreamDAO.java
index 7a87059e08a0..cc6f4148f244 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNoneStreamDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCNoneStreamDAO.java
@@ -18,30 +18,31 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
+import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.oap.server.core.analysis.config.NoneStream;
 import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
-import lombok.RequiredArgsConstructor;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
 
 /**
  * Synchronize storage H2 implements
  */
 @RequiredArgsConstructor
 public class JDBCNoneStreamDAO extends JDBCSQLExecutor implements INoneStreamDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final StorageBuilder<NoneStream> storageBuilder;
 
     @Override
     public void insert(Model model, NoneStream noneStream) throws IOException {
         try (Connection connection = jdbcClient.getConnection()) {
-            SQLExecutor insertExecutor = getInsertExecutor(model.getName(), noneStream, storageBuilder, new HashMapConverter.ToStorage(), null);
+            SQLExecutor insertExecutor = getInsertExecutor(model, noneStream, 0, storageBuilder, new HashMapConverter.ToStorage(), null);
             insertExecutor.invoke(connection);
         } catch (IOException | SQLException e) {
             throw new IOException(e.getMessage(), e);
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskLogQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskLogQueryDAO.java
index 290c1355983e..6866ccd408e5 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskLogQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskLogQueryDAO.java
@@ -18,43 +18,62 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskLogRecord;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTaskLog;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTaskLogOperationType;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileTaskLogQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
 
 @RequiredArgsConstructor
 public class JDBCProfileTaskLogQueryDAO implements IProfileTaskLogQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<ProfileTaskLog> getTaskLogList() throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        final ArrayList<Object> condition = new ArrayList<>(1);
-        sql.append("select * from ").append(ProfileTaskLogRecord.INDEX_NAME).append(" where 1=1 ");
+    @SneakyThrows
+    public List<ProfileTaskLog> getTaskLogList() {
+        final var tables = tableHelper.getTablesWithinTTL(ProfileTaskLogRecord.INDEX_NAME);
+        final var results = new ArrayList<ProfileTaskLog>();
 
-        sql.append("ORDER BY ").append(ProfileTaskLogRecord.OPERATION_TIME).append(" DESC ");
+        for (final var table : tables) {
+            final var sqlAndParameters = buildSQL(table);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]))) {
-                final List<ProfileTaskLog> tasks = new ArrayList<>();
-                while (resultSet.next()) {
-                    tasks.add(parseLog(resultSet));
-                }
-                return tasks;
-            }
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e);
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sqlAndParameters.sql(),
+                    resultSet -> {
+                        final List<ProfileTaskLog> tasks = new ArrayList<>();
+                        while (resultSet.next()) {
+                            tasks.add(parseLog(resultSet));
+                        }
+                        return tasks;
+                    },
+                    sqlAndParameters.parameters())
+            );
         }
+
+        return results;
+    }
+
+    protected SQLAndParameters buildSQL(String table) {
+        final var sql = new StringBuilder();
+        final var parameters = new ArrayList<>(2);
+        sql.append("select * from ").append(table)
+           .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(ProfileTaskLogRecord.INDEX_NAME);
+
+        sql.append(" ORDER BY ").append(ProfileTaskLogRecord.OPERATION_TIME).append(" DESC ");
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 
     private ProfileTaskLog parseLog(ResultSet data) throws SQLException {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskQueryDAO.java
index 7b3a2cd1d829..97d5133e1ca7 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileTaskQueryDAO.java
@@ -18,93 +18,125 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
+import lombok.SneakyThrows;
+import org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskRecord;
+import org.apache.skywalking.oap.server.core.query.type.ProfileTask;
+import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileTaskQueryDAO;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
-import lombok.RequiredArgsConstructor;
-import org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskRecord;
-import org.apache.skywalking.oap.server.core.query.type.ProfileTask;
-import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileTaskQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
 
-@RequiredArgsConstructor
+import static java.util.stream.Collectors.toList;
+
 public class JDBCProfileTaskQueryDAO implements IProfileTaskQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
+
+    public JDBCProfileTaskQueryDAO(JDBCClient jdbcClient, ModuleManager moduleManager) {
+        this.jdbcClient = jdbcClient;
+        this.tableHelper = new TableHelper(moduleManager, jdbcClient);
+    }
 
     @Override
+    @SneakyThrows
     public List<ProfileTask> getTaskList(String serviceId, String endpointName, Long startTimeBucket,
-                                         Long endTimeBucket, Integer limit) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        final ArrayList<Object> condition = new ArrayList<>(4);
-        sql.append("select * from ").append(ProfileTaskRecord.INDEX_NAME).append(" where 1=1 ");
-
-        if (startTimeBucket != null) {
-            sql.append(" and ").append(ProfileTaskRecord.TIME_BUCKET).append(" >= ? ");
-            condition.add(startTimeBucket);
-        }
+                                         Long endTimeBucket, Integer limit) {
+        final var results = new ArrayList<ProfileTask>();
+        final var tables = startTimeBucket == null || endTimeBucket == null ?
+            tableHelper.getTablesWithinTTL(ProfileTaskRecord.INDEX_NAME) :
+            tableHelper.getTablesForRead(ProfileTaskRecord.INDEX_NAME, startTimeBucket, endTimeBucket);
+        for (final var table : tables) {
+            final var condition = new ArrayList<>(4);
+            final var sql = new StringBuilder()
+                .append("select * from ").append(table)
+                .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(ProfileTaskRecord.INDEX_NAME);
 
-        if (endTimeBucket != null) {
-            sql.append(" and ").append(ProfileTaskRecord.TIME_BUCKET).append(" <= ? ");
-            condition.add(endTimeBucket);
-        }
+            if (startTimeBucket != null) {
+                sql.append(" and ").append(ProfileTaskRecord.TIME_BUCKET).append(" >= ? ");
+                condition.add(startTimeBucket);
+            }
 
-        if (StringUtil.isNotEmpty(serviceId)) {
-            sql.append(" and ").append(ProfileTaskRecord.SERVICE_ID).append("=? ");
-            condition.add(serviceId);
-        }
+            if (endTimeBucket != null) {
+                sql.append(" and ").append(ProfileTaskRecord.TIME_BUCKET).append(" <= ? ");
+                condition.add(endTimeBucket);
+            }
 
-        if (StringUtil.isNotEmpty(endpointName)) {
-            sql.append(" and ").append(ProfileTaskRecord.ENDPOINT_NAME).append("=?");
-            condition.add(endpointName);
-        }
+            if (StringUtil.isNotEmpty(serviceId)) {
+                sql.append(" and ").append(ProfileTaskRecord.SERVICE_ID).append("=? ");
+                condition.add(serviceId);
+            }
 
-        sql.append(" ORDER BY ").append(ProfileTaskRecord.START_TIME).append(" DESC ");
+            if (StringUtil.isNotEmpty(endpointName)) {
+                sql.append(" and ").append(ProfileTaskRecord.ENDPOINT_NAME).append("=?");
+                condition.add(endpointName);
+            }
 
-        if (limit != null) {
-            sql.append(" LIMIT ").append(limit);
-        }
+            sql.append(" ORDER BY ").append(ProfileTaskRecord.START_TIME).append(" DESC ");
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                final LinkedList<ProfileTask> tasks = new LinkedList<>();
-                while (resultSet.next()) {
-                    tasks.add(parseTask(resultSet));
-                }
-                return tasks;
+            if (limit != null) {
+                sql.append(" LIMIT ").append(limit);
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
+
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sql.toString(),
+                    resultSet -> {
+                        final var tasks = new ArrayList<ProfileTask>();
+                        while (resultSet.next()) {
+                            tasks.add(parseTask(resultSet));
+                        }
+                        return tasks;
+                    },
+                    condition.toArray(new Object[0]))
+            );
         }
+        return limit == null ?
+            results :
+            results
+                .stream()
+                .limit(limit)
+                .collect(toList());
     }
 
     @Override
-    public ProfileTask getById(String id) throws IOException {
+    @SneakyThrows
+    public ProfileTask getById(String id) {
         if (StringUtil.isEmpty(id)) {
             return null;
         }
 
-        final StringBuilder sql = new StringBuilder();
-        final ArrayList<Object> condition = new ArrayList<>(1);
-        sql.append("select * from ").append(ProfileTaskRecord.INDEX_NAME)
-            .append(" where " + ProfileTaskRecord.TASK_ID + "=? LIMIT 1");
-        condition.add(id);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                if (resultSet.next()) {
-                    return parseTask(resultSet);
-                }
+        final var tables = tableHelper.getTablesWithinTTL(ProfileTaskRecord.INDEX_NAME);
+        for (String table : tables) {
+            final StringBuilder sql = new StringBuilder();
+            final ArrayList<Object> condition = new ArrayList<>(1);
+            sql.append("select * from ").append(table)
+               .append(" where ")
+               .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ")
+               .append(" and ")
+               .append(ProfileTaskRecord.TASK_ID + "=? LIMIT 1");
+            condition.add(ProfileTaskRecord.INDEX_NAME);
+            condition.add(id);
+
+            final var r = jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> {
+                    if (resultSet.next()) {
+                        return parseTask(resultSet);
+                    }
+                    return null;
+                },
+                condition.toArray(new Object[0]));
+            if (r != null) {
+                return r;
             }
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e);
         }
         return null;
     }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java
index df8b14a3a34f..5370a5b43b8d 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java
@@ -20,93 +20,122 @@
 
 import com.google.common.base.Strings;
 import lombok.RequiredArgsConstructor;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
 import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.BooleanUtils;
-import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
 
 @RequiredArgsConstructor
 public class JDBCProfileThreadSnapshotQueryDAO implements IProfileThreadSnapshotQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<BasicTrace> queryProfiledSegments(String taskId) throws IOException {
-        // search segment id list
+    @SneakyThrows
+    public List<BasicTrace> queryProfiledSegments(String taskId) {
+        final var tables = tableHelper.getTablesWithinTTL(ProfileThreadSnapshotRecord.INDEX_NAME);
+        final var results = new ArrayList<BasicTrace>();
+        final var segments = new ArrayList<>();
+
+        for (String table : tables) {
+            segments.addAll(querySegments(taskId, table));
+        }
+
+        if (segments.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final var segmentTables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
+        for (String table : segmentTables) {
+            final var sql = new StringBuilder();
+            final var parameters = new ArrayList<>();
+
+            sql.append("select * from ").append(table).append(" where ")
+                .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? and ");
+            parameters.add(SegmentRecord.INDEX_NAME);
+
+            final var segmentQuery =
+                segments
+                    .stream()
+                    .map(it -> SegmentRecord.SEGMENT_ID + " = ? ")
+                    .collect(joining(" or ", "(", ")"));
+            sql.append(segmentQuery);
+            parameters.addAll(segments);
+            sql.append(" order by ").append(SegmentRecord.START_TIME).append(" ").append("desc");
+
+            final var sqlAndParameters = new SQLAndParameters(sql.toString(), parameters);
+
+            jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        BasicTrace basicTrace = new BasicTrace();
+
+                        basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
+                        basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));
+                        basicTrace.getEndpointNames().add(
+                            IDManager.EndpointID.analysisId(
+                                resultSet.getString(SegmentRecord.ENDPOINT_ID)).getEndpointName()
+                        );
+                        basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));
+                        basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));
+                        String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);
+                        basicTrace.getTraceIds().add(traceIds);
+
+                        results.add(basicTrace);
+                    }
+                    return null;
+                },
+                sqlAndParameters.parameters());
+        }
+        return results
+            .stream()
+            .sorted(Comparator.<BasicTrace, Long>comparing(it -> Long.parseLong(it.getStart())).reversed())
+            .collect(toList());
+    }
+
+    protected ArrayList<String> querySegments(String taskId, String table) throws SQLException {
         StringBuilder sql = new StringBuilder();
         sql.append("select ")
            .append(ProfileThreadSnapshotRecord.SEGMENT_ID)
            .append(" from ")
-           .append(ProfileThreadSnapshotRecord.INDEX_NAME);
+           .append(table);
 
         sql.append(" where ")
+           .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?")
+           .append(" and ")
            .append(ProfileThreadSnapshotRecord.TASK_ID)
            .append(" = ? and ")
            .append(ProfileThreadSnapshotRecord.SEQUENCE)
            .append(" = 0");
 
-        final LinkedList<String> segments = new LinkedList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), taskId)) {
-                while (resultSet.next()) {
-                    segments.add(resultSet.getString(ProfileThreadSnapshotRecord.SEGMENT_ID));
-                }
+        return jdbcClient.executeQuery(sql.toString(), resultSet -> {
+            final var segments = new ArrayList<String>();
+            while (resultSet.next()) {
+                segments.add(resultSet.getString(ProfileThreadSnapshotRecord.SEGMENT_ID));
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-
-        if (CollectionUtils.isEmpty(segments)) {
-            return Collections.emptyList();
-        }
-
-        // search traces
-        sql = new StringBuilder();
-        sql.append("select * from ").append(SegmentRecord.INDEX_NAME).append(" where ");
-        for (int i = 0; i < segments.size(); i++) {
-            sql.append(i > 0 ? " or " : "").append(SegmentRecord.SEGMENT_ID).append(" = ? ");
-        }
-        sql.append(" order by ").append(SegmentRecord.START_TIME).append(" ").append("desc");
-
-        ArrayList<BasicTrace> result = new ArrayList<>(segments.size());
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), segments.toArray(new String[segments.size()]))) {
-                while (resultSet.next()) {
-                    BasicTrace basicTrace = new BasicTrace();
-
-                    basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                    basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));
-                    basicTrace.getEndpointNames().add(
-                        IDManager.EndpointID.analysisId(
-                            resultSet.getString(SegmentRecord.ENDPOINT_ID)).getEndpointName()
-                    );
-                    basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));
-                    basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));
-                    String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);
-                    basicTrace.getTraceIds().add(traceIds);
-
-                    result.add(basicTrace);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-        return result;
+            return segments;
+        }, ProfileThreadSnapshotRecord.INDEX_NAME, taskId);
     }
 
     @Override
@@ -120,26 +149,29 @@ public int queryMaxSequence(String segmentId, long start, long end) throws IOExc
     }
 
     @Override
+    @SneakyThrows
     public List<ProfileThreadSnapshotRecord> queryRecords(String segmentId,
                                                           int minSequence,
                                                           int maxSequence) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        sql.append("select * from ").append(ProfileThreadSnapshotRecord.INDEX_NAME).append(" where ");
-        sql.append(" 1=1 ");
-        sql.append(" and ").append(ProfileThreadSnapshotRecord.SEGMENT_ID).append(" = ? ");
-        sql.append(" and ").append(ProfileThreadSnapshotRecord.SEQUENCE).append(" >= ? ");
-        sql.append(" and ").append(ProfileThreadSnapshotRecord.SEQUENCE).append(" < ? ");
-
-        Object[] params = new Object[] {
-            segmentId,
-            minSequence,
-            maxSequence
-        };
-
-        ArrayList<ProfileThreadSnapshotRecord> result = new ArrayList<>(maxSequence - minSequence);
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), params)) {
+        final var tables = tableHelper.getTablesWithinTTL(ProfileThreadSnapshotRecord.INDEX_NAME);
+        final var results = new ArrayList<ProfileThreadSnapshotRecord>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            sql.append("select * from ").append(table).append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+            sql.append(" and ").append(ProfileThreadSnapshotRecord.SEGMENT_ID).append(" = ? ");
+            sql.append(" and ").append(ProfileThreadSnapshotRecord.SEQUENCE).append(" >= ? ");
+            sql.append(" and ").append(ProfileThreadSnapshotRecord.SEQUENCE).append(" < ? ");
+
+            Object[] params = new Object[]{
+                ProfileThreadSnapshotRecord.INDEX_NAME,
+                segmentId,
+                minSequence,
+                maxSequence
+            };
+
+            jdbcClient.executeQuery(sql.toString(), resultSet -> {
                 while (resultSet.next()) {
                     ProfileThreadSnapshotRecord record = new ProfileThreadSnapshotRecord();
 
@@ -152,78 +184,92 @@ public List<ProfileThreadSnapshotRecord> queryRecords(String segmentId,
                         record.setStackBinary(Base64.getDecoder().decode(dataBinaryBase64));
                     }
 
-                    result.add(record);
+                    results.add(record);
                 }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+                return null;
+            }, params);
         }
 
-        return result;
+        return results;
     }
 
     @Override
+    @SneakyThrows
     public SegmentRecord getProfiledSegment(String segmentId) throws IOException {
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, "select * from " + SegmentRecord.INDEX_NAME + " where " + SegmentRecord.SEGMENT_ID + " = ?",
-                segmentId
-            )) {
-                if (resultSet.next()) {
-                    SegmentRecord segmentRecord = new SegmentRecord();
-                    segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                    segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
-                    segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
-                    segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
-                    segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
-                    segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
-                    segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
-                    String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
-                    if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
-                        segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+        final var tables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
+        for (final var table : tables) {
+            final var r = jdbcClient.executeQuery(
+                "select * from " + table +
+                    " where " + JDBCTableInstaller.TABLE_COLUMN + " = ?" +
+                    " and " + SegmentRecord.SEGMENT_ID + " = ?",
+                resultSet -> {
+                    if (resultSet.next()) {
+                        SegmentRecord segmentRecord = new SegmentRecord();
+                        segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
+                        segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
+                        segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
+                        segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
+                        segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
+                        segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
+                        segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
+                        String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
+                        if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+                            segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+                        }
+                        return segmentRecord;
                     }
-                    return segmentRecord;
-                }
+                    return null;
+                },
+                SegmentRecord.INDEX_NAME, segmentId
+            );
+            if (r != null) {
+                return r;
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
         }
-
         return null;
     }
 
+    @SneakyThrows
     private int querySequenceWithAgg(String aggType, String segmentId, long start, long end) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        sql.append("select ")
-           .append(aggType)
-           .append("(")
-           .append(ProfileThreadSnapshotRecord.SEQUENCE)
-           .append(") from ")
-           .append(ProfileThreadSnapshotRecord.INDEX_NAME)
-           .append(" where ");
-        sql.append(" 1=1 ");
-        sql.append(" and ").append(ProfileThreadSnapshotRecord.SEGMENT_ID).append(" = ? ");
-        sql.append(" and ").append(ProfileThreadSnapshotRecord.DUMP_TIME).append(" >= ? ");
-        sql.append(" and ").append(ProfileThreadSnapshotRecord.DUMP_TIME).append(" <= ? ");
-
-        Object[] params = new Object[] {
-            segmentId,
-            start,
-            end
-        };
-
-        try (Connection connection = jdbcClient.getConnection()) {
-
-            try (ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), params)) {
-                while (resultSet.next()) {
-                    return resultSet.getInt(1);
+        final var tables = tableHelper.getTablesWithinTTL(ProfileThreadSnapshotRecord.INDEX_NAME);
+
+        var result = IntStream.builder();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            sql.append("select ")
+               .append(aggType)
+               .append("(")
+               .append(ProfileThreadSnapshotRecord.SEQUENCE)
+               .append(") from ")
+               .append(table)
+               .append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            sql.append(" and ").append(ProfileThreadSnapshotRecord.SEGMENT_ID).append(" = ? ");
+            sql.append(" and ").append(ProfileThreadSnapshotRecord.DUMP_TIME).append(" >= ? ");
+            sql.append(" and ").append(ProfileThreadSnapshotRecord.DUMP_TIME).append(" <= ? ");
+
+            Object[] params = new Object[]{
+                ProfileThreadSnapshotRecord.INDEX_NAME,
+                segmentId,
+                start,
+                end
+            };
+
+            jdbcClient.executeQuery(sql.toString(), resultSet -> {
+                if (resultSet.next()) {
+                    result.add(resultSet.getInt(1));
                 }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+                return null;
+            }, params);
+        }
+        switch (aggType) {
+            case "min":
+                return result.build().min().orElse(-1);
+            case "max":
+                return result.build().max().orElse(-1);
+            default:
+                throw new UnsupportedOperationException("Unsupported agg type: " + aggType);
         }
-        return -1;
     }
-
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordDAO.java
index f382f746e14f..1c2467a8d99f 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordDAO.java
@@ -18,23 +18,24 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
+import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.client.request.InsertRequest;
-import lombok.RequiredArgsConstructor;
+
+import java.io.IOException;
 
 @RequiredArgsConstructor
 public class JDBCRecordDAO extends JDBCSQLExecutor implements IRecordDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
     private final StorageBuilder<Record> storageBuilder;
 
     @Override
     public InsertRequest prepareBatchInsert(Model model, Record record) throws IOException {
-        return getInsertExecutor(model.getName(), record, storageBuilder, new HashMapConverter.ToStorage(), null);
+        return getInsertExecutor(model, record, record.getTimeBucket(), storageBuilder, new HashMapConverter.ToStorage(), null);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordsQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordsQueryDAO.java
index 1a445ac51fb5..ee57e166595a 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordsQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCRecordsQueryDAO.java
@@ -18,33 +18,72 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.topn.TopN;
 import org.apache.skywalking.oap.server.core.query.enumeration.Order;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.input.RecordCondition;
 import org.apache.skywalking.oap.server.core.query.type.Record;
 import org.apache.skywalking.oap.server.core.storage.query.IRecordsQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
-import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @RequiredArgsConstructor
 public class JDBCRecordsQueryDAO implements IRecordsQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
+    @SneakyThrows
     public List<Record> readRecords(final RecordCondition condition,
                                     final String valueColumnName,
-                                    final Duration duration) throws IOException {
-        StringBuilder sql = new StringBuilder("select * from " + condition.getName() + " where ");
+                                    final Duration duration) {
+        final var tables = tableHelper.getTablesForRead(
+            condition.getName(),
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var results = new ArrayList<Record>();
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQL(condition, valueColumnName, duration, table);
+            jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        Record record = new Record();
+                        record.setName(resultSet.getString(TopN.STATEMENT));
+                        final String refId = resultSet.getString(TopN.TRACE_ID);
+                        record.setRefId(StringUtil.isEmpty(refId) ? "" : refId);
+                        record.setId(record.getRefId());
+                        record.setValue(String.valueOf(resultSet.getInt(valueColumnName)));
+                        results.add(record);
+                    }
+                    return null;
+                },
+                sqlAndParameters.parameters());
+        }
+
+        return results;
+    }
+
+    protected static SQLAndParameters buildSQL(
+        RecordCondition condition,
+        String valueColumnName,
+        Duration duration,
+        String table) {
+        StringBuilder sql = new StringBuilder("select * from " + table + " where ");
         List<Object> parameters = new ArrayList<>(10);
-        sql.append(" ").append(TopN.ENTITY_ID).append(" = ? and");
+        sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+        parameters.add(condition.getName());
+        sql.append(" and ").append(TopN.ENTITY_ID).append(" = ? and");
         parameters.add(condition.getParentEntity().buildId());
         sql.append(" ").append(TopN.TIME_BUCKET).append(" >= ?");
         parameters.add(duration.getStartTimeBucketInSec());
@@ -59,25 +98,6 @@ public List<Record> readRecords(final RecordCondition condition,
         }
         sql.append(" limit ").append(condition.getTopN());
 
-        List<Record> results = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, sql.toString(), parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    Record record = new Record();
-                    record.setName(resultSet.getString(TopN.STATEMENT));
-                    final String refId = resultSet.getString(TopN.TRACE_ID);
-                    record.setRefId(StringUtil.isEmpty(refId) ? "" : refId);
-                    record.setId(record.getRefId());
-                    record.setValue(resultSet.getString(valueColumnName));
-                    results.add(record);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
-
-        return results;
+        return new SQLAndParameters(sql.toString(), parameters);
     }
-
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSQLExecutor.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSQLExecutor.java
index 6db79f18b222..5697712a1f89 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSQLExecutor.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSQLExecutor.java
@@ -18,88 +18,74 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.storage.SessionCacheCallback;
 import org.apache.skywalking.oap.server.core.storage.StorageData;
+import org.apache.skywalking.oap.server.core.storage.model.ColumnName;
 import org.apache.skywalking.oap.server.core.storage.model.Model;
 import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
 import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
 import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
 import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @Slf4j
 public class JDBCSQLExecutor {
-    protected <T extends StorageData> List<StorageData> getByIDs(JDBCHikariCPClient h2Client,
+    protected <T extends StorageData> List<StorageData> getByIDs(JDBCClient h2Client,
                                                                  String modelName,
-                                                                 String[] ids,
-                                                                 StorageBuilder<T> storageBuilder) throws IOException {
+                                                                 List<String> ids,
+                                                                 StorageBuilder<T> storageBuilder) throws Exception {
+        final var tables = getModelTables(h2Client, modelName);
+        final var storageDataList = new ArrayList<StorageData>();
 
-        try (Connection connection = h2Client.getConnection()) {
-            SQLBuilder sql = new SQLBuilder("SELECT * FROM " + modelName + " WHERE id in (");
-            List<Object> parameters = new ArrayList<>(ids.length);
-            for (int i = 0; i < ids.length; i++) {
-                if (i == 0) {
-                    sql.append("?");
-                } else {
-                    sql.append(",?");
-                }
-                parameters.add(ids[i]);
-            }
-            sql.append(")");
-            try (ResultSet rs = h2Client.executeQuery(connection, sql.toString(), parameters.toArray(new Object[0]))) {
+        for (var table : tables) {
+            final var sql = new SQLBuilder("SELECT * FROM " + table + " WHERE id in ")
+                .append(ids.stream().map(it -> "?").collect(Collectors.joining(",", "(", ")")));
+            h2Client.executeQuery(sql.toString(), resultSet -> {
                 StorageData storageData;
-                List<StorageData> storageDataList = new ArrayList<>();
-                do {
-                    storageData = toStorageData(rs, modelName, storageBuilder);
-                    if (storageData != null) {
-                        storageDataList.add(storageData);
-                    }
+                while ((storageData = toStorageData(resultSet, modelName, storageBuilder)) != null) {
+                    storageDataList.add(storageData);
                 }
-                while (storageData != null);
 
-                return storageDataList;
-            }
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e.getMessage(), e);
+                return null;
+            }, ids.toArray());
         }
+        return storageDataList;
     }
 
-    protected <T extends StorageData> StorageData getByID(JDBCHikariCPClient h2Client, String modelName, String id,
-                                                          StorageBuilder<T> storageBuilder) throws IOException {
-        try (Connection connection = h2Client.getConnection();
-             ResultSet rs = h2Client.executeQuery(connection, "SELECT * FROM " + modelName + " WHERE id = ?", id)) {
-            return toStorageData(rs, modelName, storageBuilder);
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e.getMessage(), e);
-        }
-    }
-
-    protected StorageData getByColumn(JDBCHikariCPClient h2Client, String modelName, String columnName, Object value,
-                                      StorageBuilder<? extends StorageData> storageBuilder) throws IOException {
-        try (Connection connection = h2Client.getConnection();
-             ResultSet rs = h2Client.executeQuery(
-                 connection, "SELECT * FROM " + modelName + " WHERE " + columnName + " = ?", value)) {
-            return toStorageData(rs, modelName, storageBuilder);
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e.getMessage(), e);
+    @SneakyThrows
+    protected <T extends StorageData> StorageData getByID(JDBCClient h2Client, String modelName, String id,
+                                                          StorageBuilder<T> storageBuilder) {
+        final var tables = getModelTables(h2Client, modelName);
+        for (var table : tables) {
+            final var result = h2Client.executeQuery(
+                "SELECT * FROM " + table + " WHERE id = ?",
+                resultSet -> toStorageData(resultSet, modelName, storageBuilder),
+                TableHelper.generateId(modelName, id)
+            );
+            if (result != null) {
+                return result;
+            }
         }
+        return null;
     }
 
     protected StorageData toStorageData(ResultSet rs, String modelName,
@@ -115,11 +101,11 @@ protected StorageData toStorageData(ResultSet rs, String modelName,
         return null;
     }
 
-    protected <T extends StorageData> SQLExecutor getInsertExecutor(String modelName, T metrics,
+    protected <T extends StorageData> SQLExecutor getInsertExecutor(Model model, T metrics,
+                                                                    long timeBucket,
                                                                     StorageBuilder<T> storageBuilder,
                                                                     Convert2Storage<Map<String, Object>> converter,
                                                                     SessionCacheCallback callback) throws IOException {
-        Model model = TableMetaInfo.get(modelName);
         storageBuilder.entity2Storage(metrics, converter);
         Map<String, Object> objectMap = converter.obtain();
         //build main table sql
@@ -128,64 +114,76 @@ protected <T extends StorageData> SQLExecutor getInsertExecutor(String modelName
             mainEntity.put(column.getColumnName().getName(), objectMap.get(column.getColumnName().getName()));
         });
         SQLExecutor sqlExecutor = buildInsertExecutor(
-            modelName, model.getColumns(), metrics, mainEntity, callback);
+            model, metrics, timeBucket, mainEntity, callback);
         //build additional table sql
-        for (SQLDatabaseModelExtension.AdditionalTable additionalTable : model.getSqlDBModelExtension()
-                                                                              .getAdditionalTables()
-                                                                              .values()) {
+        for (final var additionalTable : model.getSqlDBModelExtension().getAdditionalTables().values()) {
             Map<String, Object> additionalEntity = new HashMap<>();
             additionalTable.getColumns().forEach(column -> {
                 additionalEntity.put(column.getColumnName().getName(), objectMap.get(column.getColumnName().getName()));
             });
 
             List<SQLExecutor> additionalSQLExecutors = buildAdditionalInsertExecutor(
-                additionalTable.getName(), additionalTable.getColumns(), metrics, additionalEntity, callback
+                model, additionalTable.getName(), additionalTable.getColumns(), metrics,
+                timeBucket, additionalEntity, callback
             );
             sqlExecutor.appendAdditionalSQLs(additionalSQLExecutors);
         }
         return sqlExecutor;
     }
 
-    private <T extends StorageData> SQLExecutor buildInsertExecutor(String tableName,
-                                                                    List<ModelColumn> columns,
+    private <T extends StorageData> SQLExecutor buildInsertExecutor(Model model,
                                                                     T metrics,
+                                                                    long timeBucket,
                                                                     Map<String, Object> objectMap,
-                                                                    SessionCacheCallback onCompleteCallback) throws IOException {
-        SQLBuilder sqlBuilder = new SQLBuilder("INSERT INTO " + tableName + " VALUES");
-        List<Object> param = new ArrayList<>();
-        sqlBuilder.append("(?,");
-        param.add(metrics.id().build());
-        for (int i = 0; i < columns.size(); i++) {
-            ModelColumn column = columns.get(i);
-            sqlBuilder.append("?");
+                                                                    SessionCacheCallback onCompleteCallback) {
+        final var table = TableHelper.getTable(model, timeBucket);
+        final var sqlBuilder = new SQLBuilder("INSERT INTO " + table);
+        final var columns = model.getColumns();
+        final var columnNames =
+            Stream.concat(
+                      Stream.of(JDBCTableInstaller.ID_COLUMN, JDBCTableInstaller.TABLE_COLUMN),
+                      columns
+                          .stream()
+                          .map(ModelColumn::getColumnName)
+                          .map(ColumnName::getStorageName))
+                  .collect(Collectors.toList());
+        sqlBuilder.append(columnNames.stream().collect(Collectors.joining(",", "(", ")")));
+        sqlBuilder.append(" VALUES ");
+        sqlBuilder.append(columnNames.stream().map(it -> "?").collect(Collectors.joining(",", "(", ")")));
 
-            Object value = objectMap.get(column.getColumnName().getName());
-            if (value instanceof StorageDataComplexObject) {
-                param.add(((StorageDataComplexObject) value).toStorageData());
-            } else {
-                param.add(value);
-            }
-
-            if (i != columns.size() - 1) {
-                sqlBuilder.append(",");
-            }
-        }
-        sqlBuilder.append(")");
+        final var param =
+            Stream.concat(
+                      Stream.of(TableHelper.generateId(model, metrics.id().build()), model.getName()),
+                      columns
+                          .stream()
+                          .map(ModelColumn::getColumnName)
+                          .map(ColumnName::getName)
+                          .map(objectMap::get)
+                          .map(it -> {
+                              if (it instanceof StorageDataComplexObject) {
+                                  return ((StorageDataComplexObject) it).toStorageData();
+                              }
+                              return it;
+                          }))
+                  .collect(Collectors.toList());
 
         return new SQLExecutor(sqlBuilder.toString(), param, onCompleteCallback);
     }
 
-    private <T extends StorageData> List<SQLExecutor> buildAdditionalInsertExecutor(String tableName,
+    private <T extends StorageData> List<SQLExecutor> buildAdditionalInsertExecutor(Model model, String tableName,
                                                                                     List<ModelColumn> columns,
                                                                                     T metrics,
+                                                                                    long timeBucket,
                                                                                     Map<String, Object> objectMap,
-                                                                                    SessionCacheCallback callback) throws IOException {
+                                                                                    SessionCacheCallback callback) {
 
         List<SQLExecutor> sqlExecutors = new ArrayList<>();
-        SQLBuilder sqlBuilder = new SQLBuilder("INSERT INTO " + tableName + " VALUES");
+        final var sqlBuilder = new SQLBuilder("INSERT INTO ")
+            .append(TableHelper.getTable(tableName, timeBucket))
+            .append(" VALUES ");
         List<Object> param = new ArrayList<>();
         sqlBuilder.append("(?,");
-        param.add(metrics.id().build());
+        param.add(TableHelper.generateId(model, metrics.id().build()));
         int position = 0;
         List valueList = new ArrayList();
         for (int i = 0; i < columns.size(); i++) {
@@ -224,41 +222,46 @@ private <T extends StorageData> List<SQLExecutor> buildAdditionalInsertExecutor(
         return sqlExecutors;
     }
 
-    protected <T extends StorageData> SQLExecutor getUpdateExecutor(String modelName, T metrics,
+    protected <T extends StorageData> SQLExecutor getUpdateExecutor(Model model, T metrics,
+                                                                    long timeBucket,
                                                                     StorageBuilder<T> storageBuilder,
-                                                                    SessionCacheCallback callback) throws IOException {
-        final HashMapConverter.ToStorage toStorage = new HashMapConverter.ToStorage();
+                                                                    SessionCacheCallback callback) {
+        final var toStorage = new HashMapConverter.ToStorage();
         storageBuilder.entity2Storage(metrics, toStorage);
-        Map<String, Object> objectMap = toStorage.obtain();
-
-        StringBuilder sqlBuilder = new StringBuilder("UPDATE " + modelName + " SET ");
-        Model model = TableMetaInfo.get(modelName);
-        List<ModelColumn> columns = model.getColumns();
-        List<Object> param = new ArrayList<>();
-        for (int i = 0; i < columns.size(); i++) {
-            ModelColumn column = columns.get(i);
-            String columnName = column.getColumnName().getName();
-            if (model.getSqlDBModelExtension().isShardingTable()) {
-                SQLDatabaseModelExtension.Sharding sharding = model.getSqlDBModelExtension().getSharding().orElseThrow(
-                    () -> new UnexpectedException("Sharding should not be empty."));
-                if (columnName.equals(sharding.getDataSourceShardingColumn()) || columnName.equals(
-                    sharding.getTableShardingColumn())) {
-                    continue;
-                }
-            }
-            sqlBuilder.append(column.getColumnName().getStorageName()).append("= ?,");
+        final var objectMap = toStorage.obtain();
+        final var table = TableHelper.getTable(model, timeBucket);
+        final var sqlBuilder = new StringBuilder("UPDATE " + table + " SET ");
+        final var columns = model.getColumns();
+        final var queries = new ArrayList<String>();
+        final var param = new ArrayList<>();
+        for (final var column : columns) {
+            final var columnName = column.getColumnName().getName();
+            queries.add(column.getColumnName().getStorageName() + " = ?");
 
-            Object value = objectMap.get(columnName);
+            final var value = objectMap.get(columnName);
             if (value instanceof StorageDataComplexObject) {
                 param.add(((StorageDataComplexObject) value).toStorageData());
             } else {
                 param.add(value);
             }
         }
-        sqlBuilder.replace(sqlBuilder.length() - 1, sqlBuilder.length(), "");
+        sqlBuilder.append(queries.stream().collect(Collectors.joining(", ")));
         sqlBuilder.append(" WHERE id = ?");
-        param.add(metrics.id().build());
+        param.add(TableHelper.generateId(model, metrics.id().build()));
 
         return new SQLExecutor(sqlBuilder.toString(), param, callback);
     }
+
+    private static ArrayList<String> getModelTables(JDBCClient h2Client, String modelName) throws Exception {
+        final var model = TableMetaInfo.get(modelName);
+        final var tableNamePattern = TableHelper.getTableName(model) + "%";
+        final var tables = new ArrayList<String>();
+        try (final var connection = h2Client.getConnection();
+             final var resultSet = connection.getMetaData().getTables(connection.getCatalog(), null, tableNamePattern, new String[]{"TABLE"})) {
+            while (resultSet.next()) {
+                tables.add(resultSet.getString("TABLE_NAME"));
+            }
+        }
+        return tables;
+    }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCServiceLabelQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCServiceLabelQueryDAO.java
index fe12d9430c95..cd5c6ef95531 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCServiceLabelQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCServiceLabelQueryDAO.java
@@ -17,39 +17,51 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.manual.process.ServiceLabelRecord;
 import org.apache.skywalking.oap.server.core.storage.profiling.ebpf.IServiceLabelDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
-import java.io.IOException;
-import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class JDBCServiceLabelQueryDAO implements IServiceLabelDAO {
-    private JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<String> queryAllLabels(String serviceId) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(1);
-        sql.append("select " + ServiceLabelRecord.LABEL + " from ")
-                .append(ServiceLabelRecord.INDEX_NAME)
-                .append(" where ").append(ServiceLabelRecord.SERVICE_ID).append(" = ?");
-        condition.add(serviceId);
-
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                    connection, sql.toString(), condition.toArray(new Object[0]))) {
-                return parseLabels(resultSet);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public List<String> queryAllLabels(String serviceId) {
+        final var tables = tableHelper.getTablesWithinTTL(ServiceLabelRecord.INDEX_NAME);
+        final var results = new ArrayList<String>();
+
+        for (String table : tables) {
+            final StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(1);
+            sql.append("select " + ServiceLabelRecord.LABEL + " from ")
+               .append(table)
+               .append(" where ")
+               .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?")
+               .append(" and ").append(ServiceLabelRecord.SERVICE_ID).append(" = ?");
+            condition.add(ServiceLabelRecord.INDEX_NAME);
+            condition.add(serviceId);
+
+            results.addAll(
+                jdbcClient.executeQuery(
+                    sql.toString(),
+                    this::parseLabels,
+                    condition.toArray(new Object[0])
+                )
+            );
         }
+
+        return results;
     }
 
     private List<String> parseLabels(ResultSet resultSet) throws SQLException {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSpanAttachedEventQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSpanAttachedEventQueryDAO.java
index fb12dac65524..3680ee256024 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSpanAttachedEventQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCSpanAttachedEventQueryDAO.java
@@ -19,70 +19,91 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.manual.spanattach.SpanAttachedEventRecord;
 import org.apache.skywalking.oap.server.core.analysis.manual.spanattach.SpanAttachedEventTraceType;
 import org.apache.skywalking.oap.server.core.storage.query.ISpanAttachedEventQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.List;
 
+import static java.util.Comparator.comparing;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+
 @RequiredArgsConstructor
 public class JDBCSpanAttachedEventQueryDAO implements ISpanAttachedEventQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<SpanAttachedEventRecord> querySpanAttachedEvents(SpanAttachedEventTraceType type, List<String> traceIds) throws IOException {
-        StringBuilder sql = new StringBuilder("select * from " + SpanAttachedEventRecord.INDEX_NAME + " where ");
-        List<Object> parameters = new ArrayList<>(traceIds.size() + 1);
+    @SneakyThrows
+    public List<SpanAttachedEventRecord> querySpanAttachedEvents(SpanAttachedEventTraceType type, List<String> traceIds) {
+        final var tables = tableHelper.getTablesWithinTTL(SpanAttachedEventRecord.INDEX_NAME);
+        final var results = new ArrayList<SpanAttachedEventRecord>();
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQL(type, traceIds, table);
+
+            jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        SpanAttachedEventRecord record = new SpanAttachedEventRecord();
+                        record.setStartTimeSecond(resultSet.getLong(SpanAttachedEventRecord.START_TIME_SECOND));
+                        record.setStartTimeNanos(resultSet.getInt(SpanAttachedEventRecord.START_TIME_NANOS));
+                        record.setEvent(resultSet.getString(SpanAttachedEventRecord.EVENT));
+                        record.setEndTimeSecond(resultSet.getLong(SpanAttachedEventRecord.END_TIME_SECOND));
+                        record.setEndTimeNanos(resultSet.getInt(SpanAttachedEventRecord.END_TIME_NANOS));
+                        record.setTraceRefType(resultSet.getInt(SpanAttachedEventRecord.TRACE_REF_TYPE));
+                        record.setRelatedTraceId(resultSet.getString(SpanAttachedEventRecord.RELATED_TRACE_ID));
+                        record.setTraceSegmentId(resultSet.getString(SpanAttachedEventRecord.TRACE_SEGMENT_ID));
+                        record.setTraceSpanId(resultSet.getString(SpanAttachedEventRecord.TRACE_SPAN_ID));
+                        String dataBinaryBase64 = resultSet.getString(SpanAttachedEventRecord.DATA_BINARY);
+                        if (StringUtil.isNotEmpty(dataBinaryBase64)) {
+                            record.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+                        }
+                        results.add(record);
+                    }
 
-        sql.append(" ").append(SpanAttachedEventRecord.RELATED_TRACE_ID).append(" in (");
-        for (int i = 0; i < traceIds.size(); i++) {
-            if (i == 0) {
-                sql.append("?");
-            } else {
-                sql.append(",?");
-            }
-            parameters.add(traceIds.get(i));
+                    return null;
+                },
+                sqlAndParameters.parameters());
         }
-        sql.append(") and ").append(SpanAttachedEventRecord.TRACE_REF_TYPE).append(" = ?");
+        return results
+            .stream()
+            .sorted(comparing(SpanAttachedEventRecord::getStartTimeSecond).thenComparing(SpanAttachedEventRecord::getStartTimeNanos))
+            .collect(toList());
+    }
+
+    private static SQLAndParameters buildSQL(SpanAttachedEventTraceType type, List<String> traceIds, String table) {
+        final var sql = new StringBuilder("select * from " + table + " where ");
+        final var parameters = new ArrayList<>(traceIds.size() + 1);
+
+        sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+        parameters.add(SpanAttachedEventRecord.INDEX_NAME);
+
+        sql.append(" and ").append(SpanAttachedEventRecord.RELATED_TRACE_ID).append(" in ");
+        sql.append(
+            traceIds
+                .stream()
+                .map(it -> "?")
+                .collect(joining(",", "(", ")"))
+        );
+        parameters.addAll(traceIds);
+
+        sql.append(" and ").append(SpanAttachedEventRecord.TRACE_REF_TYPE).append(" = ?");
         parameters.add(type.value());
 
         sql.append(" order by ").append(SpanAttachedEventRecord.START_TIME_SECOND)
-                .append(",").append(SpanAttachedEventRecord.START_TIME_NANOS).append(" ASC ");
-
-        List<SpanAttachedEventRecord> results = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                    connection, sql.toString(), parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    SpanAttachedEventRecord record = new SpanAttachedEventRecord();
-                    record.setStartTimeSecond(resultSet.getLong(SpanAttachedEventRecord.START_TIME_SECOND));
-                    record.setStartTimeNanos(resultSet.getInt(SpanAttachedEventRecord.START_TIME_NANOS));
-                    record.setEvent(resultSet.getString(SpanAttachedEventRecord.EVENT));
-                    record.setEndTimeSecond(resultSet.getLong(SpanAttachedEventRecord.END_TIME_SECOND));
-                    record.setEndTimeNanos(resultSet.getInt(SpanAttachedEventRecord.END_TIME_NANOS));
-                    record.setTraceRefType(resultSet.getInt(SpanAttachedEventRecord.TRACE_REF_TYPE));
-                    record.setRelatedTraceId(resultSet.getString(SpanAttachedEventRecord.RELATED_TRACE_ID));
-                    record.setTraceSegmentId(resultSet.getString(SpanAttachedEventRecord.TRACE_SEGMENT_ID));
-                    record.setTraceSpanId(resultSet.getString(SpanAttachedEventRecord.TRACE_SPAN_ID));
-                    String dataBinaryBase64 = resultSet.getString(SpanAttachedEventRecord.DATA_BINARY);
-                    if (StringUtil.isNotEmpty(dataBinaryBase64)) {
-                        record.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
-                    }
-                    results.add(record);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+           .append(",").append(SpanAttachedEventRecord.START_TIME_NANOS).append(" ASC ");
 
-        return results;
+        return new SQLAndParameters(sql.toString(), parameters);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCStorageDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCStorageDAO.java
index e14a83463d5e..d9a4c6844d47 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCStorageDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCStorageDAO.java
@@ -29,11 +29,11 @@
 import org.apache.skywalking.oap.server.core.storage.IRecordDAO;
 import org.apache.skywalking.oap.server.core.storage.StorageDAO;
 import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 
 @RequiredArgsConstructor
 public class JDBCStorageDAO implements StorageDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
 
     @Override
     public IMetricsDAO newMetricsDao(StorageBuilder storageBuilder) {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTagAutoCompleteQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTagAutoCompleteQueryDAO.java
index a4d2ad7fc953..6564e26bdff3 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTagAutoCompleteQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTagAutoCompleteQueryDAO.java
@@ -18,74 +18,107 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagAutocompleteData;
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagType;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.storage.query.ITagAutoCompleteQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import static java.util.Objects.nonNull;
 
 @RequiredArgsConstructor
 public class JDBCTagAutoCompleteQueryDAO implements ITagAutoCompleteQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
+    @SneakyThrows
     public Set<String> queryTagAutocompleteKeys(final TagType tagType,
                                                 final int limit,
-                                                final Duration duration) throws IOException {
+                                                final Duration duration) {
+        final var tables = tableHelper.getTablesForRead(
+            TagAutocompleteData.INDEX_NAME,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var results = new HashSet<String>();
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQLForQueryKeys(tagType, limit, duration, table);
+            jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        results.add(resultSet.getString(TagAutocompleteData.TAG_KEY));
+                    }
+                    return null;
+                },
+                sqlAndParameters.parameters());
+        }
+        return results;
+    }
+
+    protected SQLAndParameters buildSQLForQueryKeys(TagType tagType, int limit, Duration duration, String table) {
         StringBuilder sql = new StringBuilder();
         List<Object> condition = new ArrayList<>(2);
 
         sql.append("select distinct ").append(TagAutocompleteData.TAG_KEY).append(" from ")
-           .append(TagAutocompleteData.INDEX_NAME).append(" where ");
+           .append(table).append(" where ");
         sql.append(" 1=1 ");
         appendTagAutocompleteCondition(tagType, duration, sql, condition);
         sql.append(" limit ").append(limit);
-        try (Connection connection = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            Set<String> tagKeys = new HashSet<>();
-            while (resultSet.next()) {
-                tagKeys.add(resultSet.getString(TagAutocompleteData.TAG_KEY));
-            }
-            return tagKeys;
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+
+        return new SQLAndParameters(sql.toString(), condition);
     }
 
     @Override
+    @SneakyThrows
     public Set<String> queryTagAutocompleteValues(final TagType tagType,
                                                   final String tagKey,
                                                   final int limit,
-                                                  final Duration duration) throws IOException {
+                                                  final Duration duration) {
+        final var tables = tableHelper.getTablesForRead(
+            TagAutocompleteData.INDEX_NAME,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var results = new HashSet<String>();
+
+        for (String table : tables) {
+            final var sqlAndParameters = buildSQLForQueryValues(tagType, tagKey, limit, duration, table);
+            jdbcClient.executeQuery(
+                sqlAndParameters.sql(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        results.add(resultSet.getString(TagAutocompleteData.TAG_VALUE));
+                    }
+                    return null;
+                },
+                sqlAndParameters.parameters()
+            );
+        }
+        return results;
+    }
+
+    protected SQLAndParameters buildSQLForQueryValues(TagType tagType, String tagKey, int limit, Duration duration, String table) {
         StringBuilder sql = new StringBuilder();
         List<Object> condition = new ArrayList<>(3);
-        sql.append("select * from ").append(TagAutocompleteData.INDEX_NAME).append(" where ");
+        sql.append("select * from ").append(table).append(" where ");
         sql.append(TagAutocompleteData.TAG_KEY).append(" = ?");
         condition.add(tagKey);
         appendTagAutocompleteCondition(tagType, duration, sql, condition);
         sql.append(" limit ").append(limit);
 
-        try (Connection connection = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            Set<String> tagValues = new HashSet<>();
-            while (resultSet.next()) {
-                tagValues.add(resultSet.getString(TagAutocompleteData.TAG_VALUE));
-            }
-            return tagValues;
-        } catch (SQLException e) {
-            throw new IOException(e);
-        }
+        return new SQLAndParameters(sql.toString(), condition);
     }
 
     private void appendTagAutocompleteCondition(final TagType tagType,
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTopologyQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTopologyQueryDAO.java
index 15a9a8e51766..d6d841b8536d 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTopologyQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTopologyQueryDAO.java
@@ -18,13 +18,8 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.manual.relation.endpoint.EndpointRelationServerSideMetrics;
 import org.apache.skywalking.oap.server.core.analysis.manual.relation.instance.ServiceInstanceRelationClientSideMetrics;
 import org.apache.skywalking.oap.server.core.analysis.manual.relation.instance.ServiceInstanceRelationServerSideMetrics;
@@ -38,11 +33,20 @@
 import org.apache.skywalking.oap.server.core.query.type.Call;
 import org.apache.skywalking.oap.server.core.source.DetectPoint;
 import org.apache.skywalking.oap.server.core.storage.query.ITopologyQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
 
 @RequiredArgsConstructor
 public class JDBCTopologyQueryDAO implements ITopologyQueryDAO {
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
     @Override
     public List<Call.CallDetail> loadServiceRelationsDetectedAtServerSide(Duration duration,
@@ -132,46 +136,56 @@ public List<Call.CallDetail> loadProcessRelationDetectedAtServerSide(String serv
         return loadProcessFromSide(duration, serviceInstanceId, DetectPoint.SERVER);
     }
 
+    @SneakyThrows
     private List<Call.CallDetail> loadServiceCalls(String tableName,
                                                    Duration duration,
                                                    String sourceCName,
                                                    String destCName,
                                                    List<String> serviceIds,
-                                                   DetectPoint detectPoint) throws IOException {
-        Object[] conditions = new Object[serviceIds.size() * 2 + 2];
-        conditions[0] = duration.getStartTimeBucket();
-        conditions[1] = duration.getEndTimeBucket();
-        StringBuilder serviceIdMatchSql = new StringBuilder();
-        if (serviceIds.size() > 0) {
-            serviceIdMatchSql.append("and (");
-            for (int i = 0; i < serviceIds.size(); i++) {
-                serviceIdMatchSql.append(sourceCName + "=? or " + destCName + "=? ");
-                conditions[i * 2 + 2] = serviceIds.get(i);
-                conditions[i * 2 + 1 + 2] = serviceIds.get(i);
-                if (i != serviceIds.size() - 1) {
-                    serviceIdMatchSql.append("or ");
+                                                   DetectPoint detectPoint) {
+        final var tables = tableHelper.getTablesForRead(
+            tableName,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        final var calls = new ArrayList<Call.CallDetail>();
+
+        for (String table : tables) {
+            Object[] conditions = new Object[serviceIds.size() * 2 + 3];
+            conditions[0] = tableName;
+            conditions[1] = duration.getStartTimeBucket();
+            conditions[2] = duration.getEndTimeBucket();
+            StringBuilder serviceIdMatchSql = new StringBuilder();
+            if (serviceIds.size() > 0) {
+                serviceIdMatchSql.append("and (");
+                for (int i = 0; i < serviceIds.size(); i++) {
+                    serviceIdMatchSql.append(sourceCName + "=? or " + destCName + "=? ");
+                    conditions[i * 2 + 3] = serviceIds.get(i);
+                    conditions[i * 2 + 1 + 3] = serviceIds.get(i);
+                    if (i != serviceIds.size() - 1) {
+                        serviceIdMatchSql.append("or ");
+                    }
                 }
+                serviceIdMatchSql.append(")");
             }
-            serviceIdMatchSql.append(")");
-        }
-        List<Call.CallDetail> calls = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection,
+            jdbcClient.executeQuery(
                 "select " + Metrics.ENTITY_ID + ", " + ServiceRelationServerSideMetrics.COMPONENT_IDS
-                    + " from " + tableName + " where " + Metrics.TIME_BUCKET + ">= ? and "
-                    + Metrics.TIME_BUCKET + "<=? " + serviceIdMatchSql
-                    .toString() +
-                    " group by " + Metrics.ENTITY_ID + "," + ServiceRelationServerSideMetrics.COMPONENT_IDS, conditions
-            )) {
-                buildServiceCalls(resultSet, calls, detectPoint);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+                    + " from " + table + " where " + JDBCTableInstaller.TABLE_COLUMN + " = ? and "
+                    + Metrics.TIME_BUCKET + ">= ? and "
+                    + Metrics.TIME_BUCKET + "<=? " + serviceIdMatchSql +
+                    " group by " + Metrics.ENTITY_ID + "," + ServiceRelationServerSideMetrics.COMPONENT_IDS,
+                resultSet -> {
+                    buildServiceCalls(resultSet, calls, detectPoint);
+                    return null;
+                },
+                conditions
+            );
         }
+
         return calls;
     }
 
+    @SneakyThrows
     private List<Call.CallDetail> loadServiceInstanceCalls(String tableName,
                                                            Duration duration,
                                                            String sourceCName,
@@ -179,92 +193,120 @@ private List<Call.CallDetail> loadServiceInstanceCalls(String tableName,
                                                            String sourceServiceId,
                                                            String destServiceId,
                                                            DetectPoint detectPoint) throws IOException {
-        Object[] conditions = new Object[] {
+        final var tables = tableHelper.getTablesForRead(
+            tableName,
             duration.getStartTimeBucket(),
-            duration.getEndTimeBucket(),
-            sourceServiceId,
-            destServiceId,
-            destServiceId,
-            sourceServiceId
-        };
-        StringBuilder serviceIdMatchSql = new StringBuilder("and ((").append(sourceCName)
-                                                                     .append("=? and ")
-                                                                     .append(descCName)
-                                                                     .append("=?")
-                                                                     .append(") or (")
-                                                                     .append(sourceCName)
-                                                                     .append("=? and ")
-                                                                     .append(descCName)
-                                                                     .append("=?")
-                                                                     .append("))");
+            duration.getEndTimeBucket()
+        );
         List<Call.CallDetail> calls = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection,
+
+        for (String table : tables) {
+            Object[] conditions = new Object[]{
+                tableName,
+                duration.getStartTimeBucket(),
+                duration.getEndTimeBucket(),
+                sourceServiceId,
+                destServiceId,
+                destServiceId,
+                sourceServiceId
+            };
+            StringBuilder serviceIdMatchSql = new StringBuilder("and ((").append(sourceCName)
+                                                                         .append("=? and ")
+                                                                         .append(descCName)
+                                                                         .append("=?")
+                                                                         .append(") or (")
+                                                                         .append(sourceCName)
+                                                                         .append("=? and ")
+                                                                         .append(descCName)
+                                                                         .append("=?")
+                                                                         .append("))");
+            jdbcClient.executeQuery(
                 "select " + Metrics.ENTITY_ID
-                    + " from " + tableName + " where " + Metrics.TIME_BUCKET + ">= ? and " + Metrics.TIME_BUCKET + "<=? " + serviceIdMatchSql
-                    .toString() + " group by " + Metrics.ENTITY_ID,
+                    + " from " + table + " where " + JDBCTableInstaller.TABLE_COLUMN + " = ? and "
+                    + Metrics.TIME_BUCKET + ">= ? and "
+                    + Metrics.TIME_BUCKET + "<=? " + serviceIdMatchSql + " group by " + Metrics.ENTITY_ID,
+                resultSet -> {
+                    buildInstanceCalls(resultSet, calls, detectPoint);
+                    return null;
+                },
                 conditions
-            )) {
-                buildInstanceCalls(resultSet, calls, detectPoint);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            );
         }
         return calls;
     }
 
+    @SneakyThrows
     private List<Call.CallDetail> loadEndpointFromSide(String tableName,
                                                        Duration duration,
                                                        String sourceCName,
                                                        String destCName,
                                                        String id,
                                                        boolean isSourceId) throws IOException {
-        Object[] conditions = new Object[3];
-        conditions[0] = duration.getStartTimeBucket();
-        conditions[1] = duration.getEndTimeBucket();
-        conditions[2] = id;
         List<Call.CallDetail> calls = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection,
-                "select " + Metrics.ENTITY_ID + " from " + tableName
-                    + " where " + Metrics.TIME_BUCKET + ">= ? and " + Metrics.TIME_BUCKET + "<=? and "
+
+        final var tables = tableHelper.getTablesForRead(
+            tableName,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+        for (String table : tables) {
+            Object[] conditions = new Object[4];
+            conditions[0] = tableName;
+            conditions[1] = duration.getStartTimeBucket();
+            conditions[2] = duration.getEndTimeBucket();
+            conditions[3] = id;
+            jdbcClient.executeQuery(
+                "select " + Metrics.ENTITY_ID + " from " + table
+                    + " where " + JDBCTableInstaller.TABLE_COLUMN + " = ? and "
+                    + Metrics.TIME_BUCKET + ">= ? and " + Metrics.TIME_BUCKET + "<=? and "
                     + (isSourceId ? sourceCName : destCName) + "=?"
                     + " group by " + Metrics.ENTITY_ID,
+                resultSet -> {
+                    buildEndpointCalls(resultSet, calls, DetectPoint.SERVER);
+                    return null;
+                },
                 conditions
-            )) {
-                buildEndpointCalls(resultSet, calls, DetectPoint.SERVER);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            );
         }
         return calls;
     }
 
+    @SneakyThrows
     private List<Call.CallDetail> loadProcessFromSide(Duration duration,
                                                        String instanceId,
                                                        DetectPoint detectPoint) throws IOException {
-        Object[] conditions = new Object[3];
-        conditions[0] = duration.getStartTimeBucket();
-        conditions[1] = duration.getEndTimeBucket();
-        conditions[2] = instanceId;
+        final var tableName = detectPoint == DetectPoint.SERVER ?
+            ProcessRelationServerSideMetrics.INDEX_NAME :
+            ProcessRelationClientSideMetrics.INDEX_NAME;
+        final var tables = tableHelper.getTablesForRead(
+            tableName,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+
         List<Call.CallDetail> calls = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection,
-                "select " + Metrics.ENTITY_ID +  ", " + ProcessRelationServerSideMetrics.COMPONENT_ID
-                    + " from " + (detectPoint == DetectPoint.SERVER ? ProcessRelationServerSideMetrics.INDEX_NAME : ProcessRelationClientSideMetrics.INDEX_NAME)
-                    + " where " + Metrics.TIME_BUCKET + ">= ? and " + Metrics.TIME_BUCKET + "<=? and "
+
+        for (String table : tables) {
+            Object[] conditions = new Object[4];
+            conditions[0] = tableName;
+            conditions[1] = duration.getStartTimeBucket();
+            conditions[2] = duration.getEndTimeBucket();
+            conditions[3] = instanceId;
+            jdbcClient.executeQuery(
+                "select " + Metrics.ENTITY_ID + ", " + ProcessRelationServerSideMetrics.COMPONENT_ID
+                    + " from " + table
+                    + " where " + JDBCTableInstaller.TABLE_COLUMN + " = ? and "
+                    + Metrics.TIME_BUCKET + ">= ? and " + Metrics.TIME_BUCKET + "<=? and "
                     + ProcessRelationClientSideMetrics.SERVICE_INSTANCE_ID + "=?"
                     + " group by " + Metrics.ENTITY_ID + ", " + ProcessRelationServerSideMetrics.COMPONENT_ID,
+                resultSet -> {
+                    buildProcessCalls(resultSet, calls, detectPoint);
+                    return null;
+                },
                 conditions
-            )) {
-                buildProcessCalls(resultSet, calls, detectPoint);
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            );
         }
+
         return calls;
     }
 
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java
index 3c10b814e840..ad5fc9a81184 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java
@@ -20,45 +20,53 @@
 
 import com.google.common.base.Strings;
 import lombok.RequiredArgsConstructor;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.List;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
 import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
+import org.apache.skywalking.oap.server.core.config.ConfigService;
+import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.query.type.QueryOrder;
 import org.apache.skywalking.oap.server.core.query.type.Span;
 import org.apache.skywalking.oap.server.core.query.type.TraceBrief;
 import org.apache.skywalking.oap.server.core.query.type.TraceState;
 import org.apache.skywalking.oap.server.core.storage.query.ITraceQueryDAO;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.BooleanUtils;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import static java.util.Objects.nonNull;
-import static org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller.ID_COLUMN;
+import static java.util.function.Predicate.not;
+import static java.util.stream.Collectors.toSet;
 
+@Slf4j
 @RequiredArgsConstructor
 public class JDBCTraceQueryDAO implements ITraceQueryDAO {
     private final ModuleManager manager;
-    private final JDBCHikariCPClient jdbcClient;
+    private final JDBCClient jdbcClient;
+    private final TableHelper tableHelper;
 
-    private List<String> searchableTagKeys;
+    private Set<String> searchableTagKeys;
 
     @Override
+    @SneakyThrows
     public TraceBrief queryBasicTraces(Duration duration,
                                        long minDuration,
                                        long maxDuration,
@@ -71,132 +79,140 @@ public TraceBrief queryBasicTraces(Duration duration,
                                        TraceState traceState,
                                        QueryOrder queryOrder,
                                        final List<Tag> tags) throws IOException {
+        if (searchableTagKeys == null) {
+            final ConfigService configService = manager.find(CoreModule.NAME)
+                                                       .provider()
+                                                       .getService(ConfigService.class);
+            searchableTagKeys = new HashSet<>(Arrays.asList(configService.getSearchableTracesTags().split(Const.COMMA)));
+        }
+        if (tags != null && !searchableTagKeys.containsAll(tags.stream().map(Tag::getKey).collect(toSet()))) {
+            log.warn(
+                "Searching tags that are not searchable: {}",
+                tags.stream().map(Tag::getKey).filter(not(searchableTagKeys::contains)).collect(toSet()));
+            return new TraceBrief();
+        }
+
         long startSecondTB = 0;
         long endSecondTB = 0;
         if (nonNull(duration)) {
             startSecondTB = duration.getStartTimeBucketInSec();
             endSecondTB = duration.getEndTimeBucketInSec();
         }
-        if (searchableTagKeys == null) {
-            final ConfigService configService = manager.find(CoreModule.NAME)
-                                                       .provider()
-                                                       .getService(ConfigService.class);
-            searchableTagKeys = Arrays.asList(configService.getSearchableTracesTags().split(Const.COMMA));
-        }
 
-        StringBuilder sql = new StringBuilder();
-        List<Object> parameters = new ArrayList<>(10);
-
-        sql.append("from ").append(SegmentRecord.INDEX_NAME);
-
-        /**
-         * This is an AdditionalEntity feature, see:
-         * {@link org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase.AdditionalEntity}
-         */
-        if (!CollectionUtils.isEmpty(tags)) {
-            for (int i = 0; i < tags.size(); i++) {
-                sql.append(" inner join ").append(SegmentRecord.ADDITIONAL_TAG_TABLE).append(" ");
-                sql.append(SegmentRecord.ADDITIONAL_TAG_TABLE + i);
-                sql.append(" on ").append(SegmentRecord.INDEX_NAME).append(".").append(ID_COLUMN).append(" = ");
-                sql.append(SegmentRecord.ADDITIONAL_TAG_TABLE + i).append(".").append(ID_COLUMN);
+        final var tables = startSecondTB > 0 && endSecondTB > 0 ?
+            tableHelper.getTablesForRead(SegmentRecord.INDEX_NAME, startSecondTB, endSecondTB) :
+            tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
+        final var traces = new ArrayList<BasicTrace>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> parameters = new ArrayList<>(10);
+
+            sql.append("from ").append(table);
+
+            /*
+             * This is an AdditionalEntity feature, see:
+             * {@link org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase.AdditionalEntity}
+             */
+            final var timeBucket = TableHelper.getTimeBucket(table);
+            final var tagTable = TableHelper.getTable(SegmentRecord.ADDITIONAL_TAG_TABLE, timeBucket);
+            if (!CollectionUtils.isEmpty(tags)) {
+                for (int i = 0; i < tags.size(); i++) {
+                    sql.append(" inner join ").append(tagTable).append(" ");
+                    sql.append(tagTable + i);
+                    sql.append(" on ").append(table).append(".").append(JDBCTableInstaller.ID_COLUMN).append(" = ");
+                    sql.append(tagTable + i).append(".").append(JDBCTableInstaller.ID_COLUMN);
+                }
             }
-        }
-        sql.append(" where ");
-        sql.append(" 1=1 ");
-        if (startSecondTB != 0 && endSecondTB != 0) {
-            sql.append(" and ").append(SegmentRecord.INDEX_NAME).append(".").append(SegmentRecord.TIME_BUCKET).append(" >= ?");
-            parameters.add(startSecondTB);
-            sql.append(" and ").append(SegmentRecord.INDEX_NAME).append(".").append(SegmentRecord.TIME_BUCKET).append(" <= ?");
-            parameters.add(endSecondTB);
-        }
-        if (minDuration != 0) {
-            sql.append(" and ").append(SegmentRecord.LATENCY).append(" >= ?");
-            parameters.add(minDuration);
-        }
-        if (maxDuration != 0) {
-            sql.append(" and ").append(SegmentRecord.LATENCY).append(" <= ?");
-            parameters.add(maxDuration);
-        }
-        if (StringUtil.isNotEmpty(serviceId)) {
-            sql.append(" and ").append(SegmentRecord.INDEX_NAME).append(".").append(SegmentRecord.SERVICE_ID).append(" = ?");
-            parameters.add(serviceId);
-        }
-        if (StringUtil.isNotEmpty(serviceInstanceId)) {
-            sql.append(" and ").append(SegmentRecord.SERVICE_INSTANCE_ID).append(" = ?");
-            parameters.add(serviceInstanceId);
-        }
-        if (!Strings.isNullOrEmpty(endpointId)) {
-            sql.append(" and ").append(SegmentRecord.ENDPOINT_ID).append(" = ?");
-            parameters.add(endpointId);
-        }
-        if (!Strings.isNullOrEmpty(traceId)) {
-            sql.append(" and ").append(SegmentRecord.TRACE_ID).append(" = ?");
-            parameters.add(traceId);
-        }
-        if (CollectionUtils.isNotEmpty(tags)) {
-            for (int i = 0; i < tags.size(); i++) {
-                final int foundIdx = searchableTagKeys.indexOf(tags.get(i).getKey());
-                if (foundIdx > -1) {
-                    sql.append(" and ").append(SegmentRecord.ADDITIONAL_TAG_TABLE + i).append(".");
+            sql.append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            parameters.add(SegmentRecord.INDEX_NAME);
+            if (startSecondTB != 0 && endSecondTB != 0) {
+                sql.append(" and ").append(table).append(".").append(SegmentRecord.TIME_BUCKET).append(" >= ?");
+                parameters.add(startSecondTB);
+                sql.append(" and ").append(table).append(".").append(SegmentRecord.TIME_BUCKET).append(" <= ?");
+                parameters.add(endSecondTB);
+            }
+            if (minDuration != 0) {
+                sql.append(" and ").append(SegmentRecord.LATENCY).append(" >= ?");
+                parameters.add(minDuration);
+            }
+            if (maxDuration != 0) {
+                sql.append(" and ").append(SegmentRecord.LATENCY).append(" <= ?");
+                parameters.add(maxDuration);
+            }
+            if (StringUtil.isNotEmpty(serviceId)) {
+                sql.append(" and ").append(table).append(".").append(SegmentRecord.SERVICE_ID).append(" = ?");
+                parameters.add(serviceId);
+            }
+            if (StringUtil.isNotEmpty(serviceInstanceId)) {
+                sql.append(" and ").append(SegmentRecord.SERVICE_INSTANCE_ID).append(" = ?");
+                parameters.add(serviceInstanceId);
+            }
+            if (!Strings.isNullOrEmpty(endpointId)) {
+                sql.append(" and ").append(SegmentRecord.ENDPOINT_ID).append(" = ?");
+                parameters.add(endpointId);
+            }
+            if (!Strings.isNullOrEmpty(traceId)) {
+                sql.append(" and ").append(SegmentRecord.TRACE_ID).append(" = ?");
+                parameters.add(traceId);
+            }
+            if (CollectionUtils.isNotEmpty(tags)) {
+                for (int i = 0; i < tags.size(); i++) {
+                    sql.append(" and ").append(tagTable + i).append(".");
                     sql.append(SegmentRecord.TAGS).append(" = ?");
                     parameters.add(tags.get(i).toString());
-                } else {
-                    //If the tag is not searchable, but is required, then don't need to run the real query.
-                    return new TraceBrief();
                 }
             }
-        }
-        switch (traceState) {
-            case ERROR:
-                sql.append(" and ").append(SegmentRecord.IS_ERROR).append(" = ").append(BooleanUtils.TRUE);
-                break;
-            case SUCCESS:
-                sql.append(" and ").append(SegmentRecord.IS_ERROR).append(" = ").append(BooleanUtils.FALSE);
-                break;
-        }
-        switch (queryOrder) {
-            case BY_START_TIME:
-                sql.append(" order by ").append(SegmentRecord.START_TIME).append(" ").append("desc");
-                break;
-            case BY_DURATION:
-                sql.append(" order by ").append(SegmentRecord.LATENCY).append(" ").append("desc");
-                break;
-        }
-
-        TraceBrief traceBrief = new TraceBrief();
-        try (Connection connection = jdbcClient.getConnection()) {
+            switch (traceState) {
+                case ERROR:
+                    sql.append(" and ").append(SegmentRecord.IS_ERROR).append(" = ").append(BooleanUtils.TRUE);
+                    break;
+                case SUCCESS:
+                    sql.append(" and ").append(SegmentRecord.IS_ERROR).append(" = ").append(BooleanUtils.FALSE);
+                    break;
+            }
+            switch (queryOrder) {
+                case BY_START_TIME:
+                    sql.append(" order by ").append(SegmentRecord.START_TIME).append(" ").append("desc");
+                    break;
+                case BY_DURATION:
+                    sql.append(" order by ").append(SegmentRecord.LATENCY).append(" ").append("desc");
+                    break;
+            }
 
             buildLimit(sql, from, limit);
 
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, "select " +
+            jdbcClient.executeQuery(
+                "select " +
                     SegmentRecord.SEGMENT_ID + ", " +
                     SegmentRecord.START_TIME + ", " +
                     SegmentRecord.ENDPOINT_ID + ", " +
                     SegmentRecord.LATENCY + ", " +
                     SegmentRecord.IS_ERROR + ", " +
-                    SegmentRecord.TRACE_ID + " " + sql, parameters.toArray(new Object[0]))) {
-                while (resultSet.next()) {
-                    BasicTrace basicTrace = new BasicTrace();
-
-                    basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                    basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));
-                    basicTrace.getEndpointNames().add(
-                        IDManager.EndpointID.analysisId(resultSet.getString(SegmentRecord.ENDPOINT_ID))
-                                            .getEndpointName()
-                    );
-                    basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));
-                    basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));
-                    String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);
-                    basicTrace.getTraceIds().add(traceIds);
-                    traceBrief.getTraces().add(basicTrace);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+                    SegmentRecord.TRACE_ID + " " + sql,
+                resultSet -> {
+                    while (resultSet.next()) {
+                        BasicTrace basicTrace = new BasicTrace();
+
+                        basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
+                        basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));
+                        basicTrace.getEndpointNames().add(
+                            IDManager.EndpointID.analysisId(resultSet.getString(SegmentRecord.ENDPOINT_ID))
+                                                .getEndpointName()
+                        );
+                        basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));
+                        basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));
+                        String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);
+                        basicTrace.getTraceIds().add(traceIds);
+                        traces.add(basicTrace);
+                    }
+                    return null;
+                },
+                parameters.toArray(new Object[0]));
         }
 
-        return traceBrief;
+        return new TraceBrief(traces); // TODO: sort,
     }
 
     protected void buildLimit(StringBuilder sql, int from, int limit) {
@@ -205,39 +221,43 @@ protected void buildLimit(StringBuilder sql, int from, int limit) {
     }
 
     @Override
+    @SneakyThrows
     public List<SegmentRecord> queryByTraceId(String traceId) throws IOException {
-        List<SegmentRecord> segmentRecords = new ArrayList<>();
-        try (Connection connection = jdbcClient.getConnection()) {
+        final var tables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
+        final var segmentRecords = new ArrayList<SegmentRecord>();
 
-            try (ResultSet resultSet = jdbcClient.executeQuery(
-                connection, "select " + SegmentRecord.SEGMENT_ID + ", " +
+        for (String table : tables) {
+            jdbcClient.executeQuery(
+                "select " + SegmentRecord.SEGMENT_ID + ", " +
                     SegmentRecord.TRACE_ID + ", " +
                     SegmentRecord.SERVICE_ID + ", " +
                     SegmentRecord.SERVICE_INSTANCE_ID + ", " +
                     SegmentRecord.START_TIME + ", " +
                     SegmentRecord.LATENCY + ", " +
                     SegmentRecord.IS_ERROR + ", " +
-                    SegmentRecord.DATA_BINARY + " from " +
-                    SegmentRecord.INDEX_NAME + " where " + SegmentRecord.TRACE_ID + " = ?", traceId
-            )) {
-                while (resultSet.next()) {
-                    SegmentRecord segmentRecord = new SegmentRecord();
-                    segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                    segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
-                    segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
-                    segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
-                    segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
-                    segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
-                    segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
-                    String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
-                    if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
-                        segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+                    SegmentRecord.DATA_BINARY + " from " + table + " where " +
+                    JDBCTableInstaller.TABLE_COLUMN + " = ? and " +
+                    SegmentRecord.TRACE_ID + " = ?",
+                resultSet -> {
+                    while (resultSet.next()) {
+                        SegmentRecord segmentRecord = new SegmentRecord();
+                        segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
+                        segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
+                        segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
+                        segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
+                        segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
+                        segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
+                        segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
+                        String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
+                        if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+                            segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+                        }
+                        segmentRecords.add(segmentRecord);
                     }
-                    segmentRecords.add(segmentRecord);
-                }
-            }
-        } catch (SQLException e) {
-            throw new IOException(e);
+                    return null;
+                },
+                SegmentRecord.INDEX_NAME, traceId
+            );
         }
         return segmentRecords;
     }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCUITemplateManagementDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCUITemplateManagementDAO.java
index 9267efd21c9a..81b04c33e5b8 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCUITemplateManagementDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCUITemplateManagementDAO.java
@@ -18,13 +18,8 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate;
 import org.apache.skywalking.oap.server.core.query.input.DashboardSetting;
@@ -32,56 +27,78 @@
 import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus;
 import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO;
 import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.BooleanUtils;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
 
 @Slf4j
 @RequiredArgsConstructor
 public class JDBCUITemplateManagementDAO extends JDBCSQLExecutor implements UITemplateManagementDAO {
-    private final JDBCHikariCPClient h2Client;
+    private final JDBCClient h2Client;
+    private final TableHelper tableHelper;
 
     @Override
-    public DashboardConfiguration getTemplate(final String id) throws IOException {
+    @SneakyThrows
+    public DashboardConfiguration getTemplate(final String id) {
         if (StringUtil.isEmpty(id)) {
             return null;
         }
-        final StringBuilder sql = new StringBuilder();
-        final ArrayList<Object> condition = new ArrayList<>(1);
-        sql.append("select * from ").append(UITemplate.INDEX_NAME).append(" where id=? LIMIT 1 ");
-        condition.add(id);
 
-        try (Connection connection = h2Client.getConnection()) {
-            try (ResultSet rs = h2Client.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
+        final var tables = tableHelper.getTablesWithinTTL(UITemplate.INDEX_NAME);
+
+        for (String table : tables) {
+            final StringBuilder sql = new StringBuilder();
+            final ArrayList<Object> condition = new ArrayList<>(1);
+            sql.append("select * from ").append(table).append(" where ")
+               .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?")
+               .append(" and id=? LIMIT 1 ");
+            condition.add(UITemplate.INDEX_NAME);
+            condition.add(id);
+
+            final var result = h2Client.executeQuery(sql.toString(), resultSet -> {
                 final UITemplate.Builder builder = new UITemplate.Builder();
-                UITemplate uiTemplate = (UITemplate) toStorageData(rs, UITemplate.INDEX_NAME, builder);
+                UITemplate uiTemplate = (UITemplate) toStorageData(resultSet, UITemplate.INDEX_NAME, builder);
                 if (uiTemplate != null) {
                     return new DashboardConfiguration().fromEntity(uiTemplate);
                 }
+                return null;
+            }, condition.toArray(new Object[0]));
+            if (result != null) {
+                return result;
             }
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e);
         }
+
         return null;
     }
 
     @Override
-    public List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) throws IOException {
-        final StringBuilder sql = new StringBuilder();
-        final ArrayList<Object> condition = new ArrayList<>(1);
-        sql.append("select * from ").append(UITemplate.INDEX_NAME).append(" where 1=1 ");
-        if (!includingDisabled) {
-            sql.append(" and ").append(UITemplate.DISABLED).append("=?");
-            condition.add(BooleanUtils.booleanToValue(includingDisabled));
-        }
+    @SneakyThrows
+    public List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) {
+        final var tables = tableHelper.getTablesWithinTTL(UITemplate.INDEX_NAME);
+        final var configs = new ArrayList<DashboardConfiguration>();
 
-        try (Connection connection = h2Client.getConnection()) {
-            try (ResultSet resultSet = h2Client.executeQuery(
-                connection, sql.toString(), condition.toArray(new Object[0]))) {
-                final List<DashboardConfiguration> configs = new ArrayList<>();
+        for (String table : tables) {
+            final StringBuilder sql = new StringBuilder();
+            final ArrayList<Object> condition = new ArrayList<>(1);
+            sql.append("select * from ").append(table).append(" where ")
+               .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ");
+            condition.add(UITemplate.INDEX_NAME);
+            if (!includingDisabled) {
+                sql.append(" and ").append(UITemplate.DISABLED).append("=?");
+                condition.add(BooleanUtils.booleanToValue(includingDisabled));
+            }
+
+            h2Client.executeQuery(sql.toString(), resultSet -> {
                 final UITemplate.Builder builder = new UITemplate.Builder();
                 UITemplate uiTemplate = null;
                 do {
@@ -91,22 +108,23 @@ public List<DashboardConfiguration> getAllTemplates(Boolean includingDisabled) t
                     }
                 }
                 while (uiTemplate != null);
-                return configs;
-            }
-        } catch (SQLException | JDBCClientException e) {
-            throw new IOException(e);
+                return null;
+            }, condition.toArray(new Object[0]));
         }
+
+        return configs;
     }
 
     @Override
     public TemplateChangeStatus addTemplate(final DashboardSetting setting) throws IOException {
-        final UITemplate uiTemplate = setting.toEntity();
+        final var uiTemplate = setting.toEntity();
+        final var model = TableMetaInfo.get(UITemplate.INDEX_NAME);
         final SQLExecutor insertExecutor = getInsertExecutor(
-            UITemplate.INDEX_NAME, uiTemplate, new UITemplate.Builder(), new HashMapConverter.ToStorage(), null);
+            model, uiTemplate, 0, new UITemplate.Builder(), new HashMapConverter.ToStorage(), null);
         try (Connection connection = h2Client.getConnection()) {
             insertExecutor.invoke(connection);
             return TemplateChangeStatus.builder().status(true).id(setting.getId()).build();
-        } catch (SQLException | JDBCClientException e) {
+        } catch (SQLException e) {
             log.error(e.getMessage(), e);
             return TemplateChangeStatus.builder()
                                        .status(false)
@@ -134,12 +152,13 @@ public TemplateChangeStatus disableTemplate(final String id) throws IOException
     }
 
     private TemplateChangeStatus executeUpdate(final UITemplate uiTemplate) throws IOException {
-        final SQLExecutor updateExecutor = getUpdateExecutor(
-            UITemplate.INDEX_NAME, uiTemplate, new UITemplate.Builder(), null);
+        final var model = TableMetaInfo.get(UITemplate.INDEX_NAME);
+        final var updateExecutor = getUpdateExecutor(
+            model, uiTemplate, 0, new UITemplate.Builder(), null);
         try (Connection connection = h2Client.getConnection()) {
             updateExecutor.invoke(connection);
             return TemplateChangeStatus.builder().status(true).id(uiTemplate.getTemplateId()).build();
-        } catch (SQLException | JDBCClientException e) {
+        } catch (SQLException e) {
             log.error(e.getMessage(), e);
             return TemplateChangeStatus.builder()
                                        .status(false)
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
index 476b4d0f9fde..ef6ece3eea73 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCZipkinQueryDAO.java
@@ -22,236 +22,287 @@
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import lombok.RequiredArgsConstructor;
-import static org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller.ID_COLUMN;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.storage.query.IZipkinQueryDAO;
 import org.apache.skywalking.oap.server.core.zipkin.ZipkinServiceRelationTraffic;
 import org.apache.skywalking.oap.server.core.zipkin.ZipkinServiceSpanTraffic;
 import org.apache.skywalking.oap.server.core.zipkin.ZipkinServiceTraffic;
 import org.apache.skywalking.oap.server.core.zipkin.ZipkinSpanRecord;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 import zipkin2.Endpoint;
 import zipkin2.Span;
 import zipkin2.storage.QueryRequest;
 
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static java.util.stream.Collectors.toList;
+
 @RequiredArgsConstructor
 public class JDBCZipkinQueryDAO implements IZipkinQueryDAO {
     private final static int NAME_QUERY_MAX_SIZE = Integer.MAX_VALUE;
     private static final Gson GSON = new Gson();
 
-    private final JDBCHikariCPClient h2Client;
+    private final JDBCClient h2Client;
+    private final TableHelper tableHelper;
 
     @Override
-    public List<String> getServiceNames() throws IOException {
-        StringBuilder sql = new StringBuilder();
-        sql.append("select ").append(ZipkinServiceTraffic.SERVICE_NAME).append(" from ").append(ZipkinServiceTraffic.INDEX_NAME);
-        sql.append(" where ").append("1=1");
-        sql.append(" limit ").append(NAME_QUERY_MAX_SIZE);
-        try (Connection connection = h2Client.getConnection()) {
-            ResultSet resultSet = h2Client.executeQuery(connection, sql.toString());
-            List<String> services = new ArrayList<>();
-            while (resultSet.next()) {
-                services.add(resultSet.getString(ZipkinServiceTraffic.SERVICE_NAME));
-            }
-            return services;
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public List<String> getServiceNames() {
+        final var tables = tableHelper.getTablesWithinTTL(ZipkinServiceTraffic.INDEX_NAME);
+        final var services = new ArrayList<String>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            sql.append("select ").append(ZipkinServiceTraffic.SERVICE_NAME).append(" from ").append(table)
+                .append(" where ")
+               .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            sql.append(" limit ").append(NAME_QUERY_MAX_SIZE);
+            h2Client.executeQuery(sql.toString(), resultSet -> {
+                while (resultSet.next()) {
+                    services.add(resultSet.getString(ZipkinServiceTraffic.SERVICE_NAME));
+                }
+                return null;
+            }, ZipkinServiceTraffic.INDEX_NAME);
         }
+
+        return services
+            .stream()
+            .limit(NAME_QUERY_MAX_SIZE)
+            .collect(toList());
     }
 
     @Override
-    public List<String> getRemoteServiceNames(final String serviceName) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(1);
-        sql.append("select ").append(ZipkinServiceRelationTraffic.REMOTE_SERVICE_NAME).append(" from ")
-           .append(ZipkinServiceRelationTraffic.INDEX_NAME);
-        sql.append(" where ");
-        sql.append(ZipkinServiceRelationTraffic.SERVICE_NAME).append(" = ?");
-        sql.append(" limit ").append(NAME_QUERY_MAX_SIZE);
-        condition.add(serviceName);
-        try (Connection connection = h2Client.getConnection()) {
-            ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            List<String> remoteServices = new ArrayList<>();
-            while (resultSet.next()) {
-                remoteServices.add(resultSet.getString(ZipkinServiceRelationTraffic.REMOTE_SERVICE_NAME));
-            }
-            return remoteServices;
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public List<String> getRemoteServiceNames(final String serviceName) {
+        final var tables = tableHelper.getTablesWithinTTL(ZipkinServiceRelationTraffic.INDEX_NAME);
+        final var remoteServices = new ArrayList<String>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(2);
+            sql.append("select ").append(ZipkinServiceRelationTraffic.REMOTE_SERVICE_NAME).append(" from ")
+               .append(table);
+            sql.append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(ZipkinServiceRelationTraffic.INDEX_NAME);
+            sql.append(" and ").append(ZipkinServiceRelationTraffic.SERVICE_NAME).append(" = ?");
+            sql.append(" limit ").append(NAME_QUERY_MAX_SIZE);
+            condition.add(serviceName);
+            h2Client.executeQuery(sql.toString(), resultSet -> {
+                while (resultSet.next()) {
+                    remoteServices.add(resultSet.getString(ZipkinServiceRelationTraffic.REMOTE_SERVICE_NAME));
+                }
+                return null;
+            }, condition.toArray(new Object[0]));
         }
+
+        return remoteServices
+            .stream()
+            .limit(NAME_QUERY_MAX_SIZE)
+            .collect(toList());
     }
 
     @Override
-    public List<String> getSpanNames(final String serviceName) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(1);
-        sql.append("select ").append(ZipkinServiceSpanTraffic.SPAN_NAME).append(" from ")
-           .append(ZipkinServiceSpanTraffic.INDEX_NAME);
-        sql.append(" where ");
-        sql.append(ZipkinServiceSpanTraffic.SERVICE_NAME).append(" = ?");
-        sql.append(" limit ").append(NAME_QUERY_MAX_SIZE);
-        condition.add(serviceName);
-        try (Connection connection = h2Client.getConnection()) {
-            ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            List<String> spanNames = new ArrayList<>();
-            while (resultSet.next()) {
-                spanNames.add(resultSet.getString(ZipkinServiceSpanTraffic.SPAN_NAME));
-            }
-            return spanNames;
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public List<String> getSpanNames(final String serviceName) {
+        final var tables = tableHelper.getTablesWithinTTL(ZipkinServiceSpanTraffic.INDEX_NAME);
+        final var spanNames = new ArrayList<String>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(1);
+            sql.append("select ").append(ZipkinServiceSpanTraffic.SPAN_NAME).append(" from ")
+               .append(table);
+            sql.append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(ZipkinServiceSpanTraffic.INDEX_NAME);
+            sql.append(" and ").append(ZipkinServiceSpanTraffic.SERVICE_NAME).append(" = ?");
+            sql.append(" limit ").append(NAME_QUERY_MAX_SIZE);
+            condition.add(serviceName);
+            h2Client.executeQuery(sql.toString(), resultSet -> {
+                while (resultSet.next()) {
+                    spanNames.add(resultSet.getString(ZipkinServiceSpanTraffic.SPAN_NAME));
+                }
+                return null;
+            }, condition.toArray(new Object[0]));
         }
+
+        return spanNames
+            .stream()
+            .limit(NAME_QUERY_MAX_SIZE)
+            .collect(toList());
     }
 
     @Override
-    public List<Span> getTrace(final String traceId) throws IOException {
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(1);
-        sql.append("select * from ").append(ZipkinSpanRecord.INDEX_NAME);
-        sql.append(" where ");
-        sql.append(ZipkinSpanRecord.TRACE_ID).append(" = ?");
-        condition.add(traceId);
-        try (Connection connection = h2Client.getConnection()) {
-            ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            List<Span> trace = new ArrayList<>();
-            while (resultSet.next()) {
-                trace.add(buildSpan(resultSet));
-            }
-            return trace;
-        } catch (SQLException e) {
-            throw new IOException(e);
+    @SneakyThrows
+    public List<Span> getTrace(final String traceId) {
+        final var tables = tableHelper.getTablesWithinTTL(ZipkinSpanRecord.INDEX_NAME);
+        final var trace = new ArrayList<Span>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(1);
+            sql.append("select * from ").append(table);
+            sql.append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(ZipkinSpanRecord.INDEX_NAME);
+            sql.append(" and ").append(ZipkinSpanRecord.TRACE_ID).append(" = ?");
+            condition.add(traceId);
+            h2Client.executeQuery(sql.toString(), resultSet -> {
+                while (resultSet.next()) {
+                    trace.add(buildSpan(resultSet));
+                }
+                return null;
+            }, condition.toArray(new Object[0]));
         }
+        return trace;
     }
 
     @Override
-    public List<List<Span>> getTraces(final QueryRequest request, Duration duration) throws IOException {
+    @SneakyThrows
+    public List<List<Span>> getTraces(final QueryRequest request, Duration duration) {
+        final var tables = tableHelper.getTablesForRead(
+            ZipkinSpanRecord.INDEX_NAME,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
         final long startTimeMillis = duration.getStartTimestamp();
         final long endTimeMillis = duration.getEndTimestamp();
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        List<Map.Entry<String, String>> annotations = new ArrayList<>(request.annotationQuery().entrySet());
-        sql.append("select ").append(ZipkinSpanRecord.INDEX_NAME).append(".").append(ZipkinSpanRecord.TRACE_ID).append(", ")
-            .append("min(").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(")").append(" from ");
-        sql.append(ZipkinSpanRecord.INDEX_NAME);
-        /**
-         * This is an AdditionalEntity feature, see:
-         * {@link org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase.AdditionalEntity}
-         */
-        if (!CollectionUtils.isEmpty(annotations)) {
-            for (int i = 0; i < annotations.size(); i++) {
-                sql.append(" inner join ").append(ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE).append(" ");
-                sql.append(ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE + i);
-                sql.append(" on ").append(ZipkinSpanRecord.INDEX_NAME).append(".").append(ID_COLUMN).append(" = ");
-                sql.append(ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE + i).append(".").append(ID_COLUMN);
-            }
-        }
-        sql.append(" where ");
-        sql.append(" 1=1 ");
-        if (startTimeMillis > 0 && endTimeMillis > 0) {
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" >= ?");
-            condition.add(startTimeMillis);
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" <= ?");
-            condition.add(endTimeMillis);
-            buildShardingCondition(sql, condition, startTimeMillis, endTimeMillis);
-        }
-        if (request.minDuration() != null) {
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.DURATION).append(" >= ?");
-            condition.add(request.minDuration());
-        }
-        if (request.maxDuration() != null) {
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.DURATION).append(" <= ?");
-            condition.add(request.maxDuration());
-        }
-        if (!StringUtil.isEmpty(request.serviceName())) {
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.LOCAL_ENDPOINT_SERVICE_NAME).append(" = ?");
-            condition.add(request.serviceName());
-        }
-        if (!StringUtil.isEmpty(request.remoteServiceName())) {
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.REMOTE_ENDPOINT_SERVICE_NAME).append(" = ?");
-            condition.add(request.remoteServiceName());
-        }
-        if (!StringUtil.isEmpty(request.spanName())) {
-            sql.append(" and ");
-            sql.append(ZipkinSpanRecord.NAME).append(" = ?");
-            condition.add(request.spanName());
-        }
-        if (CollectionUtils.isNotEmpty(annotations)) {
-            for (int i = 0; i < annotations.size(); i++) {
-                Map.Entry<String, String> annotation = annotations.get(i);
-                if (annotation.getValue().isEmpty()) {
-                    sql.append(" and ").append(ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE).append(i).append(".");
-                    sql.append(ZipkinSpanRecord.QUERY).append(" = ?");
-                    condition.add(annotation.getKey());
-                } else {
-                    sql.append(" and ").append(ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE).append(i).append(".");
-                    sql.append(ZipkinSpanRecord.QUERY).append(" = ?");
-                    condition.add(annotation.getKey() + "=" + annotation.getValue());
+        final var traceIds = new HashSet<String>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(5);
+            List<Map.Entry<String, String>> annotations = new ArrayList<>(request.annotationQuery().entrySet());
+            sql.append("select ").append(table).append(".").append(ZipkinSpanRecord.TRACE_ID).append(", ")
+               .append("min(").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(")").append(" from ");
+            sql.append(table);
+            /*
+             * This is an AdditionalEntity feature, see:
+             * {@link org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase.AdditionalEntity}
+             */
+            final var timeBucket = TableHelper.getTimeBucket(table);
+            final var tagTable = TableHelper.getTable(ZipkinSpanRecord.ADDITIONAL_QUERY_TABLE, timeBucket);
+            if (!CollectionUtils.isEmpty(annotations)) {
+                for (int i = 0; i < annotations.size(); i++) {
+                    sql.append(" inner join ").append(tagTable).append(" ");
+                    sql.append(tagTable + i);
+                    sql.append(" on ").append(table).append(".").append(JDBCTableInstaller.ID_COLUMN).append(" = ");
+                    sql.append(tagTable + i).append(".").append(JDBCTableInstaller.ID_COLUMN);
                 }
             }
-        }
-        sql.append(" group by ").append(ZipkinSpanRecord.TRACE_ID);
-        sql.append(" order by min(").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(") desc");
-        sql.append(" limit ").append(request.limit());
-        Set<String> traceIds = new HashSet<>();
-        try (Connection connection = h2Client.getConnection()) {
-            ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            while (resultSet.next()) {
-                traceIds.add(resultSet.getString(ZipkinSpanRecord.TRACE_ID));
+            sql.append(" where ");
+            sql.append(" 1=1 ");
+            if (startTimeMillis > 0 && endTimeMillis > 0) {
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" >= ?");
+                condition.add(startTimeMillis);
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" <= ?");
+                condition.add(endTimeMillis);
+                buildShardingCondition(sql, condition, startTimeMillis, endTimeMillis);
+            }
+            if (request.minDuration() != null) {
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.DURATION).append(" >= ?");
+                condition.add(request.minDuration());
+            }
+            if (request.maxDuration() != null) {
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.DURATION).append(" <= ?");
+                condition.add(request.maxDuration());
+            }
+            if (!StringUtil.isEmpty(request.serviceName())) {
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.LOCAL_ENDPOINT_SERVICE_NAME).append(" = ?");
+                condition.add(request.serviceName());
+            }
+            if (!StringUtil.isEmpty(request.remoteServiceName())) {
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.REMOTE_ENDPOINT_SERVICE_NAME).append(" = ?");
+                condition.add(request.remoteServiceName());
+            }
+            if (!StringUtil.isEmpty(request.spanName())) {
+                sql.append(" and ");
+                sql.append(ZipkinSpanRecord.NAME).append(" = ?");
+                condition.add(request.spanName());
+            }
+            if (CollectionUtils.isNotEmpty(annotations)) {
+                for (int i = 0; i < annotations.size(); i++) {
+                    Map.Entry<String, String> annotation = annotations.get(i);
+                    if (annotation.getValue().isEmpty()) {
+                        sql.append(" and ").append(tagTable).append(i).append(".");
+                        sql.append(ZipkinSpanRecord.QUERY).append(" = ?");
+                        condition.add(annotation.getKey());
+                    } else {
+                        sql.append(" and ").append(tagTable).append(i).append(".");
+                        sql.append(ZipkinSpanRecord.QUERY).append(" = ?");
+                        condition.add(annotation.getKey() + "=" + annotation.getValue());
+                    }
+                }
             }
-        } catch (SQLException e) {
-            throw new IOException(e);
+            sql.append(" group by ").append(ZipkinSpanRecord.TRACE_ID);
+            sql.append(" order by min(").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(") desc");
+            sql.append(" limit ").append(request.limit());
+            h2Client.executeQuery(sql.toString(), resultSet -> {
+                while (resultSet.next()) {
+                    traceIds.add(resultSet.getString(ZipkinSpanRecord.TRACE_ID));
+                }
+                return null;
+            }, condition.toArray(new Object[0]));
         }
+
         return getTraces(traceIds);
     }
 
     @Override
-    public List<List<Span>> getTraces(final Set<String> traceIds) throws IOException {
+    @SneakyThrows
+    public List<List<Span>> getTraces(final Set<String> traceIds) {
         if (CollectionUtils.isEmpty(traceIds)) {
             return new ArrayList<>();
         }
-        StringBuilder sql = new StringBuilder();
-        List<Object> condition = new ArrayList<>(5);
-        sql.append("select * from ").append(ZipkinSpanRecord.INDEX_NAME);
-        sql.append(" where ");
-        sql.append(" 1=1 ");
 
-        int i = 0;
-        sql.append(" and ");
-        for (final String traceId : traceIds) {
-            sql.append(ZipkinSpanRecord.TRACE_ID).append(" = ?");
-            condition.add(traceId);
-            if (i != traceIds.size() - 1) {
-                sql.append(" or ");
+        final var tables = tableHelper.getTablesWithinTTL(ZipkinSpanRecord.INDEX_NAME);
+        final var traces = new ArrayList<List<Span>>();
+
+        for (String table : tables) {
+            StringBuilder sql = new StringBuilder();
+            List<Object> condition = new ArrayList<>(5);
+            sql.append("select * from ").append(table);
+            sql.append(" where ");
+            sql.append(JDBCTableInstaller.TABLE_COLUMN).append(" = ?");
+            condition.add(ZipkinSpanRecord.INDEX_NAME);
+
+            int i = 0;
+            sql.append(" and ");
+            for (final String traceId : traceIds) {
+                sql.append(ZipkinSpanRecord.TRACE_ID).append(" = ?");
+                condition.add(traceId);
+                if (i != traceIds.size() - 1) {
+                    sql.append(" or ");
+                }
+                i++;
             }
-            i++;
-        }
 
-        sql.append(" order by ").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" desc");
+            sql.append(" order by ").append(ZipkinSpanRecord.TIMESTAMP_MILLIS).append(" desc");
 
-        try (Connection connection = h2Client.getConnection()) {
-            ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]));
-            return buildTraces(resultSet);
-        } catch (SQLException e) {
-            throw new IOException(e);
+            traces.addAll(
+                h2Client.executeQuery(sql.toString(), this::buildTraces, condition.toArray(new Object[0]))
+            );
         }
+        return traces;
     }
 
     private List<List<Span>> buildTraces(ResultSet resultSet) throws SQLException {
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2TableInstaller.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2TableInstaller.java
index 088a1cf041cf..225ada38cf20 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2TableInstaller.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2TableInstaller.java
@@ -18,157 +18,19 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2;
 
-import com.google.gson.JsonObject;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Map;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.server.core.analysis.Layer;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
-import org.apache.skywalking.oap.server.core.storage.model.ModelInstaller;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
-import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
 import org.apache.skywalking.oap.server.library.client.Client;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
 
-/**
- * H2 table initialization. Create tables without Indexes. H2 is for the demonstration only, so, keep the logic as
- * simple as possible.
- */
 @Slf4j
-public class H2TableInstaller extends ModelInstaller {
-    public static final String ID_COLUMN = Metrics.ID;
-
+public class H2TableInstaller extends JDBCTableInstaller {
     public H2TableInstaller(Client client, ModuleManager moduleManager) {
         super(client, moduleManager);
     }
 
-    @Override
-    public boolean isExists(Model model) throws StorageException {
-        TableMetaInfo.addModel(model);
-        JDBCHikariCPClient jdbcClient = (JDBCHikariCPClient) client;
-        try (Connection conn = jdbcClient.getConnection()) {
-            try (ResultSet rset = conn.getMetaData().getTables(conn.getCatalog(), null, model.getName(), null)) {
-                if (rset.next()) {
-                    return true;
-                }
-            }
-        } catch (SQLException | JDBCClientException e) {
-            throw new StorageException(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public void createTable(Model model) throws StorageException {
-        JDBCHikariCPClient jdbcHikariCPClient = (JDBCHikariCPClient) client;
-        try (Connection connection = jdbcHikariCPClient.getConnection()) {
-            //Consider there additional table columns need to remove from model columns.
-            model = TableMetaInfo.get(model.getName());
-            createTable(jdbcHikariCPClient, connection, model.getName(), model.getColumns(), false);
-            createTableIndexes(jdbcHikariCPClient, connection, model.getName(), model.getColumns(), false);
-            createAdditionalTable(jdbcHikariCPClient, connection, model);
-        } catch (JDBCClientException | SQLException e) {
-            throw new StorageException(e.getMessage(), e);
-        }
-    }
-
     @Override
     public void start() {
         overrideColumnName("value", "value_");
     }
-
-    /**
-     * Set up the data type mapping between Java type and H2 database type
-     */
-    public String getColumn(ModelColumn column) {
-        return transform(column, column.getType(), column.getGenericType());
-    }
-
-    protected String transform(ModelColumn column, Class<?> type, Type genericType) {
-        final String storageName = column.getColumnName().getStorageName();
-        if (Integer.class.equals(type) || int.class.equals(type) || Layer.class.equals(type)) {
-            return storageName + " INT";
-        } else if (Long.class.equals(type) || long.class.equals(type)) {
-            return storageName + " BIGINT";
-        } else if (Double.class.equals(type) || double.class.equals(type)) {
-            return storageName + " DOUBLE";
-        } else if (String.class.equals(type)) {
-            return storageName + " VARCHAR(" + column.getLength() + ")";
-        } else if (StorageDataComplexObject.class.isAssignableFrom(type)) {
-            return storageName + " VARCHAR(20000)";
-        } else if (byte[].class.equals(type)) {
-            return storageName + " MEDIUMTEXT";
-        } else if (JsonObject.class.equals(type)) {
-            return storageName + " VARCHAR(" + column.getLength() + ")";
-        } else if (List.class.isAssignableFrom(type)) {
-            final Type elementType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
-            return transform(column, (Class<?>) elementType, elementType);
-        } else {
-            throw new IllegalArgumentException("Unsupported data type: " + type.getName());
-        }
-    }
-
-    public void createTableIndexes(JDBCHikariCPClient client,
-                                      Connection connection,
-                                      String tableName, List<ModelColumn> columns, boolean additionalTable) throws JDBCClientException {
-    }
-
-    public void createIndex(JDBCHikariCPClient client, Connection connection, String tableName,
-                            SQLBuilder indexSQL) throws JDBCClientException {
-        if (log.isDebugEnabled()) {
-            log.debug("create index for table {}, sql: {} ", tableName, indexSQL.toStringInNewLine());
-        }
-        client.execute(connection, indexSQL.toString());
-    }
-
-    private void createAdditionalTable(JDBCHikariCPClient client,
-                                       Connection connection,
-                                       Model model) throws JDBCClientException {
-        Map<String, SQLDatabaseModelExtension.AdditionalTable> additionalTables = model.getSqlDBModelExtension()
-                                                                                       .getAdditionalTables();
-        for (SQLDatabaseModelExtension.AdditionalTable table : additionalTables.values()) {
-            createTable(client, connection, table.getName(), table.getColumns(), true);
-            createTableIndexes(client, connection, table.getName(), table.getColumns(), true);
-        }
-    }
-
-    public void createTable(JDBCHikariCPClient client,
-                            Connection connection,
-                            String tableName, List<ModelColumn> columns, boolean additionalTable) throws JDBCClientException {
-        SQLBuilder tableCreateSQL = new SQLBuilder("CREATE TABLE IF NOT EXISTS " + tableName + " (");
-        tableCreateSQL.appendLine(ID_COLUMN).appendLine(" VARCHAR(512) ");
-        if (!additionalTable) {
-            /**
-             * 512 is also the ElasticSearch ID size.
-             */
-
-            tableCreateSQL.appendLine("PRIMARY KEY, ");
-        } else {
-            tableCreateSQL.appendLine(", ");
-        }
-        for (int i = 0; i < columns.size(); i++) {
-            ModelColumn column = columns.get(i);
-            tableCreateSQL.appendLine(
-                getColumn(column) + (i != columns.size() - 1 ? "," : ""));
-        }
-        tableCreateSQL.appendLine(")");
-
-        if (log.isDebugEnabled()) {
-            log.debug("creating table: " + tableCreateSQL.toStringInNewLine());
-        }
-
-        client.execute(connection, tableCreateSQL.toString());
-    }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java
index 0a9ed5c65647..bdf76255e21c 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java
@@ -18,27 +18,19 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.mysql;
 
-import java.sql.Connection;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseExtension;
 import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
 import org.apache.skywalking.oap.server.library.client.Client;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller;
-import com.google.gson.JsonObject;
-import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
 
 /**
  * Extend H2TableInstaller but match MySQL SQL syntax.
  */
 @Slf4j
-public class MySQLTableInstaller extends H2TableInstaller {
+public class MySQLTableInstaller extends JDBCTableInstaller {
     public MySQLTableInstaller(Client client, ModuleManager moduleManager) {
         super(client, moduleManager);
     }
@@ -48,90 +40,15 @@ public void start() {
         /*
          * Override column because the default column names in core have syntax conflict with MySQL.
          */
-        this.overrideColumnName("precision", "cal_precision");
-        this.overrideColumnName("match", "match_num");
-    }
-
-    @Override
-    public void createTable(
-        JDBCHikariCPClient client,
-        Connection connection,
-        String tableName,
-        List<ModelColumn> columns,
-        boolean additionalTable) throws JDBCClientException {
-        SQLBuilder tableCreateSQL =
-            new SQLBuilder("CREATE TABLE IF NOT EXISTS " + tableName + " (");
-        tableCreateSQL.append(ID_COLUMN).append(" VARCHAR(512) ");
-        if (!additionalTable) {
-            tableCreateSQL.appendLine("PRIMARY KEY, ");
-        } else {
-            tableCreateSQL.appendLine(", ");
-        }
-        for (int i = 0; i < columns.size(); i++) {
-            ModelColumn column = columns.get(i);
-            tableCreateSQL.appendLine(
-                getColumn(column) + (i != columns.size() ? "," : ""));
-        }
-
-        int indexSeq = 0;
-
-        // Add indexes
-        List<String> columnList =
-            columns.stream().map(column -> column.getColumnName().getStorageName()).collect(
-                Collectors.toList());
-        for (int i = 0; i < columns.size(); i++) {
-            ModelColumn column = columns.get(i);
-            for (final SQLDatabaseExtension.MultiColumnsIndex index : column.getSqlDatabaseExtension()
-                                                                            .getIndices()) {
-                final String[] multiColumns = index.getColumns();
-                // Create MultiColumnsIndex on the additional table only when it contains all need columns.
-                if (additionalTable && !columnList.containsAll(Arrays.asList(multiColumns))) {
-                    continue;
-                }
-                tableCreateSQL.append("KEY K")
-                    .append(String.valueOf(indexSeq++));
-                tableCreateSQL.append(" (");
-                for (int j = 0; j < multiColumns.length; j++) {
-                    tableCreateSQL.append(multiColumns[j]);
-                    if (j < multiColumns.length - 1) {
-                        tableCreateSQL.append(",");
-                    }
-                }
-                tableCreateSQL.appendLine("),");
-            }
-            if (column.shouldIndex() && column.getLength() < 513) {
-                tableCreateSQL
-                    .append("KEY K")
-                    .append(String.valueOf(indexSeq++))
-                    .append(" (")
-                    .append(column.getColumnName().getStorageName())
-                    .append(")");
-                tableCreateSQL.appendLine(i != columns.size() - 1 ? "," : "");
-            }
-        }
-        tableCreateSQL.appendLine(")");
-
-        if (log.isDebugEnabled()) {
-            log.debug("creating table: " + tableCreateSQL.toStringInNewLine());
-        }
-
-        client.execute(connection, tableCreateSQL.toString());
-    }
-
-    @Override
-    public void createTableIndexes(
-        JDBCHikariCPClient client,
-        Connection connection,
-        String tableName, List<ModelColumn> columns,
-        boolean additionalTable)
-        throws JDBCClientException {
-        // Do nothing, indexes have been created inside create tables.
+        overrideColumnName("value", "value_");
+        overrideColumnName("precision", "cal_precision");
+        overrideColumnName("match", "match_num");
     }
 
     @Override
-    public String getColumn(final ModelColumn column) {
-        final String storageName = column.getColumnName().getStorageName();
-        final Class<?> type = column.getType();
+    public String getColumnDefinition(final ModelColumn column) {
+        final var storageName = column.getColumnName().getStorageName();
+        final var type = column.getType();
         if (StorageDataComplexObject.class.isAssignableFrom(type)) {
             return storageName + " MEDIUMTEXT";
         } else if (String.class.equals(type)) {
@@ -147,6 +64,6 @@ public String getColumn(final ModelColumn column) {
                 return storageName + " VARCHAR(" + column.getLength() + ")";
             }
         }
-        return super.getColumn(column);
+        return super.getColumnDefinition(column);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLStorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLStorageProvider.java
index 5d36d84dad66..e59ce3992e1c 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLStorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLStorageProvider.java
@@ -49,9 +49,9 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
 
         this.registerServiceImplementation(
             IMetricsQueryDAO.class,
-            new PostgreSQLMetricsQueryDAO(jdbcClient));
+            new PostgreSQLMetricsQueryDAO(jdbcClient, tableHelper));
         this.registerServiceImplementation(
             IAggregationQueryDAO.class,
-            new PostgreSQLAggregationQueryDAO(jdbcClient));
+            new PostgreSQLAggregationQueryDAO(jdbcClient, tableHelper));
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
index 37857dabc12a..fd76087b4bcd 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/PostgreSQLTableInstaller.java
@@ -18,25 +18,19 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.postgresql;
 
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.sql.Connection;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
+import com.google.gson.JsonObject;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
 import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseExtension;
 import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
 import org.apache.skywalking.oap.server.library.client.Client;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller;
-import com.google.gson.JsonObject;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
 
-public class PostgreSQLTableInstaller extends H2TableInstaller {
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+public class PostgreSQLTableInstaller extends JDBCTableInstaller {
     public PostgreSQLTableInstaller(Client client, ModuleManager moduleManager) {
         super(client, moduleManager);
     }
@@ -46,70 +40,13 @@ public void start() {
         /*
          * Override column because the default column names in core are reserved in PostgreSQL.
          */
-        this.overrideColumnName("precision", "cal_precision");
-        this.overrideColumnName("match", "match_num");
-    }
-
-    @Override
-    public void createTableIndexes(
-        JDBCHikariCPClient client,
-        Connection connection,
-        String tableName,
-        List<ModelColumn> columns,
-        boolean additionalTable) throws JDBCClientException {
-        // Additional table's id follow the main table can not be primary key
-        if (additionalTable) {
-            SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX ");
-            tableIndexSQL.append(tableName.toUpperCase()).append("_id_IDX");
-            tableIndexSQL.append(" ON ").append(tableName).append("(").append(ID_COLUMN).append(")");
-            createIndex(client, connection, tableName, tableIndexSQL);
-        }
-
-        int indexSeq = 0;
-        for (final ModelColumn modelColumn : columns) {
-            if (modelColumn.shouldIndex() && modelColumn.getLength() < 256) {
-                    SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX ");
-                    tableIndexSQL.append(tableName.toUpperCase())
-                                 .append("_")
-                                 .append(String.valueOf(indexSeq++))
-                                 .append("_IDX ");
-                    tableIndexSQL.append("ON ").append(tableName).append("(")
-                                 .append(modelColumn.getColumnName().getStorageName())
-                                 .append(")");
-                    createIndex(client, connection, tableName, tableIndexSQL);
-            }
-        }
-
-        List<String> columnList = columns.stream().map(column -> column.getColumnName().getStorageName()).collect(
-            Collectors.toList());
-        for (final ModelColumn modelColumn : columns) {
-            for (final SQLDatabaseExtension.MultiColumnsIndex index : modelColumn.getSqlDatabaseExtension()
-                                                                                 .getIndices()) {
-                final String[] multiColumns = index.getColumns();
-                //Create MultiColumnsIndex on the additional table only when it contains all need columns.
-                if (additionalTable && !columnList.containsAll(Arrays.asList(multiColumns))) {
-                    continue;
-                }
-                SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX ");
-                tableIndexSQL.append(tableName.toUpperCase())
-                             .append("_")
-                             .append(String.valueOf(indexSeq++))
-                             .append("_IDX ");
-                tableIndexSQL.append(" ON ").append(tableName).append("(");
-                for (int i = 0; i < multiColumns.length; i++) {
-                    tableIndexSQL.append(multiColumns[i]);
-                    if (i < multiColumns.length - 1) {
-                        tableIndexSQL.append(",");
-                    }
-                }
-                tableIndexSQL.append(")");
-                createIndex(client, connection, tableName, tableIndexSQL);
-            }
-        }
+        overrideColumnName("value", "value_");
+        overrideColumnName("precision", "cal_precision");
+        overrideColumnName("match", "match_num");
     }
 
     @Override
-    protected String transform(ModelColumn column, Class<?> type, Type genericType) {
+    protected String getColumnDefinition(ModelColumn column, Class<?> type, Type genericType) {
         final String storageName = column.getColumnName().getStorageName();
         if (Integer.class.equals(type) || int.class.equals(type) || Layer.class.equals(type)) {
             return storageName + " INT";
@@ -131,14 +68,14 @@ protected String transform(ModelColumn column, Class<?> type, Type genericType)
             }
         } else if (List.class.isAssignableFrom(type)) {
             final Type elementType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
-            return transform(column, (Class<?>) elementType, elementType);
+            return getColumnDefinition(column, (Class<?>) elementType, elementType);
         } else {
             throw new IllegalArgumentException("Unsupported data type: " + type.getName());
         }
     }
 
     @Override
-    public String getColumn(final ModelColumn column) {
+    public String getColumnDefinition(final ModelColumn column) {
         final String storageName = column.getColumnName().getStorageName();
         final Class<?> type = column.getType();
         if (StorageDataComplexObject.class.isAssignableFrom(type)) {
@@ -156,6 +93,6 @@ public String getColumn(final ModelColumn column) {
                 return storageName + " VARCHAR(" + column.getLength() + ")";
             }
         }
-        return super.getColumn(column);
+        return super.getColumnDefinition(column);
     }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLAggregationQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLAggregationQueryDAO.java
index ea076da5828c..807520045e86 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLAggregationQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLAggregationQueryDAO.java
@@ -19,16 +19,16 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.postgresql.dao;
 
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCAggregationQueryDAO;
 
 public class PostgreSQLAggregationQueryDAO extends JDBCAggregationQueryDAO {
 
-    public PostgreSQLAggregationQueryDAO(JDBCHikariCPClient h2Client) {
-        super(h2Client);
+    public PostgreSQLAggregationQueryDAO(JDBCClient h2Client, TableHelper tableHelper) {
+        super(h2Client, tableHelper);
     }
 
-    @Override
     protected StringBuilder buildMetricsValueSql(String valueColumnName, String metricsName) {
         StringBuilder sql = new StringBuilder();
         sql.append("select * from (select avg(")
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLMetricsQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLMetricsQueryDAO.java
index 92fd4139d58c..13f1a38668c2 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLMetricsQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/postgresql/dao/PostgreSQLMetricsQueryDAO.java
@@ -19,13 +19,14 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.postgresql.dao;
 
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCMetricsQueryDAO;
 
 public class PostgreSQLMetricsQueryDAO extends JDBCMetricsQueryDAO {
 
-    public PostgreSQLMetricsQueryDAO(JDBCHikariCPClient h2Client) {
-        super(h2Client);
+    public PostgreSQLMetricsQueryDAO(JDBCClient h2Client, TableHelper tableHelper) {
+        super(h2Client, tableHelper);
     }
 
     @Override
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/pom.xml b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/pom.xml
deleted file mode 100644
index f0a1bb37755d..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/pom.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  ~
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>server-storage-plugin</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.5.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>storage-shardingsphere-plugin</artifactId>
-    <packaging>jar</packaging>
-
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>server-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>library-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>storage-jdbc-hikaricp-plugin</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-            <version>8.0.13</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-</project>
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/DurationWithinTTL.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/DurationWithinTTL.java
deleted file mode 100644
index 53b9c64d26cf..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/DurationWithinTTL.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import lombok.Setter;
-import org.apache.skywalking.oap.server.core.UnexpectedException;
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.query.DurationUtils;
-import org.apache.skywalking.oap.server.core.query.enumeration.Step;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.joda.time.DateTime;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
-
-public enum DurationWithinTTL {
-    INSTANCE;
-
-    private static final DateTimeFormatter YYYYMMDD = DateTimeFormat.forPattern("yyyyMMdd");
-    private static final DateTimeFormatter YYYYMMDDHH = DateTimeFormat.forPattern("yyyyMMddHH");
-    private static final DateTimeFormatter YYYYMMDDHHMM = DateTimeFormat.forPattern("yyyyMMddHHmm");
-    private static final DateTimeFormatter YYYYMMDDHHMMSS = DateTimeFormat.forPattern("yyyyMMddHHmmss");
-
-    @Setter
-    private ConfigService configService;
-
-    /**
-     * @param duration Origin Duration instance
-     * @return new Duration instance and the time range within the Metrics TTL, if origin duration is null then return null.
-     */
-    public Duration getMetricDurationWithinTTL(final Duration duration) {
-        if (duration == null) {
-            return null;
-        }
-        Duration durationWithinTTL = new Duration();
-        durationWithinTTL.setStart(DurationWithinTTL.INSTANCE.getTrimmedMetricStartTime(duration.getStep(), duration.getStart()));
-        durationWithinTTL.setEnd(DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(duration.getStep(), duration.getEnd()));
-        durationWithinTTL.setStep(duration.getStep());
-
-        return durationWithinTTL;
-    }
-
-    /**
-     * @param duration Origin Duration instance
-     * @return new Duration instance and the time range within the Record TTL, if origin duration is null then return null.
-     */
-    public Duration getRecordDurationWithinTTL(final Duration duration) {
-        if (duration == null) {
-            return null;
-        }
-        Duration durationWithinTTL = new Duration();
-        durationWithinTTL.setStart(DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(duration.getStep(), duration.getStart()));
-        durationWithinTTL.setEnd(DurationWithinTTL.INSTANCE.getTrimmedRecordEndTime(duration.getStep(), duration.getEnd()));
-        durationWithinTTL.setStep(duration.getStep());
-
-        return durationWithinTTL;
-    }
-
-    // Trim the startStr according to the record TTL, for query
-    public String getTrimmedRecordStartTime(Step step, String startStr) {
-        if (configService == null) {
-            throw new UnexpectedException("ConfigService can not be null, should set ConfigService first.");
-        }
-        return trimStartTime(step, startStr, configService.getRecordDataTTL());
-    }
-
-    // Trim the startStr according to the metric TTL, for query
-    public String getTrimmedMetricStartTime(Step step, String startStr) {
-        if (configService == null) {
-            throw new UnexpectedException("ConfigService can not be null, should set ConfigService first.");
-        }
-        return trimStartTime(step, startStr, configService.getMetricsDataTTL());
-    }
-
-    // Trim the endStr according to the record TTL, for query
-    public String getTrimmedRecordEndTime(Step step, String endStr) {
-        return trimEndTime(step, endStr);
-    }
-
-    // Trim the endStr according to the metric TTL, for query
-    public String getTrimmedMetricEndTime(Step step, String endStr) {
-        return trimEndTime(step, endStr);
-    }
-
-    private String trimStartTime(Step step, String startStr, int ttl) {
-        long startDate = DurationUtils.INSTANCE.convertToTimeBucket(step, startStr);
-        long timeFloor = Long.parseLong(DateTime.now().plusDays(1 - ttl).toString("yyyyMMdd"));
-        switch (step) {
-            case DAY:
-                return YYYYMMDD.parseDateTime(String.valueOf(Math.max(timeFloor, startDate))).toString("yyyy-MM-dd");
-            case HOUR:
-                timeFloor = timeFloor * 100;
-                return YYYYMMDDHH.parseDateTime(String.valueOf(Math.max(timeFloor, startDate))).toString("yyyy-MM-dd HH");
-            case MINUTE:
-                timeFloor = timeFloor * 100 * 100;
-                return YYYYMMDDHHMM.parseDateTime(String.valueOf(Math.max(timeFloor, startDate))).toString("yyyy-MM-dd HHmm");
-            case SECOND:
-                timeFloor = timeFloor * 100 * 100 * 100;
-                return YYYYMMDDHHMMSS.parseDateTime(String.valueOf(Math.max(timeFloor, startDate))).toString("yyyy-MM-dd HHmmss");
-        }
-
-        throw new UnexpectedException("Unsupported step " + step.name());
-    }
-
-    // Trim the endStr according to the real date, for query
-    public String trimEndTime(Step step, String endStr) {
-        long endDate = DurationUtils.INSTANCE.convertToTimeBucket(step, endStr);
-        long timeCeiling = Long.parseLong(DateTime.now().toString("yyyyMMdd"));
-        switch (step) {
-            case DAY:
-                return YYYYMMDD.parseDateTime(String.valueOf(Math.min(endDate, timeCeiling))).toString("yyyy-MM-dd");
-            case HOUR:
-                timeCeiling = (timeCeiling * 100) + 23;
-                return YYYYMMDDHH.parseDateTime(String.valueOf(Math.min(endDate, timeCeiling))).toString("yyyy-MM-dd HH");
-            case MINUTE:
-                timeCeiling = ((timeCeiling * 100) + 23) * 100 + 59;
-                return YYYYMMDDHHMM.parseDateTime(String.valueOf(Math.min(endDate, timeCeiling))).toString("yyyy-MM-dd HHmm");
-            case SECOND:
-                timeCeiling = (((timeCeiling * 100) + 23) * 100 + 59) * 100 + 59;
-                return YYYYMMDDHHMMSS.parseDateTime(String.valueOf(Math.min(endDate, timeCeiling))).toString("yyyy-MM-dd HHmmss");
-        }
-
-        throw new UnexpectedException("Unsupported step " + step.name());
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRule.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRule.java
deleted file mode 100644
index caaccc21530b..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRule.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import lombok.Builder;
-import lombok.Getter;
-import lombok.Setter;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
-
-@Getter
-@Setter
-@Builder(toBuilder = true)
-public class ShardingRule {
-    private String operation;
-    private String table;
-    private String actualDataNodes;
-    private String actualDataSources;
-    private String databaseStrategyType;
-    private String databaseShardingColumn;
-    private String databaseShardingAlgorithmType;
-    private String databaseShardingAlgorithmProps;
-    private String tableStrategyType;
-    private String tableShardingColumn;
-    private String tableShardingAlgorithmType;
-    private String tableShardingAlgorithmProps;
-    private String keyGenerateColumn;
-    private String keyGeneratorType;
-    private String keyGeneratorProps;
-
-   public String toShardingRuleSQL() {
-        SQLBuilder ruleSQL = new SQLBuilder();
-        ruleSQL.append(operation);
-        ruleSQL.append(" SHARDING TABLE RULE ");
-        ruleSQL.append(table).appendLine("(");
-        ruleSQL.append("DATANODES(").append(actualDataNodes).appendLine("),");
-        ruleSQL.append("DATABASE_STRATEGY(TYPE=").append(databaseStrategyType).appendLine(",");
-        ruleSQL.append("SHARDING_COLUMN=").append(databaseShardingColumn).appendLine(",");
-        ruleSQL.append("SHARDING_ALGORITHM(TYPE(NAME=").append(databaseShardingAlgorithmType).appendLine(",");
-        ruleSQL.append("PROPERTIES(").append(databaseShardingAlgorithmProps);
-        ruleSQL.appendLine(")))),");
-        ruleSQL.append("TABLE_STRATEGY(TYPE=").append(tableStrategyType).appendLine(",");
-        ruleSQL.append("SHARDING_COLUMN=").append(tableShardingColumn).appendLine(",");
-        ruleSQL.append("SHARDING_ALGORITHM(TYPE(NAME=").append(tableShardingAlgorithmType).appendLine(",");
-        ruleSQL.append("PROPERTIES(").append(tableShardingAlgorithmProps);
-        ruleSQL.append(")))))");
-        return ruleSQL.toString();
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRulesOperator.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRulesOperator.java
deleted file mode 100644
index 7588a8872471..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRulesOperator.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.skywalking.oap.server.core.UnexpectedException;
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
-import org.joda.time.DateTime;
-import org.joda.time.Days;
-
-public enum ShardingRulesOperator {
-    INSTANCE;
-
-    private final Map<String, ShardingRule> modelShardingRules = new HashMap<>();
-
-    private static final String TIME_RELATIVE_ID_SHARDING_EXPRESSION =
-        "${long time_bucket = Long.parseLong(id.substring(0,id.indexOf('_')));" +
-        "if (10000000L < time_bucket && time_bucket < 99999999L) {return time_bucket;};" +
-        "if (1000000000L < time_bucket && time_bucket < 9999999999L) {return time_bucket.intdiv(100);};" +
-        "if (100000000000L < time_bucket && time_bucket < 999999999999L) {return time_bucket.intdiv(100*100);};" +
-        "if (10000000000000L < time_bucket && time_bucket < 99999999999999L) {return time_bucket.intdiv(100*100*100);};" +
-        "}";
-
-    private static final String TIME_SEC_RANGE_SHARDING_EXPRESSION =
-        "\"datetime-pattern\"=\"yyyyMMddHHmmss\"," +
-        "\"datetime-interval-unit\"=\"days\"," +
-        "\"datetime-interval-amount\"=\"1\"," +
-        "\"sharding-suffix-pattern\"=\"yyyyMMdd\"," +
-        "\"datetime-lower\"=\"20220101000000\"," +
-        "\"datetime-upper\"=\"20991201000000\"";
-
-    private static final String TIME_MIN_RANGE_SHARDING_EXPRESSION =
-        "\"datetime-pattern\"=\"yyyyMMddHHmm\"," +
-        "\"datetime-interval-unit\"=\"days\"," +
-        "\"datetime-interval-amount\"=\"1\"," +
-        "\"sharding-suffix-pattern\"=\"yyyyMMdd\"," +
-        "\"datetime-lower\"=\"202201010000\"," +
-        "\"datetime-upper\"=\"209912010000\"";
-
-    private static final String TIME_BUCKET_SHARDING_EXPRESSION =
-        "${" +
-        "if (10000000L < time_bucket && time_bucket < 99999999L) {return time_bucket;};" +
-        "if (1000000000L < time_bucket && time_bucket < 9999999999L) {return time_bucket.intdiv(100);};" +
-        "if (100000000000L < time_bucket && time_bucket < 999999999999L) {return time_bucket.intdiv(100*100);};" +
-        "if (10000000000000L < time_bucket && time_bucket < 99999999999999L) {return time_bucket.intdiv(100*100*100);};" +
-        "}";
-
-    public void start(JDBCHikariCPClient client) throws IOException, SQLException, StorageException {
-        initShardingRules(client);
-    }
-
-    public boolean createOrUpdateShardingRule(JDBCHikariCPClient client, Model model, Set<String> dataSources, int ttl) throws StorageException {
-        boolean isExecuted;
-        ShardingRule.ShardingRuleBuilder builder = ShardingRule.builder();
-        builder.table(model.getName());
-        String tableName = model.getName();
-        SQLDatabaseModelExtension.Sharding sharding = model.getSqlDBModelExtension().getSharding().orElseThrow(
-            () -> new UnexpectedException("Sharding should not be empty."));
-        isExecuted = executeShardingRule(
-            buildShardingRule(builder, tableName, dataSources, sharding.getShardingAlgorithm(),
-                               sharding.getTableShardingColumn(),
-                               sharding.getDataSourceShardingColumn(),
-                               ttl,
-                               DateTime.now()
-            ),
-            client,
-            tableName
-        );
-        // additional tables
-        for (String additionalTable : model.getSqlDBModelExtension().getAdditionalTables().keySet()) {
-            ShardingRule.ShardingRuleBuilder additionalBuilder = ShardingRule.builder();
-            additionalBuilder.table(additionalTable);
-            isExecuted = executeShardingRule(
-                buildShardingRule(additionalBuilder, additionalTable, dataSources, sharding.getShardingAlgorithm(),
-                                  sharding.getTableShardingColumn(),
-                                  sharding.getDataSourceShardingColumn(), ttl, DateTime.now()
-                ), client, additionalTable
-            );
-        }
-
-        return isExecuted;
-    }
-
-    private void initShardingRules(JDBCHikariCPClient client) throws IOException {
-        SQLBuilder sql = new SQLBuilder("SHOW SHARDING TABLE RULES");
-        try (Connection connection = client.getConnection()) {
-            ResultSet resultSet = client.executeQuery(connection, sql.toString());
-            while (resultSet.next()) {
-                ShardingRule.ShardingRuleBuilder builder = ShardingRule.builder();
-                builder.table(resultSet.getString("TABLE"));
-                builder.actualDataNodes(resultSet.getString("ACTUAL_DATA_NODES"));
-                builder.actualDataSources(resultSet.getString("ACTUAL_DATA_SOURCES"));
-                // todo: shardingsphere-5.1.2 response DATABASE_STRATEGY and TABLE_STRATEGY type "inline" but should "standard"
-                builder.databaseStrategyType("standard");
-                builder.databaseShardingColumn(resultSet.getString("DATABASE_SHARDING_COLUMN"));
-                builder.databaseShardingAlgorithmType(resultSet.getString("DATABASE_SHARDING_ALGORITHM_TYPE"));
-                builder.databaseShardingAlgorithmProps(resultSet.getString("DATABASE_SHARDING_ALGORITHM_PROPS"));
-                // todo: shardingsphere-5.1.2 response DATABASE_STRATEGY and TABLE_STRATEGY type "inline" but should "standard"
-                builder.tableStrategyType("standard");
-                builder.tableShardingColumn(resultSet.getString("TABLE_SHARDING_COLUMN"));
-                builder.tableShardingAlgorithmType(resultSet.getString("TABLE_SHARDING_ALGORITHM_TYPE"));
-                builder.tableShardingAlgorithmProps(resultSet.getString("TABLE_SHARDING_ALGORITHM_PROPS"));
-                builder.keyGenerateColumn(resultSet.getString("KEY_GENERATE_COLUMN"));
-                builder.keyGeneratorType(resultSet.getString("KEY_GENERATOR_TYPE"));
-                builder.keyGeneratorProps(resultSet.getString("KEY_GENERATOR_PROPS"));
-
-                ShardingRule shardingRule = builder.build();
-                modelShardingRules.put(shardingRule.getTable(), shardingRule);
-            }
-        } catch (JDBCClientException | SQLException e) {
-            throw new IOException(e.getMessage(), e);
-        }
-    }
-
-    private void registerShardingRule(String tableName, ShardingRule rule) {
-        modelShardingRules.put(tableName, rule);
-    }
-
-    private ShardingRule.ShardingRuleBuilder buildShardingRule(ShardingRule.ShardingRuleBuilder builder,
-                                      String tableName,
-                                      Set<String> dataSources,
-                                      ShardingAlgorithm shardingAlgorithm,
-                                      String tableShardingColumn,
-                                      String dsShardingColumn,
-                                      int ttl,
-                                      DateTime currentDate) {
-        buildDataNodes(builder, tableName, dataSources, ttl, currentDate);
-        buildDatabaseStrategy(builder, dsShardingColumn, dataSources.size());
-
-        switch (shardingAlgorithm) {
-            case TIME_SEC_RANGE_SHARDING_ALGORITHM:
-                buildTimeRangeTableStrategy(builder, tableShardingColumn, TIME_SEC_RANGE_SHARDING_EXPRESSION);
-                break;
-            case TIME_MIN_RANGE_SHARDING_ALGORITHM:
-                buildTimeRangeTableStrategy(builder, tableShardingColumn, TIME_MIN_RANGE_SHARDING_EXPRESSION);
-                break;
-            case TIME_RELATIVE_ID_SHARDING_ALGORITHM:
-                buildExpressionTableStrategy(builder, tableName, tableShardingColumn,
-                                             TIME_RELATIVE_ID_SHARDING_EXPRESSION);
-                break;
-            case TIME_BUCKET_SHARDING_ALGORITHM:
-                buildExpressionTableStrategy(builder, tableName, tableShardingColumn, TIME_BUCKET_SHARDING_EXPRESSION);
-                break;
-            default:
-                throw new UnexpectedException("Unsupported sharding algorithm " + shardingAlgorithm);
-        }
-        return builder;
-    }
-
-    private void buildDataNodes(ShardingRule.ShardingRuleBuilder builder,
-                                String tableName,
-                                Set<String> dataSources,
-                                int ttl,
-                                DateTime currentDate) {
-        DateTime startDateTime = currentDate.plusDays(1 - ttl);
-        DateTime endDate = currentDate.plusDays(1);
-        int days = Days.daysBetween(startDateTime, endDate).getDays();
-        List<DateTime> timeRanges = new ArrayList<>();
-        StringBuilder nodesBuilder = new StringBuilder();
-        for (int i = 0; i <= days; i++) {
-            timeRanges.add(startDateTime.plusDays(i));
-        }
-        dataSources.forEach(dataSource -> {
-            timeRanges.forEach(dateTime -> {
-                nodesBuilder.append("\"")
-                            .append(dataSource)
-                            .append(".")
-                            .append(tableName)
-                            .append("_")
-                            .append(dateTime.toString("yyyyMMdd"))
-                            .append("\"")
-                            .append(",");
-            });
-        });
-        builder.actualDataNodes(nodesBuilder.substring(0, nodesBuilder.length() - 1));
-    }
-
-    private void buildDatabaseStrategy(ShardingRule.ShardingRuleBuilder builder,
-                                       String shardingColumn,
-                                       int dsCount) {
-        StringBuilder propsBuilder = new StringBuilder();
-        propsBuilder.append("\"algorithm-expression\"=\"ds_${")
-                  .append(shardingColumn)
-                  .append(".hashCode()&Integer.MAX_VALUE%")
-                  .append(dsCount)
-                  .append("}\"");
-
-        builder.databaseStrategyType("\"standard\"")
-               .databaseShardingColumn(shardingColumn)
-               .databaseShardingAlgorithmType("\"inline\"")
-               .databaseShardingAlgorithmProps(propsBuilder.toString());
-
-    }
-
-    private void buildTimeRangeTableStrategy(ShardingRule.ShardingRuleBuilder builder,
-                                             String tableShardingColumn, String algorithmExpression) {
-        builder.tableStrategyType("\"standard\"")
-               .tableShardingColumn(tableShardingColumn)
-               .tableShardingAlgorithmType("\"interval\"")
-               .tableShardingAlgorithmProps(algorithmExpression);
-    }
-
-    private void buildExpressionTableStrategy(ShardingRule.ShardingRuleBuilder builder,
-                                              String tableName,
-                                              String tableShardingColumn,
-                                              String algorithmExpression
-                                                                          ) {
-        StringBuilder propsBuilder = new StringBuilder();
-        propsBuilder.append("\"allow-range-query-with-inline-sharding\"=\"true\",")
-                    .append("\"algorithm-expression\"=\"")
-                    .append(tableName)
-                    .append("_")
-                    .append(algorithmExpression)
-                    .append("\"");
-
-        builder.tableStrategyType("\"standard\"")
-               .tableShardingColumn(tableShardingColumn)
-               .tableShardingAlgorithmType("\"inline\"")
-               .tableShardingAlgorithmProps(propsBuilder.toString());
-
-    }
-
-    private boolean executeShardingRule(ShardingRule.ShardingRuleBuilder builder,
-                                     JDBCHikariCPClient client,
-                                     String tableName) throws StorageException {
-        ShardingRule existRule = modelShardingRules.get(tableName);
-        ShardingRule shardingRule;
-        String shardingRuleSQL;
-        if (existRule == null) {
-            builder.operation("CREATE");
-            shardingRule = builder.build();
-            shardingRuleSQL = shardingRule.toShardingRuleSQL();
-        } else {
-            builder.operation("ALTER");
-            existRule.setOperation("ALTER");
-            shardingRule = builder.build();
-            shardingRuleSQL = shardingRule.toShardingRuleSQL();
-            if (existRule.toShardingRuleSQL().equals(shardingRuleSQL.replaceAll("\"", ""))) {
-                return false;
-            }
-        }
-
-        try (Connection connection = client.getConnection()) {
-            SQLBuilder ruleSQL = new SQLBuilder(shardingRuleSQL);
-            client.execute(connection, ruleSQL.toString());
-            registerShardingRule(tableName, shardingRule);
-        } catch (JDBCClientException | SQLException e) {
-            throw new StorageException(e.getMessage(), e);
-        }
-
-        return true;
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingSphereTableInstaller.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingSphereTableInstaller.java
deleted file mode 100644
index 252ff8688dab..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingSphereTableInstaller.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Set;
-import org.apache.skywalking.oap.server.core.CoreModule;
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
-import org.apache.skywalking.oap.server.library.client.Client;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.H2TableInstaller;
-
-/**
- * ShardingSphere table installer delegates all the works to
- * the table installer (e.g. H2TableInstaller, MySQLTableInstaller)
- * of the backed storage (e.g. H2, MySQL), and then add sharding rules.
- */
-public class ShardingSphereTableInstaller extends H2TableInstaller {
-    private final H2TableInstaller delegatee;
-    private final Set<String> dataSources;
-    private final ModuleManager moduleManager;
-
-    public ShardingSphereTableInstaller(Client client,
-                                        ModuleManager moduleManager,
-                                        Set<String> dataSources,
-                                        H2TableInstaller delegatee) {
-        super(client, moduleManager);
-        this.dataSources = dataSources;
-        this.delegatee = delegatee;
-        this.moduleManager = moduleManager;
-    }
-
-    @Override
-    public boolean isExists(Model model) throws StorageException {
-        boolean isRuleExecuted = false;
-        boolean isTableExist = isTableExists(model);
-        JDBCHikariCPClient jdbcClient = (JDBCHikariCPClient) client;
-        ConfigService configService = moduleManager.find(CoreModule.NAME).provider().getService(ConfigService.class);
-        int ttl = model.isRecord() ? configService.getRecordDataTTL() : configService.getMetricsDataTTL();
-        if (model.getSqlDBModelExtension().isShardingTable()) {
-            isRuleExecuted = ShardingRulesOperator.INSTANCE.createOrUpdateShardingRule(jdbcClient, model, this.dataSources, ttl);
-        }
-        return isTableExist && !isRuleExecuted;
-    }
-
-    private boolean isTableExists(Model model) throws StorageException {
-        TableMetaInfo.addModel(model);
-        JDBCHikariCPClient jdbcClient = (JDBCHikariCPClient) client;
-        try (Connection conn = jdbcClient.getConnection()) {
-            ResultSet resultSet = jdbcClient.executeQuery(conn, String.format("SHOW LOGICAL TABLES LIKE '%s'", model.getName()));
-            if (resultSet.next()) {
-                return true;
-            }
-        } catch (SQLException | JDBCClientException e) {
-            throw new StorageException(e.getMessage(), e);
-        }
-        return false;
-    }
-
-    @Override
-    public void start() {
-        delegatee.start();
-    }
-
-    @Override
-    public void createTable(
-        JDBCHikariCPClient client,
-        Connection connection,
-        String tableName,
-        List<ModelColumn> columns,
-        boolean additionalTable) throws JDBCClientException {
-        delegatee.createTable(client, connection, tableName, columns, additionalTable);
-    }
-
-    @Override
-    public void createTableIndexes(
-        JDBCHikariCPClient client,
-        Connection connection,
-        String tableName,
-        List<ModelColumn> columns,
-        boolean additionalTable) throws JDBCClientException {
-        delegatee.createTableIndexes(client, connection, tableName, columns, additionalTable);
-    }
-
-    @Override
-    public String getColumn(ModelColumn column) {
-        return delegatee.getColumn(column);
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingAggregationQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingAggregationQueryDAO.java
deleted file mode 100644
index 0d58e43256e7..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingAggregationQueryDAO.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.input.TopNCondition;
-import org.apache.skywalking.oap.server.core.query.type.KeyValue;
-import org.apache.skywalking.oap.server.core.query.type.SelectedRecord;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCAggregationQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-
-public class ShardingAggregationQueryDAO extends JDBCAggregationQueryDAO {
-
-    public ShardingAggregationQueryDAO(JDBCHikariCPClient h2Client) {
-        super(h2Client);
-    }
-
-    @Override
-    public List<SelectedRecord> sortMetrics(final TopNCondition metrics,
-                                            final String valueColumnName,
-                                            final Duration duration,
-                                            List<KeyValue> additionalConditions) throws IOException {
-
-        return super.sortMetrics(
-            metrics,
-            valueColumnName,
-            DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration),
-            additionalConditions
-        );
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingBrowserLogQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingBrowserLogQueryDAO.java
deleted file mode 100644
index f9511d657706..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingBrowserLogQueryDAO.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCBrowserLogQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-
-public class ShardingBrowserLogQueryDAO extends JDBCBrowserLogQueryDAO {
-
-    public ShardingBrowserLogQueryDAO(JDBCHikariCPClient jdbcClient) {
-        super(jdbcClient);
-    }
-
-    @Override
-    public BrowserErrorLogs queryBrowserErrorLogs(String serviceId,
-                                                  String serviceVersionId,
-                                                  String pagePathId,
-                                                  BrowserErrorCategory category,
-                                                  Duration duration,
-                                                  int limit,
-                                                  int from) throws IOException {
-        return super.queryBrowserErrorLogs(
-            serviceId,
-            serviceVersionId,
-            pagePathId,
-            category,
-            DurationWithinTTL.INSTANCE.getRecordDurationWithinTTL(duration),
-            limit,
-            from
-        );
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingHistoryDeleteDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingHistoryDeleteDAO.java
deleted file mode 100644
index 4719e0c3b16a..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingHistoryDeleteDAO.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.server.core.analysis.DownSampling;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.ModelInstaller;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCHistoryDeleteDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.ShardingRulesOperator;
-import org.joda.time.DateTime;
-
-@Slf4j
-public class ShardingHistoryDeleteDAO extends JDBCHistoryDeleteDAO {
-
-    private final JDBCHikariCPClient client;
-    private final ModuleManager manager;
-    private final Set<String> dataSources;
-    private final Map<String, Long> tableLatestSuccess;
-    private final ModelInstaller modelInstaller;
-
-    public ShardingHistoryDeleteDAO(JDBCHikariCPClient client,
-                                    Set<String> dataSources,
-                                    ModuleManager manager,
-                                    ModelInstaller modelInstaller) {
-        super(client);
-        this.client = client;
-        this.manager = manager;
-        this.dataSources = dataSources;
-        this.tableLatestSuccess = new HashMap<>();
-        this.modelInstaller = modelInstaller;
-    }
-
-    @Override
-    public void deleteHistory(Model model, String timeBucketColumnName, int ttl) throws IOException {
-        if (!model.isRecord()) {
-            if (!DownSampling.Minute.equals(model.getDownsampling())) {
-                return;
-            }
-        }
-
-        long deadline = Long.parseLong(DateTime.now().plusDays(-ttl).toString("yyyyMMdd"));
-        //If it's a sharding table drop expired tables
-        if (model.getSqlDBModelExtension().isShardingTable()) {
-            boolean isRuleExecuted = false;
-            Long latestSuccessDeadline = this.tableLatestSuccess.get(model.getName());
-            if (latestSuccessDeadline != null && deadline <= latestSuccessDeadline) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Table = {} already deleted, skip, deadline = {}, ttl = {}", model.getName(), deadline, ttl);
-                }
-                return;
-            }
-            try {
-                //refresh sharding rules
-                isRuleExecuted = ShardingRulesOperator.INSTANCE.createOrUpdateShardingRule(client, model, this.dataSources, ttl);
-                if (isRuleExecuted) {
-                    modelInstaller.createTable(model);
-                }
-            } catch (StorageException e) {
-                throw new IOException(e.getMessage(), e);
-            }
-            List<String> realTables = new ArrayList<>();
-            try (Connection connection = client.getConnection()) {
-                ResultSet resultSet = client.executeQuery(connection, String.format("SHOW SINGLE TABLES LIKE '%s'", model.getName() + "_20%"));
-                while (resultSet.next()) {
-                    realTables.add(resultSet.getString(1));
-                }
-
-                //delete additional tables
-                for (String additionalTable : model.getSqlDBModelExtension().getAdditionalTables().keySet()) {
-                    ResultSet additionalTableRS = client.executeQuery(connection, String.format("SHOW SINGLE TABLES LIKE '%s'", additionalTable + "_20%"));
-                    while (additionalTableRS.next()) {
-                        realTables.add(additionalTableRS.getString(1));
-                    }
-                }
-            } catch (JDBCClientException | SQLException e) {
-                throw new IOException(e.getMessage(), e);
-            }
-
-            List<String> prepareDeleteTables = new ArrayList<>();
-            for (String table : realTables) {
-                long timeSeries = isolateTimeFromTableName(table);
-                if (deadline >= timeSeries) {
-                    prepareDeleteTables.add(table);
-                }
-            }
-            if (log.isDebugEnabled()) {
-                log.debug("Tables to be dropped: {}", prepareDeleteTables);
-            }
-
-            try (Connection connection = client.getConnection()) {
-                Set<String> dsList = dataSources;
-                for (String prepareDeleteTable : prepareDeleteTables) {
-                    for (String ds : dsList) {
-                        client.execute(connection, getDropSQL(ds, prepareDeleteTable));
-                    }
-                }
-            } catch (JDBCClientException | SQLException e) {
-                throw new IOException(e.getMessage(), e);
-            }
-            this.tableLatestSuccess.put(model.getName(), deadline);
-        } else {
-            //Delete rows as previous
-            super.deleteHistory(model, timeBucketColumnName, ttl);
-        }
-    }
-
-    private long isolateTimeFromTableName(String tableName) {
-        return Long.parseLong(tableName.substring(tableName.lastIndexOf("_") + 1));
-    }
-
-    private String getDropSQL(String dataSource, String table) {
-        String dropSQL = "/* ShardingSphere hint: dataSourceName=" + dataSource + "*/\n" +
-            "drop table if exists " + table;
-
-        return dropSQL;
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingLogQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingLogQueryDAO.java
deleted file mode 100644
index c81ac6541f2e..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingLogQueryDAO.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
-import org.apache.skywalking.oap.server.core.query.enumeration.Order;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.input.TraceScopeCondition;
-import org.apache.skywalking.oap.server.core.query.type.Logs;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCLogQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-
-public class ShardingLogQueryDAO extends JDBCLogQueryDAO {
-
-    public ShardingLogQueryDAO(final JDBCHikariCPClient h2Client,
-                               final ModuleManager manager) {
-        super(h2Client, manager);
-    }
-
-    @Override
-    public Logs queryLogs(String serviceId,
-                          String serviceInstanceId,
-                          String endpointId,
-                          TraceScopeCondition relatedTrace,
-                          Order queryOrder,
-                          int from,
-                          int limit,
-                          final Duration duration,
-                          final List<Tag> tags,
-                          final List<String> keywordsOfContent,
-                          final List<String> excludingKeywordsOfContent) throws IOException {
-        return super.queryLogs(
-            serviceId,
-            serviceInstanceId,
-            endpointId,
-            relatedTrace,
-            queryOrder,
-            from,
-            limit,
-            DurationWithinTTL.INSTANCE.getRecordDurationWithinTTL(duration),
-            tags,
-            keywordsOfContent,
-            excludingKeywordsOfContent
-        );
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingMetricsQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingMetricsQueryDAO.java
deleted file mode 100644
index 96d76719eba5..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingMetricsQueryDAO.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.query.PointOfTime;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.input.MetricsCondition;
-import org.apache.skywalking.oap.server.core.query.type.HeatMap;
-import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
-import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCMetricsQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-
-public class ShardingMetricsQueryDAO extends JDBCMetricsQueryDAO {
-
-    public ShardingMetricsQueryDAO(JDBCHikariCPClient h2Client) {
-        super(h2Client);
-    }
-
-    @Override
-    public long readMetricsValue(final MetricsCondition condition,
-                                 String valueColumnName,
-                                 final Duration duration) throws IOException {
-        return super.readMetricsValue(condition, valueColumnName, DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-
-    @Override
-    public MetricsValues readMetricsValues(final MetricsCondition condition,
-                                           final String valueColumnName,
-                                           final Duration duration) throws IOException {
-
-        MetricsValues result = super.readMetricsValues(condition, valueColumnName,
-                                                       DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-        MetricsValues values = new MetricsValues();
-        values.setValues(Util.sortValues(result.getValues(), getOriginIds(condition, duration),
-                                         ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName())));
-        return values;
-
-    }
-
-    @Override
-    public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condition,
-                                                        final String valueColumnName,
-                                                        final List<String> labels,
-                                                        final Duration duration) throws IOException {
-        List<MetricsValues> result = super.readLabeledMetricsValues(condition, valueColumnName, labels,
-                                                                    DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-
-        return Util.sortValues(result, getOriginIds(condition, duration),
-                               ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName()));
-    }
-
-    @Override
-    public HeatMap readHeatMap(final MetricsCondition condition,
-                               final String valueColumnName,
-                               final Duration duration) throws IOException {
-        HeatMap result = super.readHeatMap(condition, valueColumnName,
-                                           DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-        result.fixMissingColumns(getOriginIds(condition, duration),
-                                 ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName()));
-        return result;
-    }
-
-    @Override
-    protected void buildShardingCondition(StringBuilder sql, List<Object> parameters, String entityId) {
-        sql.append(" and ");
-        sql.append(Metrics.ENTITY_ID + " = ?");
-        parameters.add(entityId);
-    }
-
-    private List<String> getOriginIds(final MetricsCondition condition, final Duration duration) {
-        final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
-        List<String> ids = new ArrayList<>(pointOfTimes.size());
-        final String entityId = condition.getEntity().buildId();
-        pointOfTimes.forEach(pointOfTime -> {
-            ids.add(pointOfTime.id(entityId));
-        });
-
-        return ids;
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingTopologyQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingTopologyQueryDAO.java
deleted file mode 100644
index 40eb704e21b3..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingTopologyQueryDAO.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.type.Call;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCTopologyQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-
-public class ShardingTopologyQueryDAO extends JDBCTopologyQueryDAO {
-
-    public ShardingTopologyQueryDAO(JDBCHikariCPClient h2Client) {
-        super(h2Client);
-    }
-
-    @Override
-    public List<Call.CallDetail> loadServiceRelationsDetectedAtServerSide(Duration duration,
-                                                                          List<String> serviceIds) throws IOException {
-        return super.loadServiceRelationsDetectedAtServerSide(DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration), serviceIds);
-    }
-
-    @Override
-    public List<Call.CallDetail> loadServiceRelationDetectedAtClientSide(Duration duration,
-                                                                         List<String> serviceIds) throws IOException {
-        return super.loadServiceRelationDetectedAtClientSide(DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration), serviceIds);
-    }
-
-    @Override
-    public List<Call.CallDetail> loadServiceRelationsDetectedAtServerSide(Duration duration) throws IOException {
-        return super.loadServiceRelationsDetectedAtServerSide(DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-
-    @Override
-    public List<Call.CallDetail> loadServiceRelationDetectedAtClientSide(Duration duration) throws IOException {
-        return super.loadServiceRelationDetectedAtClientSide(DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-
-    @Override
-    public List<Call.CallDetail> loadInstanceRelationDetectedAtServerSide(String clientServiceId,
-                                                                          String serverServiceId,
-                                                                          Duration duration) throws IOException {
-        return super.loadInstanceRelationDetectedAtServerSide(clientServiceId, serverServiceId,
-                                                              DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-
-    @Override
-    public List<Call.CallDetail> loadInstanceRelationDetectedAtClientSide(String clientServiceId,
-                                                                          String serverServiceId,
-                                                                          Duration duration) throws IOException {
-        return super.loadInstanceRelationDetectedAtClientSide(clientServiceId, serverServiceId,
-                                                              DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-
-    @Override
-    public List<Call.CallDetail> loadEndpointRelation(Duration duration,
-                                                      String destEndpointId) throws IOException {
-        return super.loadEndpointRelation(DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration),
-                                          destEndpointId);
-    }
-
-    @Override
-    public List<Call.CallDetail> loadProcessRelationDetectedAtClientSide(String serviceInstanceId, Duration duration) throws IOException {
-        return super.loadProcessRelationDetectedAtClientSide(serviceInstanceId,
-                                                             DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-
-    @Override
-    public List<Call.CallDetail> loadProcessRelationDetectedAtServerSide(String serviceInstanceId, Duration duration) throws IOException {
-        return super.loadProcessRelationDetectedAtServerSide(serviceInstanceId,
-                                                             DurationWithinTTL.INSTANCE.getMetricDurationWithinTTL(duration));
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingTraceQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingTraceQueryDAO.java
deleted file mode 100644
index 6385bf049e7b..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingTraceQueryDAO.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.type.QueryOrder;
-import org.apache.skywalking.oap.server.core.query.type.TraceBrief;
-import org.apache.skywalking.oap.server.core.query.type.TraceState;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCTraceQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-
-public class ShardingTraceQueryDAO extends JDBCTraceQueryDAO {
-
-    public ShardingTraceQueryDAO(ModuleManager manager,
-                                 JDBCHikariCPClient h2Client) {
-        super(manager, h2Client);
-    }
-
-    @Override
-    public TraceBrief queryBasicTraces(Duration duration,
-                                       long minDuration,
-                                       long maxDuration,
-                                       String serviceId,
-                                       String serviceInstanceId,
-                                       String endpointId,
-                                       String traceId,
-                                       int limit,
-                                       int from,
-                                       TraceState traceState,
-                                       QueryOrder queryOrder,
-                                       final List<Tag> tags) throws IOException {
-        return super.queryBasicTraces(
-            DurationWithinTTL.INSTANCE.getRecordDurationWithinTTL(duration),
-            minDuration,
-            maxDuration,
-            serviceId,
-            serviceInstanceId,
-            endpointId,
-            traceId,
-            limit,
-            from,
-            traceState,
-            queryOrder,
-            tags
-        );
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingZipkinQueryDAO.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingZipkinQueryDAO.java
deleted file mode 100644
index 59a6bc10104c..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/dao/ShardingZipkinQueryDAO.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao;
-
-import java.io.IOException;
-import java.util.List;
-import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.zipkin.ZipkinSpanRecord;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCZipkinQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-import zipkin2.Span;
-import zipkin2.storage.QueryRequest;
-
-public class ShardingZipkinQueryDAO extends JDBCZipkinQueryDAO {
-    public ShardingZipkinQueryDAO(final JDBCHikariCPClient h2Client) {
-        super(h2Client);
-    }
-
-    @Override
-    public List<List<Span>> getTraces(final QueryRequest request, Duration duration) throws IOException {
-        return super.getTraces(request,
-                               DurationWithinTTL.INSTANCE.getRecordDurationWithinTTL(duration));
-    }
-
-    @Override
-    protected void buildShardingCondition(StringBuilder sql, List<Object> parameters, long startTimeMillis, long endTimeMillis) {
-        sql.append(" and ");
-        sql.append(ZipkinSpanRecord.INDEX_NAME).append(".").append(ZipkinSpanRecord.TIME_BUCKET + " >= ?");
-        parameters.add(TimeBucket.getRecordTimeBucket(startTimeMillis));
-
-        sql.append(" and ");
-        sql.append(ZipkinSpanRecord.INDEX_NAME).append(".").append(ZipkinSpanRecord.TIME_BUCKET + " <= ?");
-        parameters.add(TimeBucket.getRecordTimeBucket(endTimeMillis));
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/mysql/MySQLShardingStorageProvider.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/mysql/MySQLShardingStorageProvider.java
deleted file mode 100644
index 6ec2be64b8f0..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/mysql/MySQLShardingStorageProvider.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.mysql;
-
-import java.io.IOException;
-import java.sql.SQLException;
-import org.apache.skywalking.oap.server.core.CoreModule;
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.storage.IHistoryDeleteDAO;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
-import org.apache.skywalking.oap.server.core.storage.model.ModelInstaller;
-import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.ITopologyQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.ITraceQueryDAO;
-import org.apache.skywalking.oap.server.core.storage.query.IZipkinQueryDAO;
-import org.apache.skywalking.oap.server.library.module.ModuleStartException;
-import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCStorageConfig;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.mysql.MySQLStorageProvider;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.mysql.MySQLTableInstaller;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.DurationWithinTTL;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.ShardingRulesOperator;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.ShardingSphereTableInstaller;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingAggregationQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingBrowserLogQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingHistoryDeleteDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingLogQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingMetricsQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingTopologyQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingTraceQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingZipkinQueryDAO;
-
-public class MySQLShardingStorageProvider extends MySQLStorageProvider {
-    @Override
-    public String name() {
-        return "mysql-sharding";
-    }
-
-    @Override
-    protected ModelInstaller createModelInstaller() {
-        return new ShardingSphereTableInstaller(
-            jdbcClient,
-            getManager(),
-            ((MySQLShardingStorageConfig) config).getDataSources(),
-            new MySQLTableInstaller(jdbcClient, getManager()));
-    }
-
-    @Override
-    public ConfigCreator<? extends JDBCStorageConfig> newConfigCreator() {
-        return new ConfigCreator<MySQLShardingStorageConfig>() {
-            @Override
-            public Class<MySQLShardingStorageConfig> type() {
-                return MySQLShardingStorageConfig.class;
-            }
-
-            @Override
-            public void onInitialized(final MySQLShardingStorageConfig initialized) {
-                config = initialized;
-            }
-        };
-    }
-
-    @Override
-    public void prepare() throws ServiceNotProvidedException, ModuleStartException {
-        super.prepare();
-
-        // Override service implementations.
-
-        this.registerServiceImplementation(
-            ITopologyQueryDAO.class,
-            new ShardingTopologyQueryDAO(jdbcClient));
-        this.registerServiceImplementation(
-            IMetricsQueryDAO.class,
-            new ShardingMetricsQueryDAO(jdbcClient));
-        this.registerServiceImplementation(
-            ITraceQueryDAO.class,
-            new ShardingTraceQueryDAO(getManager(), jdbcClient));
-        this.registerServiceImplementation(
-            IBrowserLogQueryDAO.class,
-            new ShardingBrowserLogQueryDAO(jdbcClient));
-        this.registerServiceImplementation(
-            IAggregationQueryDAO.class,
-            new ShardingAggregationQueryDAO(jdbcClient));
-        this.registerServiceImplementation(
-            ILogQueryDAO.class,
-            new ShardingLogQueryDAO(jdbcClient, getManager()));
-
-        this.registerServiceImplementation(
-            IHistoryDeleteDAO.class,
-            new ShardingHistoryDeleteDAO(
-                jdbcClient,
-                ((MySQLShardingStorageConfig) config).getDataSources(),
-                getManager(),
-                modelInstaller));
-
-        this.registerServiceImplementation(
-            IZipkinQueryDAO.class,
-            new ShardingZipkinQueryDAO(jdbcClient));
-    }
-
-    @Override
-    public void start() throws ServiceNotProvidedException, ModuleStartException {
-        try {
-            super.start();
-
-            ShardingRulesOperator.INSTANCE.start(jdbcClient);
-
-            DurationWithinTTL.INSTANCE.setConfigService(
-                getManager()
-                    .find(CoreModule.NAME)
-                    .provider()
-                    .getService(ConfigService.class));
-        } catch (StorageException | SQLException | IOException e) {
-            throw new ModuleStartException(e.getMessage(), e);
-        }
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
deleted file mode 100644
index ed25244c2dd5..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# 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.
-#
-#
-
-org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.mysql.MySQLShardingStorageProvider
diff --git a/oap-server/server-storage-plugin/storage-tidb-plugin/pom.xml b/oap-server/server-storage-plugin/storage-tidb-plugin/pom.xml
deleted file mode 100644
index 6c6bdda40f22..000000000000
--- a/oap-server/server-storage-plugin/storage-tidb-plugin/pom.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  ~
-  -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>server-storage-plugin</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.5.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>storage-tidb-plugin</artifactId>
-    <packaging>jar</packaging>
-
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>server-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>library-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.skywalking</groupId>
-            <artifactId>storage-jdbc-hikaricp-plugin</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-</project>
\ No newline at end of file
diff --git a/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/tidb/TiDBStorageProvider.java b/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/tidb/TiDBStorageProvider.java
deleted file mode 100644
index ef863a786616..000000000000
--- a/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/tidb/TiDBStorageProvider.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.tidb;
-
-import org.apache.skywalking.oap.server.core.storage.IHistoryDeleteDAO;
-import org.apache.skywalking.oap.server.core.storage.model.ModelInstaller;
-import org.apache.skywalking.oap.server.library.module.ModuleStartException;
-import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCStorageProvider;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.mysql.MySQLTableInstaller;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.tidb.dao.TiDBHistoryDeleteDAO;
-
-/**
- * TiDB storage enhanced and came from MySQLStorageProvider to support TiDB.
- *
- * caution: need add "useAffectedRows=true" to jdbc url.
- */
-public class TiDBStorageProvider extends JDBCStorageProvider {
-    @Override
-    public String name() {
-        return "tidb";
-    }
-
-    @Override
-    protected ModelInstaller createModelInstaller() {
-        return new MySQLTableInstaller(jdbcClient, getManager());
-    }
-
-    @Override
-    public void prepare() throws ServiceNotProvidedException, ModuleStartException {
-        super.prepare();
-
-        // Override service implementations
-
-        this.registerServiceImplementation(
-            IHistoryDeleteDAO.class,
-            new TiDBHistoryDeleteDAO(jdbcClient));
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/tidb/dao/TiDBHistoryDeleteDAO.java b/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/tidb/dao/TiDBHistoryDeleteDAO.java
deleted file mode 100644
index c40b93a82a4f..000000000000
--- a/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/tidb/dao/TiDBHistoryDeleteDAO.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.tidb.dao;
-
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
-import org.apache.skywalking.oap.server.core.storage.IHistoryDeleteDAO;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
-import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
-import org.joda.time.DateTime;
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-public class TiDBHistoryDeleteDAO implements IHistoryDeleteDAO {
-    private final JDBCHikariCPClient client;
-
-    @Override
-    public void deleteHistory(Model model, String timeBucketColumnName, int ttl) throws IOException {
-        SQLBuilder dataDeleteSQL = new SQLBuilder("delete from " + model.getName() + " where ")
-            .append(timeBucketColumnName).append("<= ? ")
-            .append(" and ")
-            .append(timeBucketColumnName).append(">= ? ")
-            .append(" limit 10000");
-
-        try (Connection connection = client.getConnection()) {
-            long deadline;
-            long minTime;
-            if (model.isRecord()) {
-                deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMddHHmmss"));
-                minTime = 1000_00_00_00_00_00L;
-            } else {
-                switch (model.getDownsampling()) {
-                    case Minute:
-                        deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMddHHmm"));
-                        minTime = 1000_00_00_00_00L;
-                        break;
-                    case Hour:
-                        deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMddHH"));
-                        minTime = 1000_00_00_00L;
-                        break;
-                    case Day:
-                        deadline = Long.parseLong(new DateTime().plusDays(-ttl).toString("yyyyMMdd"));
-                        minTime = 1000_00_00L;
-                        break;
-                    default:
-                        return;
-                }
-            }
-            while (client.executeUpdate(connection, dataDeleteSQL.toString(), deadline, minTime) > 0) {
-            }
-            //delete additional tables
-            for (SQLDatabaseModelExtension.AdditionalTable additionalTable : model.getSqlDBModelExtension()
-                                                                                  .getAdditionalTables()
-                                                                                  .values()) {
-                SQLBuilder additionalTableDeleteSQL = new SQLBuilder("delete from " + additionalTable.getName() + " where ")
-                    .append(timeBucketColumnName).append("<= ? ")
-                    .append(" and ")
-                    .append(timeBucketColumnName).append(">= ? ")
-                    .append(" limit 10000");
-                while (client.executeUpdate(connection, additionalTableDeleteSQL.toString(), deadline, minTime) > 0) {
-                }
-            }
-        } catch (JDBCClientException | SQLException e) {
-            throw new IOException(e.getMessage(), e);
-        }
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
deleted file mode 100644
index cfe7e5f9f81f..000000000000
--- a/oap-server/server-storage-plugin/storage-tidb-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# 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.
-#
-#
-
-org.apache.skywalking.oap.server.storage.plugin.jdbc.tidb.TiDBStorageProvider
\ No newline at end of file
diff --git a/oap-server/server-tools/data-generator/src/main/resources/application.yml b/oap-server/server-tools/data-generator/src/main/resources/application.yml
index 3dd61fd7267d..dc5f1d35021a 100755
--- a/oap-server/server-tools/data-generator/src/main/resources/application.yml
+++ b/oap-server/server-tools/data-generator/src/main/resources/application.yml
@@ -114,7 +114,7 @@ storage:
     advanced: ${SW_STORAGE_ES_ADVANCED:""}
   h2:
     properties:
-      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1}
+      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE}
       dataSource.user: ${SW_STORAGE_H2_USER:sa}
     metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
     maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}
diff --git a/tools/profile-exporter/application.yml b/tools/profile-exporter/application.yml
index 43c9b1ef359d..f03d319dd7f0 100644
--- a/tools/profile-exporter/application.yml
+++ b/tools/profile-exporter/application.yml
@@ -40,12 +40,12 @@ storage:
     advanced: ${SW_STORAGE_ES_ADVANCED:""}
   h2:
     properties:
-      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1}
+      jdbcUrl: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE}
       dataSource.user: ${SW_STORAGE_H2_USER:sa}
     metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
   mysql:
     properties:
-      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest"}
+      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest?allowMultiQueries=true"}
       dataSource.user: ${SW_DATA_SOURCE_USER:root}
       dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root@1234}
       dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}


Test patch:
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/model/StorageModelsTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/model/StorageModelsTest.java
index 143638b057c6..fa4c055aaa3e 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/model/StorageModelsTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/model/StorageModelsTest.java
@@ -65,8 +65,7 @@ public static void tearDown() {
     public void testStorageModels() throws StorageException {
         StorageModels models = new StorageModels();
         models.add(TestModel.class, -1,
-                   new Storage("StorageModelsTest", false, DownSampling.Hour),
-                   false
+                   new Storage("StorageModelsTest", false, DownSampling.Hour)
         );
 
         final List<Model> allModules = models.allModels();
@@ -91,12 +90,12 @@ private static class TestModel {
         private String column;
 
         @Column(name = "column1")
-        @SQLDatabase.QueryUnifiedIndex(withColumns = {"column2"})
+        @SQLDatabase.CompositeIndex(withColumns = {"column2"})
         private String column1;
 
         @Column(name = "column2")
-        @SQLDatabase.QueryUnifiedIndex(withColumns = {"column1"})
-        @SQLDatabase.QueryUnifiedIndex(withColumns = {"column"})
+        @SQLDatabase.CompositeIndex(withColumns = {"column1"})
+        @SQLDatabase.CompositeIndex(withColumns = {"column"})
         private String column2;
 
         @Column(name = "column", storageOnly = true)
diff --git a/oap-server/server-starter/src/test/java/org/apache/skywalking/oap/server/starter/config/ApplicationConfigLoaderTestCase.java b/oap-server/server-starter/src/test/java/org/apache/skywalking/oap/server/starter/config/ApplicationConfigLoaderTestCase.java
index a540090b85b7..a381363f9f52 100644
--- a/oap-server/server-starter/src/test/java/org/apache/skywalking/oap/server/starter/config/ApplicationConfigLoaderTestCase.java
+++ b/oap-server/server-starter/src/test/java/org/apache/skywalking/oap/server/starter/config/ApplicationConfigLoaderTestCase.java
@@ -47,7 +47,7 @@ public void testLoadConfig() {
         assertThat(providerConfig.get("metadataQueryMaxSize")).isEqualTo(5000);
         assertThat(providerConfig.get("properties")).isInstanceOf(Properties.class);
         Properties properties = (Properties) providerConfig.get("properties");
-        assertThat(properties.get("jdbcUrl")).isEqualTo("jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true");
+        assertThat(properties.get("jdbcUrl")).isEqualTo("jdbc:mysql://localhost:3306/swtest?rewriteBatchedStatements=true&allowMultiQueries=true");
     }
 
     @Test
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/TimeSeriesUtilsTest.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/TimeSeriesUtilsTest.java
index 97607715f10f..931edd66152b 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/TimeSeriesUtilsTest.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/TimeSeriesUtilsTest.java
@@ -43,15 +43,15 @@ public class TimeSeriesUtilsTest {
     @BeforeEach
     public void prepare() {
         superDatasetModel = new Model("superDatasetModel", Lists.newArrayList(),
-                                      0, DownSampling.Second, true, true, Record.class, true,
+                                      0, DownSampling.Second, true, Record.class, true,
                                       new SQLDatabaseModelExtension(), new BanyanDBModelExtension(), new ElasticSearchModelExtension()
         );
         normalRecordModel = new Model("normalRecordModel", Lists.newArrayList(),
-                                      0, DownSampling.Second, true, false, Record.class, true,
+                                      0, DownSampling.Second, false, Record.class, true,
                                       new SQLDatabaseModelExtension(), new BanyanDBModelExtension(), new ElasticSearchModelExtension()
         );
         normalMetricsModel = new Model("normalMetricsModel", Lists.newArrayList(),
-                                       0, DownSampling.Minute, false, false, Metrics.class, true,
+                                       0, DownSampling.Minute, false, Metrics.class, true,
                                        new SQLDatabaseModelExtension(), new BanyanDBModelExtension(), new ElasticSearchModelExtension()
         );
         TimeSeriesUtils.setSUPER_DATASET_DAY_STEP(1);
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAOIT.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAOIT.java
new file mode 100644
index 000000000000..0199c9acea04
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCHistoryDeleteDAOIT.java
@@ -0,0 +1,143 @@
+/*
+ * 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.skywalking.oap.server.storage.plugin.jdbc.common.dao;
+
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.CoreModuleProvider;
+import org.apache.skywalking.oap.server.core.analysis.DownSampling;
+import org.apache.skywalking.oap.server.core.analysis.manual.service.ServiceTraffic;
+import org.apache.skywalking.oap.server.core.config.ConfigService;
+import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+import org.apache.skywalking.oap.server.core.storage.model.BanyanDBModelExtension;
+import org.apache.skywalking.oap.server.core.storage.model.ColumnName;
+import org.apache.skywalking.oap.server.core.storage.model.ElasticSearchModelExtension;
+import org.apache.skywalking.oap.server.core.storage.model.Model;
+import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
+import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseExtension;
+import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.module.ModuleProviderHolder;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.sql.SQLException;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.util.Arrays;
+import java.util.Properties;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@Testcontainers
+@ExtendWith(MockitoExtension.class)
+class JDBCHistoryDeleteDAOIT {
+    @Container
+    private final PostgreSQLContainer<?> psqlContainer = new PostgreSQLContainer<>("postgres:13")
+        .withDatabaseName("skywalking")
+        .withUsername("postgres")
+        .withPassword("123456");
+
+    private JDBCClient jdbcClient;
+
+    @Mock
+    private ModuleManager moduleManager;
+    private Model model;
+    private TableHelper tableHelper;
+    private JDBCTableInstaller tableInstaller;
+
+    @BeforeEach
+    void setup() {
+        final var properties = new Properties();
+        properties.setProperty("jdbcUrl", psqlContainer.getJdbcUrl());
+        properties.setProperty("dataSource.user", psqlContainer.getUsername());
+        properties.setProperty("dataSource.password", psqlContainer.getPassword());
+
+        jdbcClient = new JDBCClient(properties);
+        jdbcClient.connect();
+
+        tableHelper = new TableHelper(moduleManager, jdbcClient);
+        tableInstaller = new JDBCTableInstaller(jdbcClient, moduleManager);
+
+        final var providerHolder = mock(ModuleProviderHolder.class);
+        final var coreModule = mock(CoreModuleProvider.class);
+        final var configService = mock(ConfigService.class);
+        when(moduleManager.find(CoreModule.NAME)).thenReturn(providerHolder);
+        when(providerHolder.provider()).thenReturn(coreModule);
+        when(coreModule.getService(ConfigService.class)).thenReturn(configService);
+        when(configService.getMetricsDataTTL()).thenReturn(3);
+
+        final var serviceTrafficNameColumn = mock(Column.class);
+        when(serviceTrafficNameColumn.name()).thenReturn("service_traffic_name");
+        final var timeBucketColumn = mock(Column.class);
+        when(timeBucketColumn.name()).thenReturn("time_bucket");
+
+        model = new Model(
+            "service_traffic",
+            Arrays.asList(
+                new ModelColumn(new ColumnName(serviceTrafficNameColumn), String.class, String.class, false, false, false, 100,
+                    new SQLDatabaseExtension(), null, null),
+                new ModelColumn(new ColumnName(timeBucketColumn), Long.class, Long.class, false, false, false, 0,
+                    new SQLDatabaseExtension(), null, null)
+            ), 1, DownSampling.Minute, false, ServiceTraffic.class, false, new SQLDatabaseModelExtension(),
+            new BanyanDBModelExtension(), new ElasticSearchModelExtension());
+
+        TableMetaInfo.addModel(model);
+    }
+
+    @Test
+    void test() throws SQLException {
+        // Table install should create the table.
+        var clock = Clock.fixed(Instant.parse("2023-03-17T10:00:00Z"), ZoneId.systemDefault());
+        tableInstaller.createTable(model, "service_traffic_20230317");
+
+        var jdbcHistoryDeleteDAO = new JDBCHistoryDeleteDAO(jdbcClient, tableHelper, tableInstaller, clock);
+        jdbcHistoryDeleteDAO.deleteHistory(model, "time_bucket", 3);
+        try (final var conn = jdbcClient.getConnection();
+             final var rs = conn.getMetaData().getTables(null, null, "service_traffic_20230317", null)) {
+            assertThat(rs.next()).isTrue();
+        }
+
+        // HistoryDeleteDAO should delete the table out of TTL.
+        clock = Clock.fixed(Instant.parse("2023-03-21T10:00:00Z"), ZoneId.systemDefault());
+        jdbcHistoryDeleteDAO = new JDBCHistoryDeleteDAO(jdbcClient, tableHelper, tableInstaller, clock);
+        jdbcHistoryDeleteDAO.deleteHistory(model, "time_bucket", 3);
+        try (final var conn = jdbcClient.getConnection();
+             final var rs = conn.getMetaData().getTables(null, null, "service_traffic_20230317", null)) {
+            assertThat(rs.next()).isFalse();
+        }
+        // ... and should create the new table
+        try (final var conn = jdbcClient.getConnection();
+             final var rs = conn.getMetaData().getTables(null, null, "service_traffic_20230322", null)) {
+            assertThat(rs.next()).isTrue();
+        }
+    }
+}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/DurationWithinTTLTest.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/DurationWithinTTLTest.java
deleted file mode 100644
index a583b36f75eb..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/DurationWithinTTLTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.query.enumeration.Step;
-import org.joda.time.DateTime;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DurationWithinTTLTest {
-    private final int recordDataTTL = 3;
-
-    @BeforeEach
-    public void init() {
-        ConfigService configService = mock(ConfigService.class);
-        when(configService.getRecordDataTTL()).thenReturn(recordDataTTL);
-        DurationWithinTTL.INSTANCE.setConfigService(configService);
-    }
-
-    @Test
-    public void testGetTrimmedRecordStartTime() {
-        String expectedDay = new DateTime().toString("yyyy-MM-dd");
-        String inputDay = new DateTime().toString("yyyy-MM-dd");
-        Assertions.assertEquals(expectedDay, DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.DAY, inputDay));
-        String expectedDayOutTTL = new DateTime().plusDays(1 - recordDataTTL).toString("yyyy-MM-dd");
-        String inputDayOutTTL = new DateTime().plusDays(-recordDataTTL).toString("yyyy-MM-dd");
-        Assertions.assertEquals(
-            expectedDayOutTTL, DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.DAY, inputDayOutTTL));
-
-        String expectedHour = new DateTime().toString("yyyy-MM-dd HH");
-        String inputHour = new DateTime().toString("yyyy-MM-dd HH");
-        Assertions.assertEquals(expectedHour, DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.HOUR, inputHour));
-        String inputHourOutTTL = new DateTime().plusDays(-recordDataTTL).toString("yyyy-MM-dd HH");
-        Assertions.assertEquals(
-            expectedDayOutTTL + " 00",
-            DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.HOUR, inputHourOutTTL)
-        );
-
-        String expectedMin = new DateTime().toString("yyyy-MM-dd HHmm");
-        String inputMin = new DateTime().toString("yyyy-MM-dd HHmm");
-        Assertions.assertEquals(expectedMin, DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.MINUTE, inputMin));
-        String inputMinOutTTL = new DateTime().plusDays(-recordDataTTL).toString("yyyy-MM-dd HHmm");
-        Assertions.assertEquals(
-            expectedDayOutTTL + " 0000",
-            DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.MINUTE, inputMinOutTTL)
-        );
-
-        String inputSec = new DateTime().toString("yyyy-MM-dd HHmmss");
-        String expectedSec = new DateTime().toString("yyyy-MM-dd HHmmss");
-        Assertions.assertEquals(expectedSec, DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.SECOND, inputSec));
-        String inputSecOutTTL = new DateTime().plusDays(-recordDataTTL).toString("yyyy-MM-dd HHmmss");
-        Assertions.assertEquals(
-            expectedDayOutTTL + " 000000",
-            DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.SECOND, inputSecOutTTL)
-        );
-        try {
-            DurationWithinTTL.INSTANCE.getTrimmedRecordStartTime(Step.HOUR, "2022-09-08 30");
-            Assertions.fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            Assertions.assertTrue(true);
-        }
-    }
-
-    @Test
-    public void testGetTrimmedMetricEndTime() {
-        String expectedDay = new DateTime().toString("yyyy-MM-dd");
-        String inputDay = new DateTime().toString("yyyy-MM-dd");
-        Assertions.assertEquals(expectedDay, DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.DAY, inputDay));
-        String expectedDayOutTTL = new DateTime().toString("yyyy-MM-dd");
-        String inputDayOutTTL = new DateTime().plusDays(1).toString("yyyy-MM-dd");
-        Assertions.assertEquals(
-            expectedDayOutTTL, DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.DAY, inputDayOutTTL));
-
-        String expectedHour = new DateTime().toString("yyyy-MM-dd HH");
-        String inputHour = new DateTime().toString("yyyy-MM-dd HH");
-        Assertions.assertEquals(expectedHour, DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.HOUR, inputHour));
-        String inputHourOutTTL = new DateTime().plusDays(1).toString("yyyy-MM-dd HH");
-        Assertions.assertEquals(
-            expectedDayOutTTL + " 23",
-            DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.HOUR, inputHourOutTTL)
-        );
-
-        String expectedMin = new DateTime().toString("yyyy-MM-dd HHmm");
-        String inputMin = new DateTime().toString("yyyy-MM-dd HHmm");
-        Assertions.assertEquals(expectedMin, DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.MINUTE, inputMin));
-        String inputMinOutTTL = new DateTime().plusDays(1).toString("yyyy-MM-dd HHmm");
-        Assertions.assertEquals(
-            expectedDayOutTTL + " 2359",
-            DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.MINUTE, inputMinOutTTL)
-        );
-
-        String inputSec = new DateTime().toString("yyyy-MM-dd HHmmss");
-        String expectedSec = new DateTime().toString("yyyy-MM-dd HHmmss");
-        Assertions.assertEquals(expectedSec, DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.SECOND, inputSec));
-        String inputSecOutTTL = new DateTime().plusDays(1).toString("yyyy-MM-dd HHmmss");
-        Assertions.assertEquals(
-            expectedDayOutTTL + " 235959",
-            DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.SECOND, inputSecOutTTL)
-        );
-        try {
-            DurationWithinTTL.INSTANCE.getTrimmedMetricEndTime(Step.HOUR, "2022-09-08 30");
-            Assertions.fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-            Assertions.assertTrue(true);
-        }
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ServiceCpmMetrics.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ServiceCpmMetrics.java
deleted file mode 100644
index b958197fc749..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ServiceCpmMetrics.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
-import org.apache.skywalking.oap.server.core.analysis.Stream;
-import org.apache.skywalking.oap.server.core.analysis.metrics.CPMMetrics;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
-import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
-import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.StorageID;
-import org.apache.skywalking.oap.server.core.storage.annotation.Column;
-
-@Stream(
-    name = ServiceCpmMetrics.INDEX_NAME,
-    scopeId = DefaultScopeDefine.SERVICE,
-    builder = ServiceCpmMetricsBuilder.class,
-    processor = MetricsStreamProcessor.class
-)
-@EqualsAndHashCode(of = {
-    "entityId"
-}, callSuper = true)
-public class ServiceCpmMetrics extends CPMMetrics {
-    public static final String INDEX_NAME = "service_cpm";
-
-    @Setter
-    @Getter
-    @Column(
-        name = "entity_id",
-        length = 512
-    )
-    private String entityId;
-
-    @Override
-    protected StorageID id0() {
-        return new StorageID()
-            .append(TIME_BUCKET, getTimeBucket())
-            .append(ENTITY_ID, entityId);
-    }
-
-    @Override
-    public int remoteHashCode() {
-        byte var1 = 17;
-        int var2 = 31 * var1 + this.entityId.hashCode();
-        return var2;
-    }
-
-    @Override
-    public RemoteData.Builder serialize() {
-        RemoteData.Builder var1 = RemoteData.newBuilder();
-        var1.addDataStrings(this.getEntityId());
-        var1.addDataLongs(this.getValue());
-        var1.addDataLongs(this.getTotal());
-        var1.addDataLongs(this.getTimeBucket());
-        return var1;
-    }
-
-    @Override
-    public void deserialize(RemoteData var1) {
-        this.setEntityId(var1.getDataStrings(0));
-        this.setValue(var1.getDataLongs(0));
-        this.setTotal(var1.getDataLongs(1));
-        this.setTimeBucket(var1.getDataLongs(2));
-    }
-
-    @Override
-    public Metrics toHour() {
-        ServiceCpmMetrics var1 = new ServiceCpmMetrics();
-        var1.setEntityId(this.getEntityId());
-        var1.setValue(this.getValue());
-        var1.setTotal(this.getTotal());
-        var1.setTimeBucket(this.toTimeBucketInHour());
-        return var1;
-    }
-
-    @Override
-    public Metrics toDay() {
-        ServiceCpmMetrics var1 = new ServiceCpmMetrics();
-        var1.setEntityId(this.getEntityId());
-        var1.setValue(this.getValue());
-        var1.setTotal(this.getTotal());
-        var1.setTimeBucket(this.toTimeBucketInDay());
-        return var1;
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ServiceCpmMetricsBuilder.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ServiceCpmMetricsBuilder.java
deleted file mode 100644
index 9269eb782205..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ServiceCpmMetricsBuilder.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import org.apache.skywalking.oap.server.core.storage.StorageData;
-import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity;
-import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
-import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
-
-public class ServiceCpmMetricsBuilder implements StorageBuilder {
-    public ServiceCpmMetricsBuilder() {
-    }
-
-    public void entity2Storage(StorageData var1, Convert2Storage var2) {
-        ServiceCpmMetrics var3 = (ServiceCpmMetrics) var1;
-        var2.accept("entity_id", var3.getEntityId());
-        var2.accept("value", new Long(var3.getValue()));
-        var2.accept("total", new Long(var3.getTotal()));
-        var2.accept("time_bucket", new Long(var3.getTimeBucket()));
-    }
-
-    public StorageData storage2Entity(Convert2Entity var1) {
-        ServiceCpmMetrics var2 = new ServiceCpmMetrics();
-        var2.setEntityId((String) var1.get("entity_id"));
-        var2.setValue(((Number) var1.get("value")).longValue());
-        var2.setTotal(((Number) var1.get("total")).longValue());
-        var2.setTimeBucket(((Number) var1.get("time_bucket")).longValue());
-        return var2;
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRulesTest.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRulesTest.java
deleted file mode 100644
index aac77e148e60..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingRulesTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import org.apache.skywalking.oap.server.core.storage.ShardingAlgorithm;
-import org.joda.time.DateTime;
-import org.joda.time.format.DateTimeFormat;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.powermock.reflect.Whitebox;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-public class ShardingRulesTest {
-    private DateTime currentDate;
-
-    @BeforeEach
-    public void init() {
-        currentDate = DateTimeFormat.forPattern("yyyyMMdd").parseDateTime("20220919");
-    }
-
-    @Test
-    public void buildTimeRangeShardingRuleTest() throws Exception {
-        ShardingRulesOperator rulesOperator = ShardingRulesOperator.INSTANCE;
-        ShardingRule.ShardingRuleBuilder builder = ShardingRule.builder();
-        builder.table("Test_table");
-        builder.operation("CREATE");
-        Whitebox.invokeMethod(rulesOperator, "buildShardingRule",
-                              builder,
-                              "Test_table",
-                              new HashSet<>(Arrays.asList("ds_0", "ds_1")),
-                              ShardingAlgorithm.TIME_SEC_RANGE_SHARDING_ALGORITHM,
-                              "time_bucket",
-                              "service_id",
-                              3,
-                              currentDate);
-        String rule = builder.build().toShardingRuleSQL();
-        String expectedRule = "CREATE SHARDING TABLE RULE Test_table(" + System.lineSeparator() +
-            "DATANODES(\"ds_1.Test_table_20220917\",\"ds_1.Test_table_20220918\",\"ds_1.Test_table_20220919\",\"ds_1.Test_table_20220920\",\"ds_0.Test_table_20220917\",\"ds_0.Test_table_20220918\",\"ds_0.Test_table_20220919\",\"ds_0.Test_table_20220920\")," + System.lineSeparator() +
-            "DATABASE_STRATEGY(TYPE=\"standard\"," + System.lineSeparator() +
-            "SHARDING_COLUMN=service_id," + System.lineSeparator() +
-            "SHARDING_ALGORITHM(TYPE(NAME=\"inline\"," + System.lineSeparator() +
-            "PROPERTIES(\"algorithm-expression\"=\"ds_${service_id.hashCode()&Integer.MAX_VALUE%2}\"))))," + System.lineSeparator() +
-            "TABLE_STRATEGY(TYPE=\"standard\"," + System.lineSeparator() +
-            "SHARDING_COLUMN=time_bucket," + System.lineSeparator() +
-            "SHARDING_ALGORITHM(TYPE(NAME=\"interval\"," + System.lineSeparator() +
-            "PROPERTIES(\"datetime-pattern\"=\"yyyyMMddHHmmss\",\"datetime-interval-unit\"=\"days\",\"datetime-interval-amount\"=\"1\",\"sharding-suffix-pattern\"=\"yyyyMMdd\",\"datetime-lower\"=\"20220101000000\",\"datetime-upper\"=\"20991201000000\")))))";
-        Assertions.assertEquals(expectedRule, rule);
-    }
-
-    @Test
-    public void buildTimeRelativeIDShardingRuleTest() throws Exception {
-        ShardingRulesOperator rulesOperator = ShardingRulesOperator.INSTANCE;
-        ShardingRule.ShardingRuleBuilder builder = ShardingRule.builder();
-        builder.table("Test_table");
-        builder.operation("CREATE");
-        Whitebox.invokeMethod(rulesOperator, "buildShardingRule",
-                              builder,
-                              "Test_table",
-                              new HashSet<>(Arrays.asList("ds_0", "ds_1")),
-                              ShardingAlgorithm.TIME_RELATIVE_ID_SHARDING_ALGORITHM,
-                              "id",
-                              "entity_id",
-                              3,
-                              currentDate);
-        String rule = builder.build().toShardingRuleSQL();
-        String expectedRule = "CREATE SHARDING TABLE RULE Test_table(" + System.lineSeparator() +
-            "DATANODES(\"ds_1.Test_table_20220917\",\"ds_1.Test_table_20220918\",\"ds_1.Test_table_20220919\",\"ds_1.Test_table_20220920\",\"ds_0.Test_table_20220917\",\"ds_0.Test_table_20220918\",\"ds_0.Test_table_20220919\",\"ds_0.Test_table_20220920\")," + System.lineSeparator() +
-            "DATABASE_STRATEGY(TYPE=\"standard\"," + System.lineSeparator() +
-            "SHARDING_COLUMN=entity_id," + System.lineSeparator() +
-            "SHARDING_ALGORITHM(TYPE(NAME=\"inline\"," + System.lineSeparator() +
-            "PROPERTIES(\"algorithm-expression\"=\"ds_${entity_id.hashCode()&Integer.MAX_VALUE%2}\"))))," + System.lineSeparator() +
-            "TABLE_STRATEGY(TYPE=\"standard\"," + System.lineSeparator() +
-            "SHARDING_COLUMN=id," + System.lineSeparator() +
-            "SHARDING_ALGORITHM(TYPE(NAME=\"inline\"," + System.lineSeparator() +
-            "PROPERTIES(\"allow-range-query-with-inline-sharding\"=\"true\",\"algorithm-expression\"=\"Test_table_${long time_bucket = Long.parseLong(id.substring(0,id.indexOf('_')));" +
-            "if (10000000L < time_bucket && time_bucket < 99999999L) {return time_bucket;};" +
-            "if (1000000000L < time_bucket && time_bucket < 9999999999L) {return time_bucket.intdiv(100);};" +
-            "if (100000000000L < time_bucket && time_bucket < 999999999999L) {return time_bucket.intdiv(100*100);};" +
-            "if (10000000000000L < time_bucket && time_bucket < 99999999999999L) {return time_bucket.intdiv(100*100*100);};" +
-            "}\")))))";
-        Assertions.assertEquals(expectedRule, rule);
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingSphereIT.java b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingSphereIT.java
deleted file mode 100644
index 7b1cc7743bef..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/shardingsphere/ShardingSphereIT.java
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * 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.skywalking.oap.server.storage.plugin.jdbc.shardingsphere;
-
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.server.core.CoreModule;
-import org.apache.skywalking.oap.server.core.analysis.DownSampling;
-import org.apache.skywalking.oap.server.core.analysis.IDManager;
-import org.apache.skywalking.oap.server.core.analysis.Stream;
-import org.apache.skywalking.oap.server.core.analysis.manual.endpoint.EndpointTraffic;
-import org.apache.skywalking.oap.server.core.analysis.manual.relation.service.ServiceRelationClientSideMetrics;
-import org.apache.skywalking.oap.server.core.analysis.manual.relation.service.ServiceRelationServerSideMetrics;
-import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
-import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagAutocompleteData;
-import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagType;
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
-import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.record.Record;
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.query.enumeration.Order;
-import org.apache.skywalking.oap.server.core.query.enumeration.Scope;
-import org.apache.skywalking.oap.server.core.query.enumeration.Step;
-import org.apache.skywalking.oap.server.core.query.input.Duration;
-import org.apache.skywalking.oap.server.core.query.input.Entity;
-import org.apache.skywalking.oap.server.core.query.input.MetricsCondition;
-import org.apache.skywalking.oap.server.core.query.input.TopNCondition;
-import org.apache.skywalking.oap.server.core.query.type.Call;
-import org.apache.skywalking.oap.server.core.query.type.Endpoint;
-import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
-import org.apache.skywalking.oap.server.core.query.type.QueryOrder;
-import org.apache.skywalking.oap.server.core.query.type.SelectedRecord;
-import org.apache.skywalking.oap.server.core.query.type.TraceBrief;
-import org.apache.skywalking.oap.server.core.query.type.TraceState;
-import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
-import org.apache.skywalking.oap.server.core.storage.StorageData;
-import org.apache.skywalking.oap.server.core.storage.StorageException;
-import org.apache.skywalking.oap.server.core.storage.annotation.SQLDatabase;
-import org.apache.skywalking.oap.server.core.storage.annotation.Storage;
-import org.apache.skywalking.oap.server.core.storage.model.Model;
-import org.apache.skywalking.oap.server.core.storage.model.StorageModels;
-import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
-import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.apache.skywalking.oap.server.library.module.ModuleProviderHolder;
-import org.apache.skywalking.oap.server.library.module.ModuleServiceHolder;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCMetadataQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCMetricsDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCRecordDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao.JDBCTagAutoCompleteQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.mysql.MySQLTableInstaller;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingAggregationQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingHistoryDeleteDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingMetricsQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingTopologyQueryDAO;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.shardingsphere.dao.ShardingTraceQueryDAO;
-import org.joda.time.DateTime;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.mockito.MockedStatic;
-import org.powermock.reflect.Whitebox;
-import org.testcontainers.containers.DockerComposeContainer;
-import org.testcontainers.containers.wait.strategy.Wait;
-
-import java.io.File;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
-
-@Slf4j
-@org.junit.jupiter.api.Tag("slow")
-public class ShardingSphereIT {
-    private static MockedStatic<DefaultScopeDefine> DEFAULT_SCOPE_DEFINE_MOCKED_STATIC;
-
-    @BeforeAll
-    public static void setup() {
-        DEFAULT_SCOPE_DEFINE_MOCKED_STATIC = mockStatic(DefaultScopeDefine.class);
-        DEFAULT_SCOPE_DEFINE_MOCKED_STATIC.when(() -> DefaultScopeDefine.nameOf(1)).thenReturn("any");
-    }
-
-    @AfterAll
-    public static void teardown() {
-        DEFAULT_SCOPE_DEFINE_MOCKED_STATIC.close();
-    }
-
-    public static Collection<Object[]> versions() {
-        return Arrays.asList(new Object[][] {
-            {
-                "5.3.1",
-                DataSourceType.MYSQL
-            }
-        });
-    }
-
-    public  DockerComposeContainer<?> environment;
-    private JDBCHikariCPClient ssClient;
-    private JDBCHikariCPClient dsClient0;
-    private JDBCHikariCPClient dsClient1;
-    private final Set<String> dataSources = new HashSet<>(Arrays.asList("ds_0", "ds_1"));
-    private final int ttlTestCreate = 3;
-    private final int ttlTestDrop = 2;
-    private final String searchableTag = "http.method";
-    private final long timeBucketSec = Long.parseLong(DateTime.now().toString("yyyyMMddHHmmss"));
-    private final long timeBucketMin = Long.parseLong(DateTime.now().toString("yyyyMMddHHmm"));
-    private final long timeBucketDay = Long.parseLong(DateTime.now().toString("yyyyMMdd"));
-    private Duration duration;
-    private Entity entityA;
-    private Entity entityB;
-    private String serviceIdA;
-    private String serviceIdB;
-
-    private ModuleManager moduleManager;
-    private MySQLTableInstaller mySQLTableInstaller;
-    private ShardingSphereTableInstaller installer;
-    private DurationWithinTTL durationWithinTTL = DurationWithinTTL.INSTANCE;
-    private final String countQuery = "SELECT COUNT(*) AS rc FROM ";
-
-    public void init(final String version,
-                     final DataSourceType dsType) {
-        if (dsType.equals(DataSourceType.MYSQL)) {
-            startEnv(version, "docker-compose-mysql.yml", 3306);
-            initConnection("mysql", "/swtest?rewriteBatchedStatements=true", 3306, "root", "root@1234");
-        }
-        initTestData();
-    }
-
-    private void startEnv(String version, String dockerComposeName, int dsServicePort) {
-        environment = new DockerComposeContainer<>(new File(ShardingSphereIT.class
-                                                                .getClassLoader()
-                                                                .getResource(dockerComposeName).getPath()))
-            .withExposedService("sharding-proxy", 3307,
-                                Wait.defaultWaitStrategy().withStartupTimeout(java.time.Duration.ofMinutes(20))
-            )
-            .withExposedService("data-source-0", dsServicePort,
-                                Wait.defaultWaitStrategy().withStartupTimeout(java.time.Duration.ofMinutes(20))
-            )
-            .withExposedService("data-source-1", dsServicePort,
-                                Wait.defaultWaitStrategy().withStartupTimeout(java.time.Duration.ofMinutes(20))
-            )
-            .withEnv("SS_VERSION", version);
-        environment.start();
-    }
-
-    private void initConnection(String driverType,
-                                String urlSuffix,
-                                int dsServicePort,
-                                String dsUserName,
-                                String dsPassword) {
-        String ssUrl = "jdbc:" + driverType + "://" +
-            environment.getServiceHost("sharding-proxy", 3307) + ":" +
-            environment.getServicePort("sharding-proxy", 3307) +
-            urlSuffix;
-        Properties properties = new Properties();
-        properties.setProperty("jdbcUrl", ssUrl);
-        properties.setProperty("dataSource.user", "root");
-        properties.setProperty("dataSource.password", "root");
-
-        String dsUrl0 = "jdbc:" + driverType + "://" +
-            environment.getServiceHost("data-source-0", dsServicePort) + ":" +
-            environment.getServicePort("data-source-0", dsServicePort) +
-            urlSuffix;
-        Properties propertiesDs0 = new Properties();
-        propertiesDs0.setProperty("jdbcUrl", dsUrl0);
-        propertiesDs0.setProperty("dataSource.user", dsUserName);
-        propertiesDs0.setProperty("dataSource.password", "root@1234");
-
-        String dsUrl1 = "jdbc:" + driverType + "://" +
-            environment.getServiceHost("data-source-1", dsServicePort) + ":" +
-            environment.getServicePort("data-source-1", dsServicePort) +
-            urlSuffix;
-        Properties propertiesDs1 = new Properties();
-        propertiesDs1.setProperty("jdbcUrl", dsUrl1);
-        propertiesDs1.setProperty("dataSource.user", dsUserName);
-        propertiesDs1.setProperty("dataSource.password", dsPassword);
-
-        ssClient = new JDBCHikariCPClient(properties);
-        dsClient0 = new JDBCHikariCPClient(propertiesDs0);
-        dsClient1 = new JDBCHikariCPClient(propertiesDs1);
-
-        ssClient.connect();
-        dsClient0.connect();
-        dsClient1.connect();
-    }
-
-    private void initTestData() {
-        moduleManager = mock(ModuleManager.class);
-        ConfigService configService = mock(ConfigService.class);
-        Whitebox.setInternalState(moduleManager, "isInPrepareStage", false);
-        when(configService.getMetricsDataTTL()).thenReturn(ttlTestCreate);
-        when(configService.getRecordDataTTL()).thenReturn(ttlTestCreate);
-        when(configService.getSearchableTracesTags()).thenReturn(searchableTag);
-        when(moduleManager.find(anyString())).thenReturn(mock(ModuleProviderHolder.class));
-        when(moduleManager.find(CoreModule.NAME).provider()).thenReturn(mock(ModuleServiceHolder.class));
-        when(moduleManager.find(CoreModule.NAME).provider().getService(ConfigService.class))
-            .thenReturn(configService);
-        mySQLTableInstaller = new MySQLTableInstaller(ssClient, moduleManager);
-        installer = new ShardingSphereTableInstaller(ssClient, moduleManager,
-                                                     dataSources,
-                                                     mySQLTableInstaller
-        );
-
-        durationWithinTTL.setConfigService(configService);
-
-        duration = new Duration();
-        duration.setStart(DateTime.now().minusMinutes(15).toString("yyyy-MM-dd HHmm"));
-        duration.setEnd(DateTime.now().plusMinutes(1).toString("yyyy-MM-dd HHmm"));
-        duration.setStep(Step.MINUTE);
-
-        entityA = new Entity();
-        entityA.setServiceName("Service_A");
-        entityA.setNormal(true);
-        entityA.setScope(Scope.Service);
-
-        entityB = new Entity();
-        entityB.setServiceName("Service_B");
-        entityB.setNormal(true);
-        entityB.setScope(Scope.Service);
-
-        serviceIdA = entityA.buildId();
-        serviceIdB = entityB.buildId();
-    }
-
-    @SneakyThrows
-    @AfterEach
-    public void after() {
-        environment.stop();
-    }
-
-    @SneakyThrows
-    @ParameterizedTest(name = "{0}")
-    @MethodSource("versions")
-    public void test(final String version,
-                     final DataSourceType dsType) {
-        init(version, dsType);
-        trafficTest();
-        metricsTest();
-        tagsTest();
-        recordsTest();
-        topologyTest();
-    }
-
-    // @SQLDatabase.Sharding(
-    // shardingAlgorithm = ShardingAlgorithm.TIME_MIN_RANGE_SHARDING_ALGORITHM,
-    // tableShardingColumn = TIME_BUCKET,
-    // dataSourceShardingColumn = ID)
-    @SneakyThrows
-    private void trafficTest() {
-        log.info("Traffic test start...");
-        StorageModels models = new StorageModels();
-        models.add(
-            EndpointTraffic.class, DefaultScopeDefine.SERVICE,
-            new Storage(EndpointTraffic.INDEX_NAME, false, DownSampling.Minute), false
-        );
-        Model model = models.allModels().get(0);
-        TableMetaInfo.addModel(model);
-
-        EndpointTraffic endpointTrafficA = new EndpointTraffic();
-        endpointTrafficA.setName("Endpoint_A");
-        endpointTrafficA.setServiceId(serviceIdA);
-        endpointTrafficA.setTimeBucket(timeBucketMin);
-        EndpointTraffic endpointTrafficB = new EndpointTraffic();
-        endpointTrafficB.setName("Endpoint_B");
-        endpointTrafficB.setServiceId(serviceIdB);
-        endpointTrafficB.setTimeBucket(timeBucketMin);
-        List<Metrics> metricsList = new ArrayList<>();
-        metricsList.add(endpointTrafficA);
-        metricsList.add(endpointTrafficB);
-
-        createShardingRuleTest(model);
-        updateShardingRuleTest(model);
-        createShardingTableTest(model);
-
-        insertMetrics(model, metricsList);
-        testDataSharding(endpointTrafficA);
-        ttlDropTest(model);
-
-        //Test traffic query
-        JDBCMetadataQueryDAO metadataQueryDAO = new JDBCMetadataQueryDAO(ssClient, 100);
-        List<Endpoint> endpoints = metadataQueryDAO.findEndpoint("", endpointTrafficA.getServiceId(), 100);
-        Assertions.assertEquals(endpointTrafficA.getName(), endpoints.get(0).getName());
-        log.info("Traffic test passed.");
-    }
-
-    // @SQLDatabase.Sharding(
-    // shardingAlgorithm = ShardingAlgorithm.TIME_RELATIVE_ID_SHARDING_ALGORITHM,
-    // tableShardingColumn = ID,
-    // dataSourceShardingColumn = ENTITY_ID)
-    @SneakyThrows
-    private void metricsTest() {
-        log.info("Metrics test start...");
-        StorageModels models = new StorageModels();
-        models.add(
-            ServiceCpmMetrics.class, DefaultScopeDefine.SERVICE,
-            new Storage(ServiceCpmMetrics.INDEX_NAME, true, DownSampling.Minute), false
-        );
-        Model model = models.allModels().get(0);
-        TableMetaInfo.addModel(model);
-
-        ServiceCpmMetrics serviceCpmMetricsA = new ServiceCpmMetrics();
-        serviceCpmMetricsA.setEntityId(serviceIdA);
-        serviceCpmMetricsA.setValue(100);
-        serviceCpmMetricsA.setTotal(100);
-        serviceCpmMetricsA.setTimeBucket(timeBucketMin);
-        ServiceCpmMetrics serviceCpmMetricsB = new ServiceCpmMetrics();
-        serviceCpmMetricsB.setEntityId(serviceIdB);
-        serviceCpmMetricsB.setValue(200);
-        serviceCpmMetricsB.setTotal(200);
-        serviceCpmMetricsB.setTimeBucket(timeBucketMin);
-
-        createShardingRuleTest(model);
-        updateShardingRuleTest(model);
-        createShardingTableTest(model);
-
-        insertMetrics(model, Arrays.asList(serviceCpmMetricsA, serviceCpmMetricsB));
-        testDataSharding(serviceCpmMetricsA);
-
-        ttlDropTest(model);
-
-        //Test topN
-        ShardingAggregationQueryDAO aggregationQueryDAO = new ShardingAggregationQueryDAO(ssClient);
-        TopNCondition topNCondition = new TopNCondition();
-        topNCondition.setName(ServiceCpmMetrics.INDEX_NAME);
-        topNCondition.setTopN(1);
-        topNCondition.setOrder(Order.DES);
-
-        SelectedRecord top1Record = aggregationQueryDAO.sortMetrics(topNCondition, "value", duration, null).get(0);
-        Assertions.assertEquals(serviceCpmMetricsB.getEntityId(), top1Record.getId());
-        Assertions.assertEquals("200.0000", top1Record.getValue());
-
-        //Test metrics query
-        ShardingMetricsQueryDAO metricsQueryDAO = new ShardingMetricsQueryDAO(ssClient);
-        MetricsCondition metricsCondition = new MetricsCondition();
-
-        metricsCondition.setName(ServiceCpmMetrics.INDEX_NAME);
-        metricsCondition.setEntity(entityA);
-
-        long value = metricsQueryDAO.readMetricsValue(metricsCondition, "value", duration);
-        Assertions.assertEquals(serviceCpmMetricsA.getValue(), value);
-
-        MetricsValues values = metricsQueryDAO.readMetricsValues(metricsCondition, "value", duration);
-        String metricsId = serviceCpmMetricsA.getTimeBucket() + "_" + serviceCpmMetricsA.getEntityId();
-        Assertions.assertEquals(serviceCpmMetricsA.getValue(), values.getValues().findValue(metricsId, 0));
-        log.info("Metrics test passed.");
-    }
-
-    // @SQLDatabase.Sharding(shardingAlgorithm = ShardingAlgorithm.NO_SHARDING)
-    @SneakyThrows
-    private void tagsTest() {
-        log.info("Tag auto complete data test start...");
-        StorageModels models = new StorageModels();
-        models.add(
-            TagAutocompleteData.class, DefaultScopeDefine.SEGMENT,
-            new Storage(TagAutocompleteData.INDEX_NAME, true, DownSampling.Minute), false
-        );
-        Model model = models.allModels().get(0);
-        TableMetaInfo.addModel(model);
-        installer.createTable(model);
-        TagAutocompleteData tagData1 = new TagAutocompleteData();
-        tagData1.setTagType(TagType.TRACE.name());
-        tagData1.setTagKey(searchableTag);
-        tagData1.setTagValue("GET");
-        tagData1.setTimeBucket(timeBucketMin);
-        TagAutocompleteData tagData2 = new TagAutocompleteData();
-        tagData2.setTagType(TagType.TRACE.name());
-        tagData2.setTagKey(searchableTag);
-        tagData2.setTagValue("POST");
-        //Should be deleted after TTL process
-        tagData2.setTimeBucket(timeBucketMin);
-        TagAutocompleteData tagData3 = new TagAutocompleteData();
-        tagData3.setTagType(TagType.TRACE.name());
-        tagData3.setTagKey(searchableTag);
-        tagData3.setTagValue("HEAD");
-        //Should be deleted after TTL process
-        tagData3.setTimeBucket(Long.parseLong(DateTime.now().minusDays(5).toString("yyyyMMddHHmm")));
-        insertMetrics(model, Arrays.asList(tagData1, tagData2, tagData3));
-
-        //Test total count
-        try (Connection ssConn = ssClient.getConnection()) {
-            ResultSet rs = ssClient.executeQuery(ssConn, countQuery + TagAutocompleteData.INDEX_NAME);
-            rs.next();
-            Assertions.assertEquals(3, rs.getInt("rc"));
-        }
-
-        // Test query
-        JDBCTagAutoCompleteQueryDAO tagQueryDAO = new JDBCTagAutoCompleteQueryDAO(ssClient);
-        Set<String> tagKeys = tagQueryDAO.queryTagAutocompleteKeys(TagType.TRACE, 10, duration);
-        Assertions.assertEquals(searchableTag, tagKeys.iterator().next());
-        Set<String> tagValues = tagQueryDAO.queryTagAutocompleteValues(TagType.TRACE, searchableTag, 10, duration);
-        Assertions.assertEquals(2, tagValues.size());
-
-        // Test TTL
-        historyDelete(model);
-        try (Connection ssConn = ssClient.getConnection()) {
-            ResultSet rs = ssClient.executeQuery(ssConn, countQuery + TagAutocompleteData.INDEX_NAME);
-            rs.next();
-            Assertions.assertEquals(2, rs.getInt("rc"));
-        }
-        log.info("Tag auto complete data test passed.");
-    }
-
-    // @SQLDatabase.Sharding(
-    // shardingAlgorithm = ShardingAlgorithm.TIME_SEC_RANGE_SHARDING_ALGORITHM,
-    // dataSourceShardingColumn = SERVICE_ID,
-    // tableShardingColumn = TIME_BUCKET)
-    @SneakyThrows
-    private void recordsTest() {
-        log.info("Records (Trace) test start...");
-        StorageModels models = new StorageModels();
-        models.add(
-            SegmentRecord.class, DefaultScopeDefine.SEGMENT,
-            new Storage(SegmentRecord.INDEX_NAME, false, DownSampling.Second), true
-        );
-        Model model = models.allModels().get(0);
-        TableMetaInfo.addModel(model);
-        Tag tag = new Tag(searchableTag, "GET");
-        List<String> tags = Collections.singletonList(tag.toString());
-        SegmentRecord segmentRecordA = new SegmentRecord();
-        segmentRecordA.setSegmentId("segmentA");
-        segmentRecordA.setTraceId("traceA");
-        segmentRecordA.setServiceId(serviceIdA);
-        segmentRecordA.setTimeBucket(timeBucketSec);
-        segmentRecordA.setTags(tags);
-        segmentRecordA.setStartTime(DateTime.now().getMillis());
-        segmentRecordA.setEndpointId(IDManager.EndpointID.buildId(segmentRecordA.getServiceId(), "Endpoint_A"));
-        SegmentRecord segmentRecordB = new SegmentRecord();
-        segmentRecordB.setSegmentId("segmentB");
-        segmentRecordB.setTraceId("traceA");
-        segmentRecordB.setServiceId(serviceIdB);
-        segmentRecordB.setTimeBucket(timeBucketSec);
-        segmentRecordB.setTags(tags);
-        segmentRecordB.setStartTime(DateTime.now().getMillis());
-        segmentRecordA.setEndpointId(IDManager.EndpointID.buildId(segmentRecordB.getServiceId(), "Endpoint_B"));
-
-        createShardingRuleTest(model);
-        updateShardingRuleTest(model);
-        createShardingTableTest(model);
-        insertRecords(model, Arrays.asList(segmentRecordA, segmentRecordB));
-        testDataSharding(segmentRecordA);
-        ttlDropTest(model);
-
-        //Test trace query
-        ShardingTraceQueryDAO traceQueryDAO = new ShardingTraceQueryDAO(moduleManager, ssClient);
-        TraceBrief traceBrief = traceQueryDAO.queryBasicTraces(
-            duration, 0, 0,
-            segmentRecordA.getServiceId(), null,
-            null, null, 10, 0,
-            TraceState.SUCCESS, QueryOrder.BY_START_TIME, Collections.singletonList(tag)
-        );
-        Assertions.assertEquals(segmentRecordA.getSegmentId(), traceBrief.getTraces().get(0).getSegmentId());
-
-        List<SegmentRecord> segmentRecords = traceQueryDAO.queryByTraceId(segmentRecordA.getTraceId());
-        Assertions.assertEquals(2, segmentRecords.size());
-        log.info("Records (Trace) test passed.");
-    }
-
-    // @SQLDatabase.Sharding(
-    // shardingAlgorithm = ShardingAlgorithm.TIME_BUCKET_SHARDING_ALGORITHM,
-    // tableShardingColumn = TIME_BUCKET,
-    // dataSourceShardingColumn = ENTITY_ID)
-    @SneakyThrows
-    private void topologyTest() {
-        log.info("Topology test start...");
-        StorageModels models = new StorageModels();
-        models.add(
-            ServiceRelationServerSideMetrics.class, DefaultScopeDefine.SERVICE_RELATION,
-            new Storage(ServiceRelationServerSideMetrics.INDEX_NAME, true, DownSampling.Minute), false
-        );
-        models.add(
-            ServiceRelationClientSideMetrics.class, DefaultScopeDefine.SERVICE_RELATION,
-            new Storage(ServiceRelationClientSideMetrics.INDEX_NAME, true, DownSampling.Minute), false
-        );
-        Model serverModel = models.allModels().get(0);
-        Model clientModel = models.allModels().get(1);
-        TableMetaInfo.addModel(serverModel);
-        TableMetaInfo.addModel(clientModel);
-
-        ServiceRelationServerSideMetrics serverSideMetricsA = new ServiceRelationServerSideMetrics();
-        String clientIdA = IDManager.ServiceID.buildId("HTTP_Client", false);
-        serverSideMetricsA.setSourceServiceId(clientIdA);
-        serverSideMetricsA.setDestServiceId(serviceIdA);
-        serverSideMetricsA.setEntityId(IDManager.ServiceID.buildRelationId(
-            new IDManager.ServiceID.ServiceRelationDefine(clientIdA, serviceIdA)));
-        serverSideMetricsA.getComponentIds().add(0);
-        serverSideMetricsA.setTimeBucket(timeBucketMin);
-        ServiceRelationClientSideMetrics clientSideMetricsA = new ServiceRelationClientSideMetrics();
-        clientSideMetricsA.setSourceServiceId(clientIdA);
-        clientSideMetricsA.setDestServiceId(serviceIdA);
-        clientSideMetricsA.setEntityId(IDManager.ServiceID.buildRelationId(
-            new IDManager.ServiceID.ServiceRelationDefine(clientIdA, serviceIdA)));
-        clientSideMetricsA.getComponentIds().add(0);
-        clientSideMetricsA.setTimeBucket(timeBucketMin);
-
-        ServiceRelationServerSideMetrics serverSideMetricsB = new ServiceRelationServerSideMetrics();
-        serverSideMetricsB.setSourceServiceId(serviceIdA);
-        serverSideMetricsB.setDestServiceId(serviceIdB);
-        serverSideMetricsB.setEntityId(IDManager.ServiceID.buildRelationId(
-            new IDManager.ServiceID.ServiceRelationDefine(serviceIdA, serviceIdB)));
-        serverSideMetricsB.getComponentIds().add(0);
-        serverSideMetricsB.setTimeBucket(timeBucketMin);
-        ServiceRelationClientSideMetrics clientSideMetricsB = new ServiceRelationClientSideMetrics();
-        clientSideMetricsB.setSourceServiceId(clientIdA);
-        clientSideMetricsB.setDestServiceId(serviceIdA);
-        clientSideMetricsB.setEntityId(IDManager.ServiceID.buildRelationId(
-            new IDManager.ServiceID.ServiceRelationDefine(serviceIdA, serviceIdB)));
-        clientSideMetricsB.getComponentIds().add(0);
-        clientSideMetricsB.setTimeBucket(timeBucketMin);
-
-        createShardingRuleTest(serverModel);
-        createShardingRuleTest(clientModel);
-        updateShardingRuleTest(serverModel);
-        updateShardingRuleTest(clientModel);
-        createShardingTableTest(serverModel);
-        createShardingTableTest(clientModel);
-
-        insertMetrics(serverModel, Arrays.asList(serverSideMetricsA, serverSideMetricsB));
-        insertMetrics(clientModel, Arrays.asList(clientSideMetricsA, clientSideMetricsB));
-        testDataSharding(serverSideMetricsA);
-        testDataSharding(clientSideMetricsA);
-        ttlDropTest(serverModel);
-        ttlDropTest(clientModel);
-
-        //Test topology query
-        ShardingTopologyQueryDAO queryDAO = new ShardingTopologyQueryDAO(ssClient);
-        List<Call.CallDetail> callDetailsServerSide = queryDAO.loadServiceRelationsDetectedAtServerSide(
-            duration, Arrays.asList(serviceIdB));
-        //Service_A -----> Service_B
-        Assertions.assertEquals(serviceIdB, callDetailsServerSide.get(0).getTarget());
-        List<Call.CallDetail> callDetailsClientSide = queryDAO.loadServiceRelationDetectedAtClientSide(
-            duration, Arrays.asList(serviceIdA));
-        //HTTP_Client -----> Service_A -----> Service_B
-        Assertions.assertEquals(2, callDetailsClientSide.size());
-        log.info("Topology test passed.");
-    }
-
-    @SneakyThrows
-    private void createShardingRuleTest(Model model) {
-        ShardingRulesOperator.INSTANCE.createOrUpdateShardingRule(ssClient, model, dataSources, ttlTestCreate);
-        Map<String, ShardingRule> shardingRules = Whitebox.getInternalState(
-            ShardingRulesOperator.INSTANCE, "modelShardingRules");
-        ShardingRule inputRule = shardingRules.get(model.getName()).toBuilder().build();
-        ShardingRule outPutRule = loadShardingRule(model);
-        outPutRule.setOperation("CREATE");
-        //The rules in the database erased all `"`
-        Assertions.assertEquals(inputRule.toShardingRuleSQL().replaceAll("\"", ""), outPutRule.toShardingRuleSQL());
-    }
-
-    private void updateShardingRuleTest(Model model) throws StorageException {
-        ShardingRulesOperator.INSTANCE.createOrUpdateShardingRule(ssClient, model, dataSources, ttlTestCreate);
-        Map<String, ShardingRule> shardingRules = Whitebox.getInternalState(
-            ShardingRulesOperator.INSTANCE, "modelShardingRules");
-        ShardingRule inputRule = shardingRules.get(model.getName()).toBuilder().build();
-        ShardingRule outPutRule = loadShardingRule(model);
-        outPutRule.setOperation("ALTER");
-        //The rules in the database erased all `"`
-        Assertions.assertEquals(inputRule.toShardingRuleSQL().replaceAll("\"", ""), outPutRule.toShardingRuleSQL());
-    }
-
-    /**
-     * Load sharding rule from the database, return a clone rule for comparing.
-     */
-    @SneakyThrows
-    private ShardingRule loadShardingRule(Model model) {
-        Whitebox.invokeMethod(ShardingRulesOperator.INSTANCE, "initShardingRules", ssClient);
-        Map<String, ShardingRule> shardingRules = Whitebox.getInternalState(
-            ShardingRulesOperator.INSTANCE, "modelShardingRules");
-        return shardingRules.get(model.getName()).toBuilder().build();
-    }
-
-    @SneakyThrows
-    private void createShardingTableTest(Model model) {
-        installer.createTable(model);
-        existsTest(dsClient0, model);
-        existsTest(dsClient1, model);
-    }
-
-    @SneakyThrows
-    private void existsTest(JDBCHikariCPClient dsClient, Model model) {
-        //TTL is 3 so just test 4 tables
-        List<String> tables = new ArrayList<>();
-        tables.add(model.getName() + "_" + DateTime.now().minusDays(2).toString("yyyyMMdd"));
-        tables.add(model.getName() + "_" + DateTime.now().minusDays(1).toString("yyyyMMdd"));
-        tables.add(model.getName() + "_" + DateTime.now().toString("yyyyMMdd"));
-        tables.add(model.getName() + "_" + DateTime.now().plusDays(1).toString("yyyyMMdd"));
-        try (Connection conn = dsClient.getConnection()) {
-            for (String name : tables) {
-                ResultSet rset = conn.getMetaData().getTables(conn.getCatalog(), null, name, null);
-                Assertions.assertTrue(rset.next());
-            }
-        }
-    }
-
-    @SneakyThrows
-    private void insertMetrics(Model model, List<Metrics> metricsList) {
-        try (Connection conn = ssClient.getConnection()) {
-            for (Metrics metrics : metricsList) {
-                JDBCMetricsDAO jdbcMetricsDAO = new JDBCMetricsDAO(ssClient, metrics.getClass()
-                                                                                    .getAnnotation(Stream.class)
-                                                                                    .builder()
-                                                                                    .getDeclaredConstructor()
-                                                                                    .newInstance());
-                jdbcMetricsDAO.prepareBatchInsert(model, metrics, null).invoke(conn);
-            }
-        }
-    }
-
-    @SneakyThrows
-    private void insertRecords(Model model, List<Record> recordList) {
-        try (Connection conn = ssClient.getConnection()) {
-            for (Record record : recordList) {
-                JDBCRecordDAO jdbcRecordDAO = new JDBCRecordDAO(ssClient, record.getClass()
-                                                                                .getAnnotation(Stream.class)
-                                                                                .builder()
-                                                                                .getDeclaredConstructor()
-                                                                                .newInstance());
-                ((SQLExecutor) jdbcRecordDAO.prepareBatchInsert(model, record)).invoke(conn);
-            }
-        }
-    }
-
-    @SneakyThrows
-    private void testDataSharding(StorageData data) {
-        try (Connection ssConn = ssClient.getConnection();
-             Connection ds0Conn = dsClient0.getConnection();
-             Connection ds1Conn = dsClient1.getConnection()) {
-
-            String logicIndex = data.getClass().getAnnotation(Stream.class).name();
-            String physicalIndex = logicIndex + "_" + timeBucketDay;
-
-            ResultSet logicSet = ssClient.executeQuery(ssConn, countQuery + logicIndex);
-            logicSet.next();
-            Assertions.assertEquals(2, logicSet.getInt("rc"));
-
-            ResultSet physicalSet0 = dsClient0.executeQuery(ds0Conn, countQuery + physicalIndex);
-            physicalSet0.next();
-            Assertions.assertEquals(1, physicalSet0.getInt("rc"));
-
-            ResultSet physicalSet1 = dsClient1.executeQuery(ds1Conn, countQuery + physicalIndex);
-            physicalSet1.next();
-            Assertions.assertEquals(1, physicalSet1.getInt("rc"));
-
-            if (data.getClass().isAnnotationPresent(SQLDatabase.ExtraColumn4AdditionalEntity.class)) {
-                String additionalLogicIndex = data.getClass().getAnnotation(Stream.class).name();
-                String additionalPhysicalIndex = logicIndex + "_" + timeBucketDay;
-
-                ResultSet additionalLogicSet = ssClient.executeQuery(
-                    ssConn, countQuery + additionalLogicIndex);
-                additionalLogicSet.next();
-                Assertions.assertEquals(2, additionalLogicSet.getInt("rc"));
-
-                ResultSet additionalPhysicalSet0 = dsClient0.executeQuery(
-                    ds0Conn, countQuery + additionalPhysicalIndex);
-                additionalPhysicalSet0.next();
-                Assertions.assertEquals(1, additionalPhysicalSet0.getInt("rc"));
-
-                ResultSet additionalPhysicalSet1 = dsClient1.executeQuery(
-                    ds1Conn, countQuery + additionalPhysicalIndex);
-                additionalPhysicalSet1.next();
-                Assertions.assertEquals(1, additionalPhysicalSet1.getInt("rc"));
-            }
-        }
-    }
-
-    @SneakyThrows
-    private void ttlDropTest(Model model) {
-        historyDelete(model);
-
-        String droppedTable = model.getName() + "_" + DateTime.now().minusDays(2).toString("yyyyMMdd");
-        ResultSet rset0 = dsClient0.getConnection()
-                                   .getMetaData()
-                                   .getTables(dsClient0.getConnection().getCatalog(), null, droppedTable, null);
-        Assertions.assertFalse(rset0.next());
-        ResultSet rset1 = dsClient1.getConnection()
-                                   .getMetaData()
-                                   .getTables(dsClient1.getConnection().getCatalog(), null, droppedTable, null);
-        Assertions.assertFalse(rset1.next());
-    }
-
-    @SneakyThrows
-    private void historyDelete(Model model) {
-        ShardingHistoryDeleteDAO deleteDAO = new ShardingHistoryDeleteDAO(
-            ssClient, dataSources, moduleManager, mySQLTableInstaller);
-        deleteDAO.deleteHistory(model, Metrics.TIME_BUCKET, ttlTestDrop);
-    }
-
-    private enum DataSourceType {
-        MYSQL
-    }
-}
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/conf-mysql/config-sharding.yaml b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/conf-mysql/config-sharding.yaml
deleted file mode 100644
index c7b336bd52fc..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/conf-mysql/config-sharding.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# 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.
-#
-
-######################################################################################################
-# 
-# Here you can configure the rules for the proxy.
-# This example is configuration of sharding rule.
-# 
-######################################################################################################
-#
-databaseName: swtest
-
-dataSources:
- ds_0:
-   url: jdbc:mysql://data-source-0:3306/swtest?allowPublicKeyRetrieval=true
-   username: root
-   password: root@1234
-   connectionTimeoutMilliseconds: 30000
-   idleTimeoutMilliseconds: 60000
-   maxLifetimeMilliseconds: 1800000
-   maxPoolSize: 50
-   minPoolSize: 1
- ds_1:
-   url: jdbc:mysql://data-source-1:3306/swtest?allowPublicKeyRetrieval=true
-   username: root
-   password: root@1234
-   connectionTimeoutMilliseconds: 30000
-   idleTimeoutMilliseconds: 60000
-   maxLifetimeMilliseconds: 1800000
-   maxPoolSize: 50
-   minPoolSize: 1
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/conf-mysql/server.yaml b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/conf-mysql/server.yaml
deleted file mode 100644
index a49ab5675bd2..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/conf-mysql/server.yaml
+++ /dev/null
@@ -1,78 +0,0 @@
-#
-# 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.
-#
-
-######################################################################################################
-#
-# If you want to configure governance, authorization and proxy properties, please refer to this file.
-#
-######################################################################################################
-
-#mode:
-#  type: Cluster
-#  repository:
-#    type: ZooKeeper
-#    props:
-#      namespace: governance_ds
-#      server-lists: localhost:2181
-#      retryIntervalMilliseconds: 500
-#      timeToLiveSeconds: 60
-#      maxRetries: 3
-#      operationTimeoutMilliseconds: 500
-#
-#authority:
-#  users:
-#    - user: root@%
-#      password: root
-#  privilege:
-#    type: ALL_PERMITTED
-
-transaction:
-  defaultType: XA
-  providerType: Atomikos
-
-sqlParser:
-  sqlCommentParseEnabled: true
-  sqlStatementCache:
-    initialCapacity: 2000
-    maximumSize: 65535
-  parseTreeCache:
-    initialCapacity: 128
-    maximumSize: 1024
-
-props:
-  max-connections-size-per-query: 1
-  kernel-executor-size: 16  # Infinite by default.
-  proxy-frontend-flush-threshold: 128  # The default value is 128.
-  proxy-hint-enabled: true
-  sql-show: false
-  check-table-metadata-enabled: false
-  show-process-list-enabled: false
-    # Proxy backend query fetch size. A larger value may increase the memory usage of ShardingSphere Proxy.
-    # The default value is -1, which means set the minimum value for different JDBC drivers.
-  proxy-backend-query-fetch-size: -1
-  check-duplicate-table-enabled: false
-  proxy-frontend-executor-size: 0 # Proxy frontend executor size. The default value is 0, which means let Netty decide.
-    # Available options of proxy backend executor suitable: OLAP(default), OLTP. The OLTP option may reduce time cost of writing packets to client, but it may increase the latency of SQL execution
-    # and block other clients if client connections are more than `proxy-frontend-executor-size`, especially executing slow SQL.
-  proxy-backend-executor-suitable: OLAP
-  proxy-frontend-max-connections: 0 # Less than or equal to 0 means no limitation.
-  sql-federation-enabled: false
-    # Available proxy backend driver type: JDBC (default), ExperimentalVertx
-  proxy-backend-driver-type: JDBC
-  proxy-mysql-default-version: 8.0.13 # In the absence of schema name, the default version will be used.
-  proxy-default-port: 3307 # Proxy default port.
-  proxy-netty-backlog: 1024 # Proxy netty backlog.
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/docker-compose-mysql.yml b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/docker-compose-mysql.yml
deleted file mode 100644
index e3227a2523f4..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/docker-compose-mysql.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  sharding-proxy:
-    image: apache/shardingsphere-proxy:${SS_VERSION}
-    volumes:
-      - ./download-mysql.sh:/opt/shardingsphere-proxy/download-mysql.sh
-      - ./conf-mysql:/opt/shardingsphere-proxy/conf
-    networks:
-      - e2e
-    expose:
-      - 3307
-    entrypoint: ['sh', '-c', '/opt/shardingsphere-proxy/download-mysql.sh /opt/shardingsphere-proxy/ext-lib && /opt/shardingsphere-proxy/bin/start.sh 3307 && tail -f /opt/shardingsphere-proxy/logs/stdout.log']
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3307"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    depends_on:
-      data-source-0:
-        condition: service_healthy
-      data-source-1:
-        condition: service_healthy
-
-  data-source-0: &ds
-    image: mysql/mysql-server:8.0.13
-    networks:
-      - e2e
-    expose:
-      - 3306
-    environment:
-      MYSQL_ROOT_PASSWORD: "root@1234"
-      MYSQL_DATABASE: "swtest"
-      MYSQL_ROOT_HOST: "%"
-    healthcheck:
-      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  data-source-1:
-    <<: *ds
-
-networks:
-  e2e:
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/download-mysql.sh b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/download-mysql.sh
deleted file mode 100755
index 7ffd5e876089..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/download-mysql.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-set -ex
-
-LIB_HOME=$1
-MYSQL_URL="https://repo.maven.apache.org/maven2/mysql/mysql-connector-java/8.0.13/mysql-connector-java-8.0.13.jar"
-MYSQL_DRIVER="mysql-connector-java-8.0.13.jar"
-
-# ensure the curl command been installed
-if ! command -v curl &> /dev/null; then
-    apt update -y && apt install -y curl
-fi
-
-if ! curl -Lo "${LIB_HOME}/${MYSQL_DRIVER}" ${MYSQL_URL}; then
-    echo "Fail to download ${MYSQL_DRIVER}."
-    exit 1
-fi
diff --git a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/log4j2.xml b/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/log4j2.xml
deleted file mode 100644
index cd672826bb3f..000000000000
--- a/oap-server/server-storage-plugin/storage-shardingsphere-plugin/src/test/resources/log4j2.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ 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.
-  ~
-  -->
-
-<Configuration status="INFO">
-    <Appenders>
-        <Console name="Console" target="SYSTEM_OUT">
-            <PatternLayout charset="UTF-8" pattern="%d - %c -%-4r [%t] %-5p %x - %m%n"/>
-        </Console>
-    </Appenders>
-    <Loggers>
-        <Root level="INFO">
-            <AppenderRef ref="Console"/>
-        </Root>
-    </Loggers>
-</Configuration>
diff --git a/test/e2e-v2/cases/alarm/h2/docker-compose.yml b/test/e2e-v2/cases/alarm/h2/docker-compose.yml
index f0d7fc204679..148f6c9ed6e7 100644
--- a/test/e2e-v2/cases/alarm/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/alarm/h2/docker-compose.yml
@@ -36,7 +36,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
       SW_SEARCHABLE_ALARM_TAG_KEYS: level,receivers
     ports:
       - 12800
diff --git a/test/e2e-v2/cases/browser/mysql/sharding/docker-compose.yml b/test/e2e-v2/cases/browser/mysql/sharding/docker-compose.yml
deleted file mode 100644
index d53d3c705364..000000000000
--- a/test/e2e-v2/cases/browser/mysql/sharding/docker-compose.yml
+++ /dev/null
@@ -1,165 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  sharding-proxy:
-    extends:
-      file: ../../../../script/shardingsphere-proxy/base-compose.yml
-      service: sharding-proxy
-    networks:
-      - e2e
-    volumes:
-      - ../../../../script/shardingsphere-proxy/conf-mysql:/opt/shardingsphere-proxy/conf
-    expose:
-      - 3307
-    depends_on:
-      mysql-1:
-        condition: service_healthy
-      mysql-2:
-        condition: service_healthy
-
-  mysql-1: &mysql
-    image: mysql/mysql-server:8.0.13
-    networks:
-      - e2e
-    expose:
-      - 3306
-    environment:
-      MYSQL_ROOT_PASSWORD: "root@1234"
-      MYSQL_DATABASE: "swtest"
-      MYSQL_ROOT_HOST: "%"
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  mysql-2:
-    <<: *mysql
-
-  oap:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: mysql-sharding
-      SW_JDBC_URL: jdbc:mysql://sharding-proxy:3307/swtest
-      SW_JDBC_SHARDING_DATA_SOURCES: ds_0,ds_1
-      SW_CORE_METRICS_DATA_TTL: 2
-      SW_CORE_RECORD_DATA_TTL: 2
-      SW_OTEL_RECEIVER_ENABLED_OTEL_RULES: ""
-      SW_METER_ANALYZER_ACTIVE_FILES: ""
-
-    ports:
-      - 12800
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    networks:
-      - e2e
-    depends_on:
-      sharding-proxy:
-        condition: service_healthy
-
-  provider:
-    build:
-      context: ./../../
-      dockerfile: docker/Dockerfile.provider
-      args:
-        - SW_AGENT_PYTHON_COMMIT=${SW_AGENT_PYTHON_COMMIT}
-    command: [ 'python3', '/entrypoint.py' ]
-    networks:
-      - e2e
-    expose:
-      - 9091
-    environment:
-      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
-      SW_AGENT_LOGGING_LEVEL: DEBUG
-    volumes:
-      - ./../../docker/provider.py:/entrypoint.py
-    depends_on:
-      oap:
-        condition: service_healthy
-    healthcheck:
-      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9091" ]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  testui:
-    build:
-      context: ./../../
-      dockerfile: docker/Dockerfile.test-ui
-      args:
-        - SW_AGENT_CLIENT_JS_TEST_COMMIT=${SW_AGENT_CLIENT_JS_TEST_COMMIT}
-        - SW_AGENT_CLIENT_JS_COMMIT=${SW_AGENT_CLIENT_JS_COMMIT}
-    networks:
-      - e2e
-    ports:
-      - 80
-    depends_on:
-      provider:
-        condition: service_healthy
-      oap:
-        condition: service_healthy
-
-  selenium-hub:
-    image: selenium/hub:4.0.0-alpha-7-prerelease-20201009
-    networks:
-      - e2e
-    expose:
-      - 4444
-    depends_on:
-      testui:
-        condition: service_started
-      provider:
-        condition: service_healthy
-
-  chrome:
-    image: selenium/node-chrome:4.0.0-alpha-7-prerelease-20201009
-    networks:
-      - e2e
-    volumes:
-      - /dev/shm:/dev/shm
-    depends_on:
-      selenium-hub:
-        condition: service_started
-      testui:
-        condition: service_started
-      provider:
-        condition: service_healthy
-    environment:
-      - SE_EVENT_BUS_HOST=selenium-hub
-      - SE_EVENT_BUS_PUBLISH_PORT=4442
-      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
-  generate-traffic:
-    build:
-      context: ./../../
-      dockerfile: docker/Dockerfile.generate-traffic
-    networks:
-      - e2e
-    restart: always
-    depends_on:
-      selenium-hub:
-        condition: service_started
-      chrome:
-        condition: service_started
-      provider:
-        condition: service_healthy
-      testui:
-        condition: service_started
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/browser/mysql/sharding/e2e.yaml b/test/e2e-v2/cases/browser/mysql/sharding/e2e.yaml
deleted file mode 100644
index eb2eaa8d7e16..000000000000
--- a/test/e2e-v2/cases/browser/mysql/sharding/e2e.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-verify:
-  # verify with retry strategy
-  retry:
-    # max retry count
-    count: 20
-    # the interval between two retries, in millisecond.
-    interval: 3s
-  cases:
-    - includes:
-        - ../../browser-cases.yaml
diff --git a/test/e2e-v2/cases/event/h2/docker-compose.yml b/test/e2e-v2/cases/event/h2/docker-compose.yml
index 61131695c915..65ea3112f50c 100644
--- a/test/e2e-v2/cases/event/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/event/h2/docker-compose.yml
@@ -36,7 +36,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
     depends_on:
       h2db:
         condition: service_healthy
diff --git a/test/e2e-v2/cases/log/h2/docker-compose.yml b/test/e2e-v2/cases/log/h2/docker-compose.yml
index c7bad94f732b..cf293be54511 100644
--- a/test/e2e-v2/cases/log/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/log/h2/docker-compose.yml
@@ -36,7 +36,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
     depends_on:
       h2db:
         condition: service_healthy
diff --git a/test/e2e-v2/cases/log/mysql/docker-compose.yml b/test/e2e-v2/cases/log/mysql/docker-compose.yml
index ac18e7a14a7d..70df63180eac 100644
--- a/test/e2e-v2/cases/log/mysql/docker-compose.yml
+++ b/test/e2e-v2/cases/log/mysql/docker-compose.yml
@@ -38,7 +38,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: mysql
-      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest
+      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest?allowMultiQueries=true
     ports:
       - 12800
     entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
diff --git a/test/e2e-v2/cases/log/mysql/sharding/docker-compose.yml b/test/e2e-v2/cases/log/mysql/sharding/docker-compose.yml
deleted file mode 100644
index 09ece8cbefb4..000000000000
--- a/test/e2e-v2/cases/log/mysql/sharding/docker-compose.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  sharding-proxy:
-    extends:
-      file: ../../../../script/shardingsphere-proxy/base-compose.yml
-      service: sharding-proxy
-    volumes:
-      - ../../../../script/shardingsphere-proxy/conf-mysql:/opt/shardingsphere-proxy/conf
-    networks:
-      - e2e
-    expose:
-      - 3307
-    depends_on:
-      mysql-1:
-        condition: service_healthy
-      mysql-2:
-        condition: service_healthy
-
-  mysql-1: &mysql
-    image: mysql/mysql-server:8.0.13
-    networks:
-      - e2e
-    expose:
-      - 3306
-    environment:
-      MYSQL_ROOT_PASSWORD: "root@1234"
-      MYSQL_DATABASE: "swtest"
-      MYSQL_ROOT_HOST: "%"
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  mysql-2:
-    <<: *mysql
-
-  oap:
-    extends:
-      file: ../../log-base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: mysql-sharding
-      SW_JDBC_URL: jdbc:mysql://sharding-proxy:3307/swtest
-      SW_JDBC_SHARDING_DATA_SOURCES: ds_0,ds_1
-      SW_CORE_METRICS_DATA_TTL: 2
-      SW_CORE_RECORD_DATA_TTL: 2
-      SW_OTEL_RECEIVER_ENABLED_OTEL_RULES: ""
-      SW_METER_ANALYZER_ACTIVE_FILES: ""
-      SW_ENVOY_METRIC: "-"
-
-    ports:
-      - 12800
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    networks:
-      - e2e
-    depends_on:
-      sharding-proxy:
-        condition: service_healthy
-
-  provider:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: provider
-    depends_on:
-      oap:
-        condition: service_healthy
-    ports:
-      - 9090
-    networks:
-      - e2e
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/log/mysql/sharding/e2e.yaml b/test/e2e-v2/cases/log/mysql/sharding/e2e.yaml
deleted file mode 100644
index 592267acd079..000000000000
--- a/test/e2e-v2/cases/log/mysql/sharding/e2e.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-trigger:
-  action: http
-  interval: 3s
-  times: 10
-  url: http://${provider_host}:${provider_9090}/logs/trigger
-  method: GET
-
-verify:
-  # verify with retry strategy
-  retry:
-    # max retry count
-    count: 20
-    # the interval between two retries, in millisecond.
-    interval: 10s
-  cases:
-    - includes:
-        - ../../log-cases.yaml
diff --git a/test/e2e-v2/cases/mysql/mysql-slowsql/docker-compose.yaml b/test/e2e-v2/cases/mysql/mysql-slowsql/docker-compose.yaml
index a2ce1307666b..a0acd7a2cb42 100644
--- a/test/e2e-v2/cases/mysql/mysql-slowsql/docker-compose.yaml
+++ b/test/e2e-v2/cases/mysql/mysql-slowsql/docker-compose.yaml
@@ -30,7 +30,7 @@ services:
       - SW_STORAGE=mysql
       - SW_DATA_SOURCE_USER=root
       - SW_DATA_SOURCE_PASSWORD=password
-      - SW_JDBC_URL=jdbc:mysql://mysql:3306/swtest
+      - SW_JDBC_URL=jdbc:mysql://mysql:3306/swtest?allowMultiQueries=true
       - SW_CORE_TOPN_REPORT_PERIOD=2
     depends_on:
       mysql:
diff --git a/test/e2e-v2/cases/profiling/ebpf/network/h2/docker-compose.yml b/test/e2e-v2/cases/profiling/ebpf/network/h2/docker-compose.yml
index 529d90cda1ce..a2bdac82a670 100644
--- a/test/e2e-v2/cases/profiling/ebpf/network/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/profiling/ebpf/network/h2/docker-compose.yml
@@ -38,7 +38,7 @@ services:
       - e2e
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
     depends_on:
       h2db:
         condition: service_healthy
@@ -85,4 +85,4 @@ services:
         condition: service_healthy
 
 networks:
-  e2e:
\ No newline at end of file
+  e2e:
diff --git a/test/e2e-v2/cases/profiling/ebpf/network/tidb/docker-compose.yml b/test/e2e-v2/cases/profiling/ebpf/network/tidb/docker-compose.yml
deleted file mode 100644
index 4d7b63f9b1cf..000000000000
--- a/test/e2e-v2/cases/profiling/ebpf/network/tidb/docker-compose.yml
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  tidb:
-    image: pingcap/tidb:v4.0.12
-    expose:
-      - 4000
-    volumes:
-      - ../../../storage/tidb/tidbconfig/tidb.toml:/tidb.toml:ro
-    restart: on-failure
-    healthcheck:
-      test: [ "CMD", "sh", "-c", "nc -zn 127.0.0.1 4000" ]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    networks:
-      - e2e
-
-  oap:
-    extends:
-      file: ../docker-compose.yml
-      service: oap
-    networks:
-      - e2e
-    environment:
-      SW_STORAGE: tidb
-      SW_JDBC_URL: "jdbc:mysql://tidb:4000/test"
-      SW_DATA_SOURCE_PASSWORD: ""
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    depends_on:
-      tidb:
-        condition: service_healthy
-    ports:
-    - 12800
-
-  rover:
-    extends:
-      file: ../docker-compose.yml
-      service: rover
-    networks:
-      - e2e
-    depends_on:
-      oap:
-        condition: service_healthy
-
-  service:
-    extends:
-      file: ../docker-compose.yml
-      service: service
-    networks:
-      - e2e
-    environment:
-      OAP_BACKEND_ADDR: oap:11800
-    ports:
-      - 80
-    depends_on:
-      oap:
-        condition: service_healthy
-    healthcheck:
-      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/80" ]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  proxy:
-    extends:
-      file: ../docker-compose.yml
-      service: proxy
-    networks:
-      - e2e
-    depends_on:
-      service:
-        condition: service_healthy
-
-networks:
-  e2e:
\ No newline at end of file
diff --git a/test/e2e-v2/cases/profiling/ebpf/network/tidb/e2e.yaml b/test/e2e-v2/cases/profiling/ebpf/network/tidb/e2e.yaml
deleted file mode 100644
index 765e5a2ec22c..000000000000
--- a/test/e2e-v2/cases/profiling/ebpf/network/tidb/e2e.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-trigger:
-  action: http
-  interval: 3s
-  times: 10
-  url: http://${service_host}:${service_80}/consumer
-  method: GET
-
-verify:
-  retry:
-    count: 20
-    interval: 10s
-  cases:
-    - includes:
-        - ../network-cases.yaml
\ No newline at end of file
diff --git a/test/e2e-v2/cases/profiling/ebpf/oncpu/h2/docker-compose.yml b/test/e2e-v2/cases/profiling/ebpf/oncpu/h2/docker-compose.yml
index e9c5695ba1f7..60de1ca3ca54 100644
--- a/test/e2e-v2/cases/profiling/ebpf/oncpu/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/profiling/ebpf/oncpu/h2/docker-compose.yml
@@ -38,7 +38,7 @@ services:
       - e2e
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
     depends_on:
       h2db:
         condition: service_healthy
@@ -63,4 +63,4 @@ services:
         condition: service_healthy
 
 networks:
-  e2e:
\ No newline at end of file
+  e2e:
diff --git a/test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/docker-compose.yml b/test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/docker-compose.yml
deleted file mode 100644
index db5f51eb48d2..000000000000
--- a/test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/docker-compose.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  tidb:
-    image: pingcap/tidb:v4.0.12
-    expose:
-      - 4000
-    volumes:
-      - ../../../storage/tidb/tidbconfig/tidb.toml:/tidb.toml:ro
-    restart: on-failure
-    healthcheck:
-      test: [ "CMD", "sh", "-c", "nc -zn 127.0.0.1 4000" ]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    networks:
-      - e2e
-
-  oap:
-    extends:
-      file: ../docker-compose.yml
-      service: oap
-    networks:
-      - e2e
-    environment:
-      SW_STORAGE: tidb
-      SW_JDBC_URL: "jdbc:mysql://tidb:4000/test"
-      SW_DATA_SOURCE_PASSWORD: ""
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    depends_on:
-      tidb:
-        condition: service_healthy
-    ports:
-    - 12800
-
-  sqrt:
-    extends:
-      file: ../docker-compose.yml
-      service: sqrt
-    networks:
-      - e2e
-
-  rover:
-    extends:
-      file: ../docker-compose.yml
-      service: rover
-    networks:
-      - e2e
-    depends_on:
-      oap:
-        condition: service_healthy
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/e2e.yaml b/test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/e2e.yaml
deleted file mode 100644
index f8fdca0f49ab..000000000000
--- a/test/e2e-v2/cases/profiling/ebpf/oncpu/tidb/e2e.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-verify:
-  retry:
-    count: 20
-    interval: 10s
-  cases:
-    - includes:
-        - ../profiling-cases.yaml
\ No newline at end of file
diff --git a/test/e2e-v2/cases/profiling/trace/h2/docker-compose.yml b/test/e2e-v2/cases/profiling/trace/h2/docker-compose.yml
index fc2a30c9ea89..02327cf2242d 100644
--- a/test/e2e-v2/cases/profiling/trace/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/profiling/trace/h2/docker-compose.yml
@@ -46,7 +46,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
     depends_on:
       h2db:
         condition: service_healthy
diff --git a/test/e2e-v2/cases/profiling/trace/tidb/docker-compose.yml b/test/e2e-v2/cases/profiling/trace/tidb/docker-compose.yml
deleted file mode 100644
index 46df25a16d87..000000000000
--- a/test/e2e-v2/cases/profiling/trace/tidb/docker-compose.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  tidb:
-    image: pingcap/tidb:v4.0.12
-    expose:
-      - 4000
-    volumes:
-      - ../../../storage/tidb/tidbconfig/tidb.toml:/tidb.toml:ro
-    restart: on-failure
-    healthcheck:
-      test: [ "CMD", "sh", "-c", "nc -zn 127.0.0.1 4000" ]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    networks:
-      - e2e
-
-  provider:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: provider
-    depends_on:
-      oap:
-        condition: service_healthy
-    ports:
-      - 9090
-
-  oap:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: tidb
-      SW_JDBC_URL: "jdbc:mysql://tidb:4000/test"
-      SW_DATA_SOURCE_PASSWORD: ""
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    depends_on:
-      tidb:
-        condition: service_healthy
-    ports:
-      - 12800
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/profiling/trace/tidb/e2e.yaml b/test/e2e-v2/cases/profiling/trace/tidb/e2e.yaml
deleted file mode 100644
index 8a4fdf3a3e8c..000000000000
--- a/test/e2e-v2/cases/profiling/trace/tidb/e2e.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-verify:
-  retry:
-    count: 20
-    interval: 3s
-  cases:
-    - includes:
-        - ../profiling-cases.yaml
diff --git a/test/e2e-v2/cases/storage/h2/docker-compose.yml b/test/e2e-v2/cases/storage/h2/docker-compose.yml
index 1220d6a202cd..ae7ace11f6cd 100644
--- a/test/e2e-v2/cases/storage/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/storage/h2/docker-compose.yml
@@ -36,7 +36,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
     depends_on:
       h2db:
         condition: service_healthy
diff --git a/test/e2e-v2/cases/storage/mysql/docker-compose.yml b/test/e2e-v2/cases/storage/mysql/docker-compose.yml
index f5426be3037a..f19c1fbf9c86 100644
--- a/test/e2e-v2/cases/storage/mysql/docker-compose.yml
+++ b/test/e2e-v2/cases/storage/mysql/docker-compose.yml
@@ -38,7 +38,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: mysql
-      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest
+      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest?allowMultiQueries=true
     ports:
       - 12800
     entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
diff --git a/test/e2e-v2/cases/storage/mysql/sharding/docker-compose.yml b/test/e2e-v2/cases/storage/mysql/sharding/docker-compose.yml
deleted file mode 100644
index b87f73b04318..000000000000
--- a/test/e2e-v2/cases/storage/mysql/sharding/docker-compose.yml
+++ /dev/null
@@ -1,103 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  sharding-proxy:
-    extends:
-      file: ../../../../script/shardingsphere-proxy/base-compose.yml
-      service: sharding-proxy
-    networks:
-      - e2e
-    expose:
-      - 3307
-    volumes:
-      - ../../../../script/shardingsphere-proxy/conf-mysql:/opt/shardingsphere-proxy/conf
-    depends_on:
-      mysql-1:
-        condition: service_healthy
-      mysql-2:
-        condition: service_healthy
-
-  mysql-1: &mysql
-    image: mysql/mysql-server:8.0.13
-    networks:
-      - e2e
-    expose:
-      - 3306
-    environment:
-      MYSQL_ROOT_PASSWORD: "root@1234"
-      MYSQL_DATABASE: "swtest"
-      MYSQL_ROOT_HOST: "%"
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  mysql-2:
-    <<: *mysql
-
-  oap:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: mysql-sharding
-      SW_JDBC_URL: jdbc:mysql://sharding-proxy:3307/swtest
-      SW_JDBC_SHARDING_DATA_SOURCES: ds_0,ds_1
-      SW_CORE_METRICS_DATA_TTL: 2
-      SW_CORE_RECORD_DATA_TTL: 2
-      SW_OTEL_RECEIVER_ENABLED_OTEL_RULES: ""
-      SW_METER_ANALYZER_ACTIVE_FILES: ""
-      SW_LOG_LAL_FILES: ""
-      SW_ENVOY_METRIC: "-"
-
-    ports:
-      - 12800
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    networks:
-      - e2e
-    depends_on:
-      sharding-proxy:
-        condition: service_healthy
-
-  provider:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: provider
-    depends_on:
-      oap:
-        condition: service_healthy
-    ports:
-      - 9090
-    networks:
-      - e2e
-
-  consumer:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: consumer
-    ports:
-      - 9092
-    depends_on:
-      oap:
-        condition: service_healthy
-      provider:
-        condition: service_healthy
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/storage/mysql/sharding/e2e.yaml b/test/e2e-v2/cases/storage/mysql/sharding/e2e.yaml
deleted file mode 100644
index 214270be441c..000000000000
--- a/test/e2e-v2/cases/storage/mysql/sharding/e2e.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-trigger:
-  action: http
-  interval: 3s
-  times: 10
-  url: http://${consumer_host}:${consumer_9092}/users
-  method: POST
-  body: '{"id":"123","name":"skywalking"}'
-  headers:
-    "Content-Type": "application/json"
-
-verify:
-  # verify with retry strategy
-  retry:
-    # max retry count
-    count: 20
-    # the interval between two retries, in millisecond.
-    interval: 10s
-  cases:
-    - includes:
-      - ../../storage-cases.yaml
diff --git a/test/e2e-v2/cases/storage/tidb/docker-compose.yml b/test/e2e-v2/cases/storage/tidb/docker-compose.yml
deleted file mode 100644
index e3854b60bdc2..000000000000
--- a/test/e2e-v2/cases/storage/tidb/docker-compose.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  tidb:
-    image: pingcap/tidb:v4.0.12
-    expose:
-      - 4000
-    volumes:
-      - ./tidbconfig/tidb.toml:/tidb.toml:ro
-    restart: on-failure
-    healthcheck:
-      test: ["CMD", "sh", "-c", "nc -zn 127.0.0.1 4000"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    networks:
-      - e2e
-
-  oap:
-    extends:
-      file: ../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: tidb
-      SW_JDBC_URL: "jdbc:mysql://tidb:4000/test"
-      SW_DATA_SOURCE_PASSWORD: ""
-    ports:
-      - 12800
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    networks:
-      - e2e
-    depends_on:
-      tidb:
-        condition: service_healthy
-
-  provider:
-    extends:
-      file: ../../../script/docker-compose/base-compose.yml
-      service: provider
-    depends_on:
-      oap:
-        condition: service_healthy
-    ports:
-      - 9090
-    networks:
-      - e2e
-
-  consumer:
-    extends:
-      file: ../../../script/docker-compose/base-compose.yml
-      service: consumer
-    ports:
-      - 9092
-    depends_on:
-      oap:
-        condition: service_healthy
-      provider:
-        condition: service_healthy
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/storage/tidb/e2e.yaml b/test/e2e-v2/cases/storage/tidb/e2e.yaml
deleted file mode 100644
index 833e1957dc5b..000000000000
--- a/test/e2e-v2/cases/storage/tidb/e2e.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-trigger:
-  action: http
-  interval: 3s
-  times: 10
-  url: http://${consumer_host}:${consumer_9092}/users
-  method: POST
-  body: '{"id":"123","name":"skywalking"}'
-  headers:
-    "Content-Type": "application/json"
-
-verify:
-  # verify with retry strategy
-  retry:
-    # max retry count
-    count: 20
-    # the interval between two retries, in millisecond.
-    interval: 10s
-  cases:
-    - includes:
-      - ../storage-cases.yaml
diff --git a/test/e2e-v2/cases/storage/tidb/tidbconfig/tidb.toml b/test/e2e-v2/cases/storage/tidb/tidbconfig/tidb.toml
deleted file mode 100644
index acfadaef3433..000000000000
--- a/test/e2e-v2/cases/storage/tidb/tidbconfig/tidb.toml
+++ /dev/null
@@ -1,254 +0,0 @@
-# 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.
-
-# TiDB Configuration.
-
-# TiDB server host.
-host = "0.0.0.0"
-
-# TiDB server port.
-port = 4000
-
-# Registered store name, [tikv, mocktikv]
-store = "mocktikv"
-
-# TiDB storage path.
-path = "/tmp/tidb"
-
-# The socket file to use for connection.
-socket = ""
-
-# Run ddl worker on this tidb-server.
-run-ddl = true
-
-# Schema lease duration, very dangerous to change only if you know what you do.
-lease = "0"
-
-# When create table, split a separated region for it. It is recommended to
-# turn off this option if there will be a large number of tables created.
-split-table = true
-
-# The limit of concurrent executed sessions.
-token-limit = 1000
-
-# Only print a log when out of memory quota.
-# Valid options: ["log", "cancel"]
-oom-action = "log"
-
-# Set the memory quota for a query in bytes. Default: 32GB
-mem-quota-query = 34359738368
-
-# Enable coprocessor streaming.
-enable-streaming = false
-
-# Set system variable 'lower_case_table_names'
-lower-case-table-names = 2
-
-[log]
-# Log level: debug, info, warn, error, fatal.
-level = "error"
-
-# Log format, one of json, text, console.
-format = "text"
-
-# Disable automatic timestamp in output
-disable-timestamp = false
-
-# Stores slow query log into separated files.
-slow-query-file = ""
-
-# Queries with execution time greater than this value will be logged. (Milliseconds)
-slow-threshold = 300
-
-# Queries with internal result greater than this value will be logged.
-expensive-threshold = 10000
-
-# Maximum query length recorded in log.
-query-log-max-len = 2048
-
-# File logging.
-[log.file]
-# Log file name.
-filename = ""
-
-# Max log file size in MB (upper limit to 4096MB).
-max-size = 300
-
-# Max log file keep days. No clean up by default.
-max-days = 0
-
-# Maximum number of old log files to retain. No clean up by default.
-max-backups = 0
-
-# Rotate log by day
-log-rotate = true
-
-[security]
-# Path of file that contains list of trusted SSL CAs for connection with mysql client.
-ssl-ca = ""
-
-# Path of file that contains X509 certificate in PEM format for connection with mysql client.
-ssl-cert = ""
-
-# Path of file that contains X509 key in PEM format for connection with mysql client.
-ssl-key = ""
-
-# Path of file that contains list of trusted SSL CAs for connection with cluster components.
-cluster-ssl-ca = ""
-
-# Path of file that contains X509 certificate in PEM format for connection with cluster components.
-cluster-ssl-cert = ""
-
-# Path of file that contains X509 key in PEM format for connection with cluster components.
-cluster-ssl-key = ""
-
-[status]
-# If enable status report HTTP service.
-report-status = true
-
-# TiDB status port.
-status-port = 10080
-
-# Prometheus pushgateway address, leaves it empty will disable prometheus push.
-metrics-addr = "pushgateway:9091"
-
-# Prometheus client push interval in second, set \"0\" to disable prometheus push.
-metrics-interval = 15
-
-[performance]
-# Max CPUs to use, 0 use number of CPUs in the machine.
-max-procs = 0
-# StmtCountLimit limits the max count of statement inside a transaction.
-stmt-count-limit = 5000
-
-# Set keep alive option for tcp connection.
-tcp-keep-alive = true
-
-# The maximum number of retries when commit a transaction.
-retry-limit = 10
-
-# Whether support cartesian product.
-cross-join = true
-
-# Stats lease duration, which influences the time of analyze and stats load.
-stats-lease = "3s"
-
-# Run auto analyze worker on this tidb-server.
-run-auto-analyze = true
-
-# Probability to use the query feedback to update stats, 0 or 1 for always false/true.
-feedback-probability = 0.0
-
-# The max number of query feedback that cache in memory.
-query-feedback-limit = 1024
-
-# Pseudo stats will be used if the ratio between the modify count and
-# row count in statistics of a table is greater than it.
-pseudo-estimate-ratio = 0.7
-
-[proxy-protocol]
-# PROXY protocol acceptable client networks.
-# Empty string means disable PROXY protocol, * means all networks.
-networks = ""
-
-# PROXY protocol header read timeout, unit is second
-header-timeout = 5
-
-[plan-cache]
-enabled = false
-capacity = 2560
-shards = 256
-
-[prepared-plan-cache]
-enabled = false
-capacity = 100
-
-[opentracing]
-# Enable opentracing.
-enable = false
-
-# Whether to enable the rpc metrics.
-rpc-metrics = false
-
-[opentracing.sampler]
-# Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote
-type = "const"
-
-# Param is a value passed to the sampler.
-# Valid values for Param field are:
-# - for "const" sampler, 0 or 1 for always false/true respectively
-# - for "probabilistic" sampler, a probability between 0 and 1
-# - for "rateLimiting" sampler, the number of spans per second
-# - for "remote" sampler, param is the same as for "probabilistic"
-# and indicates the initial sampling rate before the actual one
-# is received from the mothership
-param = 1.0
-
-# SamplingServerURL is the address of jaeger-agent's HTTP sampling server
-sampling-server-url = ""
-
-# MaxOperations is the maximum number of operations that the sampler
-# will keep track of. If an operation is not tracked, a default probabilistic
-# sampler will be used rather than the per operation specific sampler.
-max-operations = 0
-
-# SamplingRefreshInterval controls how often the remotely controlled sampler will poll
-# jaeger-agent for the appropriate sampling strategy.
-sampling-refresh-interval = 0
-
-[opentracing.reporter]
-# QueueSize controls how many spans the reporter can keep in memory before it starts dropping
-# new spans. The queue is continuously drained by a background go-routine, as fast as spans
-# can be sent out of process.
-queue-size = 0
-
-# BufferFlushInterval controls how often the buffer is force-flushed, even if it's not full.
-# It is generally not useful, as it only matters for very low traffic services.
-buffer-flush-interval = 0
-
-# LogSpans, when true, enables LoggingReporter that runs in parallel with the main reporter
-# and logs all submitted spans. Main Configuration.Logger must be initialized in the code
-# for this option to have any effect.
-log-spans = false
-
-#  LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address
-local-agent-host-port = ""
-
-[tikv-client]
-# Max gRPC connections that will be established with each tikv-server.
-grpc-connection-count = 16
-
-# After a duration of this time in seconds if the client doesn't see any activity it pings
-# the server to see if the transport is still alive.
-grpc-keepalive-time = 10
-
-# After having pinged for keepalive check, the client waits for a duration of Timeout in seconds
-# and if no activity is seen even after that the connection is closed.
-grpc-keepalive-timeout = 3
-
-# max time for commit command, must be twice bigger than raft election timeout.
-commit-timeout = "41s"
-
-[binlog]
-
-# Socket file to write binlog.
-binlog-socket = ""
-
-# WriteTimeout specifies how long it will wait for writing binlog to pump.
-write-timeout = "15s"
-
-# If IgnoreError is true, when writing binlog meets error, TiDB would stop writing binlog,
-# but still provide service.
-ignore-error = false
diff --git a/test/e2e-v2/cases/ttl/postgresql/docker-compose.yml b/test/e2e-v2/cases/ttl/postgresql/docker-compose.yml
deleted file mode 100644
index dad2729cd757..000000000000
--- a/test/e2e-v2/cases/ttl/postgresql/docker-compose.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  postgres:
-    image: postgres:13
-    networks:
-      - e2e
-    expose:
-      - 5432
-    environment:
-      - POSTGRES_PASSWORD=123456
-      - POSTGRES_DB=skywalking
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/5432"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  oap:
-    extends:
-      file: ../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: postgresql
-      SW_CORE_DATA_KEEPER_EXECUTE_PERIOD: 1
-      SW_CORE_METRICS_DATA_TTL: 7
-      SW_JDBC_URL: "jdbc:postgresql://postgres:5432/skywalking"
-    depends_on:
-      postgres:
-        condition: service_healthy
-    ports:
-    - 12800
-
-  sender:
-    image: "eclipse-temurin:8-jre"
-    volumes:
-      - ./../../../java-test-service/e2e-mock-sender/target/e2e-mock-sender-2.0.0.jar:/e2e-mock-sender-2.0.0.jar
-    command: [ "java", "-jar", "/e2e-mock-sender-2.0.0.jar" ]
-    environment:
-      OAP_HOST: oap
-      OAP_GRPC_PORT: 11800
-    networks:
-      - e2e
-    ports:
-      - 9093
-    healthcheck:
-      test: ["CMD", "sh", "-c", "nc -nz 127.0.0.1 9093"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    depends_on:
-      oap:
-        condition: service_healthy
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/ttl/postgresql/e2e.yaml b/test/e2e-v2/cases/ttl/postgresql/e2e.yaml
deleted file mode 100644
index b8fc6ed0a849..000000000000
--- a/test/e2e-v2/cases/ttl/postgresql/e2e.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-verify:
-  retry:
-    count: 30
-    interval: 3s
-  cases:
-    - includes:
-        - ../ttl-cases.yaml
diff --git a/test/e2e-v2/cases/ttl/tidb/docker-compose.yml b/test/e2e-v2/cases/ttl/tidb/docker-compose.yml
deleted file mode 100644
index 78f452ab65f9..000000000000
--- a/test/e2e-v2/cases/ttl/tidb/docker-compose.yml
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  tidb:
-    image: pingcap/tidb:v4.0.12
-    expose:
-      - 4000
-    volumes:
-      - ./tidbconfig/tidb.toml:/tidb.toml:ro
-    restart: on-failure
-    healthcheck:
-      test: ["CMD", "sh", "-c", "nc -zn 127.0.0.1 4000"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    networks:
-      - e2e
-
-  oap:
-    extends:
-      file: ../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: tidb
-      SW_CORE_DATA_KEEPER_EXECUTE_PERIOD: 1
-      SW_CORE_METRICS_DATA_TTL: 7
-      SW_JDBC_URL: "jdbc:mysql://tidb:4000/test"
-      SW_DATA_SOURCE_PASSWORD: ""
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    depends_on:
-      tidb:
-        condition: service_healthy
-    ports:
-    - 12800
-
-  sender:
-    image: "eclipse-temurin:8-jre"
-    volumes:
-      - ./../../../java-test-service/e2e-mock-sender/target/e2e-mock-sender-2.0.0.jar:/e2e-mock-sender-2.0.0.jar
-    command: [ "java", "-jar", "/e2e-mock-sender-2.0.0.jar" ]
-    environment:
-      OAP_HOST: oap
-      OAP_GRPC_PORT: 11800
-    networks:
-      - e2e
-    ports:
-      - 9093
-    healthcheck:
-      test: ["CMD", "sh", "-c", "nc -nz 127.0.0.1 9093"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-    depends_on:
-      oap:
-        condition: service_healthy
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/ttl/tidb/e2e.yaml b/test/e2e-v2/cases/ttl/tidb/e2e.yaml
deleted file mode 100644
index b8fc6ed0a849..000000000000
--- a/test/e2e-v2/cases/ttl/tidb/e2e.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-verify:
-  retry:
-    count: 30
-    interval: 3s
-  cases:
-    - includes:
-        - ../ttl-cases.yaml
diff --git a/test/e2e-v2/cases/zipkin/h2/docker-compose.yml b/test/e2e-v2/cases/zipkin/h2/docker-compose.yml
index 6ee4b84d1bd2..2cc4a189fa62 100644
--- a/test/e2e-v2/cases/zipkin/h2/docker-compose.yml
+++ b/test/e2e-v2/cases/zipkin/h2/docker-compose.yml
@@ -36,7 +36,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: h2
-      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+      SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db;DATABASE_TO_UPPER=FALSE
       SW_QUERY_ZIPKIN: default
       SW_RECEIVER_ZIPKIN: default
     expose:
diff --git a/test/e2e-v2/cases/zipkin/mysql/docker-compose.yml b/test/e2e-v2/cases/zipkin/mysql/docker-compose.yml
index 287a97460a97..95b8bd4bab1a 100644
--- a/test/e2e-v2/cases/zipkin/mysql/docker-compose.yml
+++ b/test/e2e-v2/cases/zipkin/mysql/docker-compose.yml
@@ -38,7 +38,7 @@ services:
       service: oap
     environment:
       SW_STORAGE: mysql
-      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest
+      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest?allowMultiQueries=true
       SW_QUERY_ZIPKIN: default
       SW_RECEIVER_ZIPKIN: default
     expose:
diff --git a/test/e2e-v2/cases/zipkin/mysql/sharding/docker-compose.yml b/test/e2e-v2/cases/zipkin/mysql/sharding/docker-compose.yml
deleted file mode 100644
index 0a2fcb6b3746..000000000000
--- a/test/e2e-v2/cases/zipkin/mysql/sharding/docker-compose.yml
+++ /dev/null
@@ -1,102 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  sharding-proxy:
-    extends:
-      file: ../../../../script/shardingsphere-proxy/base-compose.yml
-      service: sharding-proxy
-    networks:
-      - e2e
-    volumes:
-      - ../../../../script/shardingsphere-proxy/conf-mysql:/opt/shardingsphere-proxy/conf
-    expose:
-      - 3307
-    depends_on:
-      mysql-1:
-        condition: service_healthy
-      mysql-2:
-        condition: service_healthy
-
-  mysql-1: &mysql
-    image: mysql/mysql-server:8.0.13
-    networks:
-      - e2e
-    expose:
-      - 3306
-    environment:
-      MYSQL_ROOT_PASSWORD: "root@1234"
-      MYSQL_DATABASE: "swtest"
-      MYSQL_ROOT_HOST: "%"
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-  mysql-2:
-    <<: *mysql
-
-  oap:
-    extends:
-      file: ../../../../script/docker-compose/base-compose.yml
-      service: oap
-    environment:
-      SW_STORAGE: mysql-sharding
-      SW_JDBC_URL: jdbc:mysql://sharding-proxy:3307/swtest
-      SW_JDBC_SHARDING_DATA_SOURCES: ds_0,ds_1
-      SW_CORE_METRICS_DATA_TTL: 2
-      SW_CORE_RECORD_DATA_TTL: 2
-      SW_OTEL_RECEIVER_ENABLED_OTEL_RULES: ""
-      SW_METER_ANALYZER_ACTIVE_FILES: ""
-      SW_LOG_LAL_FILES: ""
-      SW_ENVOY_METRIC: "-"
-      SW_QUERY_ZIPKIN: default
-      SW_RECEIVER_ZIPKIN: default
-    expose:
-      - 9411
-    ports:
-      - 9412
-    entrypoint: ['sh', '-c', '/download-mysql.sh /skywalking/oap-libs && /skywalking/docker-entrypoint.sh']
-    networks:
-      - e2e
-    depends_on:
-      sharding-proxy:
-        condition: service_healthy
-
-  frontend:
-    extends:
-      file: ../../docker-compose-brave.yml
-      service: frontend
-    depends_on:
-      backend:
-        condition: service_healthy
-      oap:
-        condition: service_healthy
-    ports:
-      - 8081
-
-  backend:
-    extends:
-      file: ../../docker-compose-brave.yml
-      service: backend
-    depends_on:
-      oap:
-        condition: service_healthy
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/cases/zipkin/mysql/sharding/e2e.yaml b/test/e2e-v2/cases/zipkin/mysql/sharding/e2e.yaml
deleted file mode 100644
index d3fff5104ecf..000000000000
--- a/test/e2e-v2/cases/zipkin/mysql/sharding/e2e.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-# 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.
-
-# This file is used to show how to write configuration files and can be used to test.
-
-setup:
-  env: compose
-  file: docker-compose.yml
-  timeout: 20m
-  init-system-environment: ../../../../script/env
-  steps:
-    - name: set PATH
-      command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
-    - name: install yq
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh yq
-    - name: install swctl
-      command: bash test/e2e-v2/script/prepare/setup-e2e-shell/install.sh swctl
-
-trigger:
-  action: http
-  interval: 3s
-  times: 10
-  url: http://${frontend_host}:${frontend_8081}
-  method: POST
-
-verify:
-  # verify with retry strategy
-  retry:
-    # max retry count
-    count: 20
-    # the interval between two retries, in millisecond.
-    interval: 10s
-  cases:
-    - includes:
-      - ../../zipkin-cases.yaml
diff --git a/test/e2e-v2/script/docker-compose/base-compose.yml b/test/e2e-v2/script/docker-compose/base-compose.yml
index 4f06f5118f77..1a78645d3ea8 100644
--- a/test/e2e-v2/script/docker-compose/base-compose.yml
+++ b/test/e2e-v2/script/docker-compose/base-compose.yml
@@ -31,7 +31,7 @@ services:
     environment:
       SW_CLUSTER_ZK_HOST_PORT: zk:2181
       SW_STORAGE_ES_CLUSTER_NODES: es:9200
-      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest
+      SW_JDBC_URL: jdbc:mysql://mysql:3306/swtest?allowMultiQueries=true
       SW_STORAGE_INFLUXDB_URL: http://influxdb:8086
       SW_STORAGE_BANYANDB_HOST: "banyandb"
       SW_CONFIG_ETCD_PERIOD: 1
diff --git a/test/e2e-v2/script/prepare/setup-oap/log4j2.xml b/test/e2e-v2/script/prepare/setup-oap/log4j2.xml
index eab9c374158d..2d1b4e4ef8ef 100644
--- a/test/e2e-v2/script/prepare/setup-oap/log4j2.xml
+++ b/test/e2e-v2/script/prepare/setup-oap/log4j2.xml
@@ -24,6 +24,8 @@
         </Console>
     </Appenders>
     <Loggers>
+        <logger name="org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient" level="DEBUG" />
+        <logger name="org.apache.skywalking.oap.server.storage.plugin.jdbc" level="DEBUG" />
         <Root level="INFO">
             <AppenderRef ref="Console"/>
         </Root>
diff --git a/test/e2e-v2/script/shardingsphere-proxy/base-compose.yml b/test/e2e-v2/script/shardingsphere-proxy/base-compose.yml
deleted file mode 100644
index 8f8dc0573509..000000000000
--- a/test/e2e-v2/script/shardingsphere-proxy/base-compose.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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.
-
-version: '2.1'
-
-services:
-  sharding-proxy:
-    image: apache/shardingsphere-proxy:5.3.1
-    volumes:
-      - ./../prepare/setup-oap/download-mysql.sh:/opt/shardingsphere-proxy/download-mysql.sh
-    networks:
-      - e2e
-    expose:
-      - 3307
-    entrypoint: ['sh', '-c', '/opt/shardingsphere-proxy/download-mysql.sh /opt/shardingsphere-proxy/ext-lib && /opt/shardingsphere-proxy/bin/start.sh 3307 && tail -f /opt/shardingsphere-proxy/logs/stdout.log']
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3307"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
-
-networks:
-  e2e:
diff --git a/test/e2e-v2/script/shardingsphere-proxy/conf-mysql/config-sharding.yaml b/test/e2e-v2/script/shardingsphere-proxy/conf-mysql/config-sharding.yaml
deleted file mode 100644
index b3c6dfce25cf..000000000000
--- a/test/e2e-v2/script/shardingsphere-proxy/conf-mysql/config-sharding.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# 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.
-#
-
-######################################################################################################
-# 
-# Here you can configure the rules for the proxy.
-# This example is configuration of sharding rule.
-# 
-######################################################################################################
-#
-databaseName: swtest
-
-dataSources:
- ds_0:
-   url: jdbc:mysql://mysql-1:3306/swtest?allowPublicKeyRetrieval=true
-   username: root
-   password: root@1234
-   connectionTimeoutMilliseconds: 30000
-   idleTimeoutMilliseconds: 60000
-   maxLifetimeMilliseconds: 1800000
-   maxPoolSize: 50
-   minPoolSize: 1
- ds_1:
-   url: jdbc:mysql://mysql-2:3306/swtest?allowPublicKeyRetrieval=true
-   username: root
-   password: root@1234
-   connectionTimeoutMilliseconds: 30000
-   idleTimeoutMilliseconds: 60000
-   maxLifetimeMilliseconds: 1800000
-   maxPoolSize: 50
-   minPoolSize: 1
diff --git a/test/e2e-v2/script/shardingsphere-proxy/conf-mysql/server.yaml b/test/e2e-v2/script/shardingsphere-proxy/conf-mysql/server.yaml
deleted file mode 100644
index 9a738fc1d0f6..000000000000
--- a/test/e2e-v2/script/shardingsphere-proxy/conf-mysql/server.yaml
+++ /dev/null
@@ -1,77 +0,0 @@
-#
-# 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.
-#
-
-######################################################################################################
-#
-# If you want to configure governance, authorization and proxy properties, please refer to this file.
-#
-######################################################################################################
-
-#mode:
-#  type: Cluster
-#  repository:
-#    type: ZooKeeper
-#    props:
-#      namespace: governance_ds
-#      server-lists: localhost:2181
-#      retryIntervalMilliseconds: 500
-#      timeToLiveSeconds: 60
-#      maxRetries: 3
-#      operationTimeoutMilliseconds: 500
-#
-#authority:
-#  users:
-#    - user: root@%
-#      password: root
-#  privilege:
-#    type: ALL_PERMITTED
-
-transaction:
-  defaultType: LOCAL
-
-sqlParser:
-  sqlCommentParseEnabled: true
-  sqlStatementCache:
-    initialCapacity: 2000
-    maximumSize: 65535
-  parseTreeCache:
-    initialCapacity: 128
-    maximumSize: 1024
-
-props:
-  max-connections-size-per-query: 1
-  kernel-executor-size: 16  # Infinite by default.
-  proxy-frontend-flush-threshold: 128  # The default value is 128.
-  proxy-hint-enabled: true
-  sql-show: false
-  check-table-metadata-enabled: false
-  show-process-list-enabled: false
-    # Proxy backend query fetch size. A larger value may increase the memory usage of ShardingSphere Proxy.
-  # The default value is -1, which means set the minimum value for different JDBC drivers.
-  proxy-backend-query-fetch-size: -1
-  check-duplicate-table-enabled: false
-  proxy-frontend-executor-size: 0 # Proxy frontend executor size. The default value is 0, which means let Netty decide.
-    # Available options of proxy backend executor suitable: OLAP(default), OLTP. The OLTP option may reduce time cost of writing packets to client, but it may increase the latency of SQL execution
-  # and block other clients if client connections are more than `proxy-frontend-executor-size`, especially executing slow SQL.
-  proxy-backend-executor-suitable: OLAP
-  proxy-frontend-max-connections: 0 # Less than or equal to 0 means no limitation.
-  sql-federation-enabled: false
-  # Available proxy backend driver type: JDBC (default), ExperimentalVertx
-  proxy-backend-driver-type: JDBC
-  proxy-mysql-default-version: 8.0.13 # In the absence of schema name, the default version will be used.
-  proxy-default-port: 3307 # Proxy default port.
-  proxy-netty-backlog: 1024 # Proxy netty backlog.