Repository: apache/skywalking (language: python)

Issue:
[Feature] Add new metric `type=STANDARD_VALUE`
### 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

After we brought MQE into the key query feature and OTEL monitoring integration as an important eco-system, we noticed the labeled value we have is too simple. Currently, it is just one label with its value. You can't do multiple labels in the persistence. In the previous solution, we connect the remained labels as a new label.

Such
![image](https://github.com/apache/skywalking/assets/5441976/afe1bc17-4eda-4b5e-9c66-3e14a2676f37)

In the query stage, although we have MQE system, we still can't merge the metric on-demand to get per instance or per error_code. The hands of system capabilities are tired.

### Use case

The typical use cases mentioned in [[Bug] Metrics are not aggregated properly as OTEL collector targeting per node](https://github.com/apache/skywalking/issues/11982). To support that, we were trying to use the existing labeled valued, but it is not powerful enough.

The new proposal is adding a new metric type, `type=STANDARD_VALUE`. The data is assembled like a MQEValues, which includes entity, labels and value.

https://github.com/apache/skywalking-query-protocol/blob/f0bdba688afecff2167d018ecdaf509d2c8598f7/metrics-v3.graphqls#L70-L78

___

This data should be hosted through a new implementation of **StorageDataComplexObject**, but not `DataTable`. Because of this, this metric can't be queried out by v1 and v2 query APIs. Users have to use MQE system and syntax. 

Note, as this is a new metric type, the MQE implementation on the alerting side should be supported too. `LabeledValueHolder` is not enough, we need a new `StandardValueHolder`.

About the UI side, the current UI is easily using `metric.labels[0].value` to show the only label. In the use case, the logic should be, that if the label key is `_` and there is only one key, the logic keeps the same, otherwise, if there are multiple key-value pairs in the MQE return, it should combine them to visualize like `key1=value key2=value2...`



### Related issues

_No response_

### Are you willing to submit a pull request to implement this on your own?

- [ ] Yes I am willing to submit a pull request on my own!

### Code of Conduct

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



Discussion / hints:
I think it's related to https://github.com/apache/skywalking/issues/11982#issuecomment-1980247042.
If we support multiple labels, `aggregate_labels ` should support aggregation based on specified labels, we can aggregate results through specified labels to get accurate service level metrics
> I think it's related to [#11982 (comment)](https://github.com/apache/skywalking/issues/11982#issuecomment-1980247042). If we support multiple labels, `aggregate_labels ` should support aggregation based on specified labels, we can aggregate results through specified labels and preserve other labels at the same time to get accurate service level metrics

Yes, that could be a use case. FYI @wankai123 
About adding a new `type=STANDARD_VALUE`, another option is, we re-implemented the labeled value metric. Only treat today LABELED_VALUE and **DataTable** as special cases of the multiple labels feature. 
Let's see whether this is possible in codes.

Fix patch:
diff --git a/dist-material/alarm-settings.yml b/dist-material/alarm-settings.yml
index ce55ab88e826..51c775d8aeb1 100644
--- a/dist-material/alarm-settings.yml
+++ b/dist-material/alarm-settings.yml
@@ -37,7 +37,7 @@ rules:
     silence-period: 3
     message: Successful rate of service {name} is lower than 80% in 2 minutes of last 10 minutes
   service_resp_time_percentile_rule:
-    expression: sum(service_percentile{_='0,1,2,3,4'} > 1000) >= 3
+    expression: sum(service_percentile{p='50,75,90,95,99'} > 1000) >= 3
     period: 10
     silence-period: 5
     message: Percentile response time of service {name} alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000
diff --git a/docs/en/api/metrics-query-expression.md b/docs/en/api/metrics-query-expression.md
index a3b717887d56..fa2446e2979d 100644
--- a/docs/en/api/metrics-query-expression.md
+++ b/docs/en/api/metrics-query-expression.md
@@ -27,21 +27,27 @@ service_sla
 The `ExpressionResultType` of the expression is `TIME_SERIES_VALUES`.
 
 ### Labeled Value Metrics
-For now, we only have a single anonymous label with multi label values in a labeled metric. 
-To be able to use it in expressions, define `_` as the anonymous label name (key).
+Since v10.0.0, SkyWalking supports multiple labels metrics.
+We could query the specific labels of the metric by the following expression.
 
 Expression:
 ```text
-<metric_name>{_='<label_value_1>,...'}
+<metric_name>{<label1_name>='<label1_value_1>,...', <label2_name>='<label2_value_1>,...',<label2...}
 ```
-`{_='<label_value_1>,...'}` is the selected label value of the metric. If is not specified, all label values of the metric will be selected. 
+`{<label1_name>='<label_value_1>,...'}` is the selected label name/value of the metric. If is not specified, all label values of the metric will be selected. 
 
 For example:
-If we want to query the `service_percentile` metric with the label values `0,1,2,3,4`, we can use the following expression:
+The `k8s_cluster_deployment_status` metric has labels `namespace`, `deployment` and `status`.
+If we want to query all deployment metric value with `namespace=skywalking-showcase` and `status=true`, we can use the following expression:
 ```text
-service_percentile{_='0,1,2,3,4'}
+k8s_cluster_deployment_status{namespace='skywalking-showcase', status='true'}
 ```
 
+We also could query the label with multiple values by separating the values with `,`:
+If we want to query the `service_percentile` metric with the label name `p` and values `50,75,90,95,99`, we can use the following expression:
+```text
+service_percentile{p='50,75,90,95,99'}
+```
 If we want to rename the label values to `P50,P75,P90,P95,P99`, see [Relabel Operation](#relabel-operation).
 
 #### Result Type
@@ -233,19 +239,23 @@ According to the type of the metric, the `ExpressionResultType` of the expressio
 
 ## Relabel Operation
 Relabel Operation takes an expression and replaces the label values with new label values on its results.
+Since v10.0.0, SkyWalking supports relabel multiple labels.
 
 Expression:
 ```text
-relabel(Expression, _='<new_label_value_1>,...')
+relabel(Expression, <target_label_name>='<origin_label_value_1>,...', <new_label_name>='<new_label_value_1>,...')
 ```
 
-`_` is the new label of the metric after the label is relabeled, the order of the new label values should be the same as the order of the label values in the input expression result.
+The order of the new label values should be the same as the order of the label values in the input expression result.
 
 For example:
-If we want to query the `service_percentile` metric with the label values `0,1,2,3,4`, and rename the label values to `P50,P75,P90,P95,P99`, we can use the following expression:
+If we want to query the `service_percentile` metric with the label values `50,75,90,95,99`, and rename the label name to `percentile` and the label values to `P50,P75,P90,P95,P99`, we can use the following expression:
 
 ```text
-relabel(service_percentile{_='0,1,2,3,4'}, _='P50,P75,P90,P95,P99')
+and rename the label values to `P50,P75,P90,P95,P99`, we can use the following expression:
+
+```text
+relabel(service_percentile{p='50,75,90,95,99'}, p='50,75,90,95,99', percentile='P50,P75,P90,P95,P99')
 ```
 
 ### Result Type
@@ -256,22 +266,30 @@ AggregateLabels Operation takes an expression and performs an aggregate calculat
 
 Expression:
 ```text
-aggregate_labels(Expression, parameter)
+aggregate_labels(Expression, AggregateType<Optional>(<label1_name>,<label2_name>...))
 ```
 
-| parameter | Definition                                          | ExpressionResultType |
-|-----------|-----------------------------------------------------|----------------------|
-| avg       | calculate avg value of a `Labeled Value Metrics`    | TIME_SERIES_VALUES   |
-| sum       | calculate sum value of a `Labeled Value Metrics`    | TIME_SERIES_VALUES   |
-| max       | select the maximum value from a `Labeled Value Metrics` | TIME_SERIES_VALUES   |
-| min       | select the minimum value from a `Labeled Value Metrics` | TIME_SERIES_VALUES   |
+- `AggregateType` is the type of the aggregation operation.
+- `<label1_name>,<label2_name>...` is the label names that need to be aggregated. If not specified, all labels will be aggregated.
+
+| AggregateType | Definition                                         | ExpressionResultType |
+|---------------|----------------------------------------------------|----------------------|
+| avg           | calculate avg value of a `Labeled Value Metrics`   | TIME_SERIES_VALUES   |
+| sum           | calculate sum value of a `Labeled Value Metrics`   | TIME_SERIES_VALUES   |
+| max           | select the maximum value from a `Labeled Value Metrics` | TIME_SERIES_VALUES   |
+| min           | select the minimum value from a `Labeled Value Metrics` | TIME_SERIES_VALUES   |
 
 For example:
 If we want to query all Redis command total rates, we can use the following expression(`total_commands_rate` is a metric which recorded every command rate in labeled value):
-
+Aggregating all the labels:
 ```text
 aggregate_labels(total_commands_rate, sum)
 ```
+Also, we can aggregate by the `cmd` label:
+
+```text
+aggregate_labels(total_commands_rate, sum(cmd))
+```
 
 ### Result Type
 The ExpressionResultType of the aggregateLabels operation is TIME_SERIES_VALUES.
@@ -357,7 +375,7 @@ TIME_SERIES_VALUES.
 ## Expression Query Example
 ### Labeled Value Metrics
 ```text
-service_percentile{_='0,1'}
+service_percentile{p='50,95'}
 ```
 The example result is:
 ```json
@@ -369,13 +387,13 @@ The example result is:
       "results": [
         {
           "metric": {
-            "labels": [{"key": "_", "value": "0"}]
+            "labels": [{"key": "p", "value": "50"}]
           },
           "values": [{"id": "1691658000000", "value": "1000", "traceID": null}, {"id": "1691661600000", "value": 2000, "traceID": null}]
         },
         {
           "metric": {
-            "labels": [{"key": "_", "value": "1"}]
+            "labels": [{"key": "p", "value": "75"}]
           },
           "values": [{"id": "1691658000000", "value": "2000", "traceID": null}, {"id": "1691661600000", "value": 3000, "traceID": null}]
         }
@@ -386,7 +404,7 @@ The example result is:
 ```
 If we want to transform the percentile value unit from `ms` to `s` the expression is:
 ```text
-service_percentile{_='0,1'} / 1000
+service_percentile{p='50,75'} / 1000
 ```
 ```json
 {
@@ -397,13 +415,13 @@ service_percentile{_='0,1'} / 1000
       "results": [
         {
           "metric": {
-            "labels": [{"key": "_", "value": "0"}]
+            "labels": [{"key": "p", "value": "50"}]
           },
           "values": [{"id": "1691658000000", "value": "1", "traceID": null}, {"id": "1691661600000", "value": 2, "traceID": null}]
         },
         {
           "metric": {
-            "labels": [{"key": "_", "value": "1"}]
+            "labels": [{"key": "p", "value": "75"}]
           },
           "values": [{"id": "1691658000000", "value": "2", "traceID": null}, {"id": "1691661600000", "value": 3, "traceID": null}]
         }
@@ -414,7 +432,7 @@ service_percentile{_='0,1'} / 1000
 ```
 Get the average value of each percentile, the expression is:
 ```text
-avg(service_percentile{_='0,1'})
+avg(service_percentile{p='50,75'})
 ```
 ```json
 {
@@ -425,13 +443,13 @@ avg(service_percentile{_='0,1'})
       "results": [
         {
           "metric": {
-            "labels": [{"key": "_", "value": "0"}]
+            "labels": [{"key": "p", "value": "50"}]
           },
           "values": [{"id": null, "value": "1500", "traceID": null}]
         },
         {
           "metric": {
-            "labels": [{"key": "_", "value": "1"}]
+            "labels": [{"key": "p", "value": "75"}]
           },
           "values": [{"id": null, "value": "2500", "traceID": null}]
         }
@@ -442,7 +460,7 @@ avg(service_percentile{_='0,1'})
 ```
 Calculate the difference between the percentile and the average value, the expression is:
 ```text
-service_percentile{_='0,1'} - avg(service_percentile{_='0,1'})
+service_percentile{p='50,75'} - avg(service_percentile{p='50,75'})
 ```
 ```json
 {
@@ -453,13 +471,13 @@ service_percentile{_='0,1'} - avg(service_percentile{_='0,1'})
       "results": [
         {
           "metric": {
-            "labels": [{"key": "_", "value": "0"}]
+            "labels": [{"key": "p", "value": "50"}]
           },
           "values": [{"id": "1691658000000", "value": "-500", "traceID": null}, {"id": "1691661600000", "value": 500, "traceID": null}]
         },
         {
           "metric": {
-            "labels": [{"key": "_", "value": "1"}]
+            "labels": [{"key": "p", "value": "75"}]
           },
           "values": [{"id": "1691658000000", "value": "-500", "traceID": null}, {"id": "1691661600000", "value": 500, "traceID": null}]
         }
@@ -489,7 +507,7 @@ Calculate the difference between the `service_resp_time` and the `service_percen
 ```
 The expression is:
 ```text
-service_resp_time - service_percentile{_='0,1'}
+service_resp_time - service_percentile{p='50,75'}
 ```
 ```json
 {
@@ -500,13 +518,13 @@ service_resp_time - service_percentile{_='0,1'}
       "results": [
         {
           "metric": {
-            "labels": [{"key": "_", "value": "0"}]
+            "labels": [{"key": "p", "value": "50"}]
           },
           "values": [{"id": "1691658000000", "value": "1500", "traceID": null}, {"id": "1691661600000", "value": "1500", "traceID": null}]
         },
         {
           "metric": {
-            "labels": [{"key": "_", "value": "1"}]
+            "labels": [{"key": "p", "value": "75"}]
           },
           "values": [{"id": "1691658000000", "value": "500", "traceID": null}, {"id": "1691661600000", "value": "500", "traceID": null}]
         }
diff --git a/docs/en/api/promql-service.md b/docs/en/api/promql-service.md
index 686b5599c3da..a610a9ddaa42 100644
--- a/docs/en/api/promql-service.md
+++ b/docs/en/api/promql-service.md
@@ -269,11 +269,11 @@ Result:
 GET|POST /api/v1/labels
 ```
 
-| Parameter | Definition      | Support | Optional |
-|-----------|-----------------|---------|----------|
-| match[]   | series selector | yes     | yes      |
-| start     | start timestamp | **no**  | yes      |
-| end       | end timestamp   | **no**  | yes      |
+| Parameter | Definition                                                                      | Support | Optional |
+|-----------|---------------------------------------------------------------------------------|---------|----------|
+| match[]   | series selector                                                                 | yes     | yes      |
+| start     | start timestamp                                                                 | **no**  | yes      |
+| end       | end timestamp, if end time is not present, use current time as default end time | yes     | yes      |
 
 For example:
 ```text
@@ -300,11 +300,11 @@ Result:
 GET /api/v1/label/<label_name>/values
 ```
 
-| Parameter | Definition      | Support | Optional |
-|-----------|-----------------|---------|----------|
-| match[]   | series selector | yes     | no       |
-| start     | start timestamp | **no**  | yes      |
-| end       | end timestamp   | **no**  | yes      |
+| Parameter | Definition                                                                      | Support | Optional |
+|-----------|---------------------------------------------------------------------------------|---------|----------|
+| match[]   | series selector                                                                 | yes     | yes      |
+| start     | start timestamp                                                                 | **no**  | yes      |
+| end       | end timestamp, if end time is not present, use current time as default end time | yes     | yes      |
 
 For example:
 ```text
@@ -446,14 +446,12 @@ service_cpm{service='agent::songs', layer='GENERAL'}
 - Query Labels:
 ```text
 --{General labels}
---labels: Used to filter the value labels to be returned
---relabels: Used to rename the returned value labels
-note: The number and order of labels must match the number and order of relabels.
+--metric labels: Used to filter the value labels to be returned
 ```
 
 - Expression Example:
 ```text
-service_percentile{service='agent::songs', layer='GENERAL', labels='0,1,2', relabels='P50,P75,P90'}
+service_percentile{service='agent::songs', layer='GENERAL', p='50,75,90'}
 ```
 
 - Result (Instant Query):
@@ -466,7 +464,7 @@ service_percentile{service='agent::songs', layer='GENERAL', labels='0,1,2', rela
       {
         "metric": {
           "__name__": "service_percentile",
-          "label": "P50",
+          "p": "50",
           "layer": "GENERAL",
           "scope": "Service",
           "service": "agent::songs"
@@ -479,7 +477,7 @@ service_percentile{service='agent::songs', layer='GENERAL', labels='0,1,2', rela
       {
         "metric": {
           "__name__": "service_percentile",
-          "label": "P75",
+          "p": "75",
           "layer": "GENERAL",
           "scope": "Service",
           "service": "agent::songs"
@@ -492,7 +490,7 @@ service_percentile{service='agent::songs', layer='GENERAL', labels='0,1,2', rela
       {
         "metric": {
           "__name__": "service_percentile",
-          "label": "P90",
+          "p": "90",
           "layer": "GENERAL",
           "scope": "Service",
           "service": "agent::songs"
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 7a8b2365a355..d23ae7e0aae5 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -81,6 +81,18 @@
 * Support displaying the port services listen to from OAP and UI during server start.
 * Refactor data-generator to support generating metrics.
 * Fix `AvgHistogramPercentileFunction` legacy name.
+* [Break Change] Labeled Metrics support multiple labels.
+  - Storage: store all label names and values instead of only the values.
+  - MQE: 
+    - Support querying by multiple labels(name and value) instead using `_` as the anonymous label name.
+    - `aggregate_labels` function support aggregate by specific labels.
+    - `relabels` function require target label and rename label name and value.
+  - PromQL:
+    - Support querying by multiple labels(name and value) instead using `lables` as the anonymous label name.
+    - Remove general labels `labels/relabels/label` function.
+    - API `/api/v1/labels` and `/api/v1/label/<label_name>/values` support return matched metrics labels.
+  - OAL:
+    - Deprecate `percentile` function and introduce `percentile2` function instead.
 
 #### UI
 
diff --git a/docs/en/concepts-and-designs/oal.md b/docs/en/concepts-and-designs/oal.md
index 704529a2469b..1f88901b90e8 100644
--- a/docs/en/concepts-and-designs/oal.md
+++ b/docs/en/concepts-and-designs/oal.md
@@ -94,9 +94,10 @@ Parameter (1) is the service name, which reflects the Apdex threshold value load
 Parameter (2) is the status of this request. The status(success/failure) reflects the Apdex calculation.
 
 - `p99`, `p95`, `p90`, `p75`, `p50`. See [percentile in WIKI](https://en.wikipedia.org/wiki/Percentile).
-> service_percentile = from(Service.latency).percentile(10);
+> service_percentile = from(Service.latency).percentile2(10);
 
-**percentile** is the first multiple-value metric, which has been introduced since 7.0.0. As a metric with multiple values, it could be queried through the `getMultipleLinearIntValues` GraphQL query.
+**percentile (deprecated since 10.0.0)** is the first multiple-value metric, which has been introduced since 7.0.0. As a metric with multiple values, it could be queried through the `getMultipleLinearIntValues` GraphQL query.
+**percentile2** Since 10.0.0, the `percentile` function has been instead by `percentile2`. The `percentile2` function is a labeled-value metric with default label name `p` and label values `50`,`75`,`90`,`95`,`99`.
 In this case, see `p99`, `p95`, `p90`, `p75`, and `p50` of all incoming requests. The parameter is precise to a latency at p99, such as in the above case, and 120ms and 124ms are considered to produce the same response time.
 
 In this case, the p99 value of all incoming requests. The parameter is precise to a latency at p99, such as in the above case, and 120ms and 124ms are considered to produce the same response time.
@@ -146,7 +147,7 @@ serv_Endpoint_p99 = from(Endpoint.latency).filter(name like "serv%").summary(0.9
 endpoint_resp_time = from(Endpoint.latency).avg()
 
 // Calculate the p50, p75, p90, p95 and p99 of each Endpoint by 50 ms steps.
-endpoint_percentile = from(Endpoint.latency).percentile(10)
+endpoint_percentile = from(Endpoint.latency).percentile2(10)
 
 // Calculate the percent of response status is true, for each service.
 endpoint_success = from(Endpoint.*).filter(status == true).percent()
diff --git a/docs/en/setup/backend/backend-alarm.md b/docs/en/setup/backend/backend-alarm.md
index 85360db33195..a80aa697f88a 100644
--- a/docs/en/setup/backend/backend-alarm.md
+++ b/docs/en/setup/backend/backend-alarm.md
@@ -53,7 +53,7 @@ the calculation is `((1001 + 10001 + ... + 1001) / 7) > 1000` and the result wou
 * In every minute, the window would shift automatically. At T8, Value8 would be cached, and T1/Value1 would be removed from the window.
 
 **NOTE**: 
-* If the expression include labeled metrics and result has multiple labeled value(e.g. `sum(service_percentile{_='0,1'} > 1000) >= 3`), the alarm will be triggered if any of the labeled value result matches 3 times of the condition(P50 > 1000 or P75 > 1000).
+* If the expression include labeled metrics and result has multiple labeled value(e.g. `sum(service_percentile{p='50,75'} > 1000) >= 3`), the alarm will be triggered if any of the labeled value result matches 3 times of the condition(P50 > 1000 or P75 > 1000).
 * One alarm rule is targeting the same entity level, such as service-level expression (`avg(service_resp_time) > 1000`).
   Set entity names(Include/Exclude names...) according to metrics entity levels,
   do not include different entity levels metrics in the same expression, such as service metrics and endpoint metrics.
@@ -82,7 +82,7 @@ rules:
     period: 10
     message: Service {name} successful rate is less than 85%
   service_resp_time_percentile_rule:
-    expression: sum(service_percentile{_='0,1,2,3,4'} > 1000) >= 3
+    expression: sum(service_percentile{p='50,75,90,95,99'} > 1000) >= 3
     period: 10
     silence-period: 5
     message: Percentile response time of service {name} alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000
diff --git a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java
index 27a203c578f0..82af27879fd6 100644
--- a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java
+++ b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/Analyzer.java
@@ -58,6 +58,7 @@
 import org.apache.skywalking.oap.server.core.analysis.meter.function.AcceptableValue;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.BucketedValues;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.PercentileArgument;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 
@@ -147,8 +148,11 @@ public void analyse(final ImmutableMap<String, SampleFamily> sampleFamilies) {
                 case labeled:
                     AcceptableValue<DataTable> lv = meterSystem.buildMetrics(metricName, DataTable.class);
                     DataTable dt = new DataTable();
+                    // put all labels into the data table.
                     for (Sample each : ss) {
-                        dt.put(composeGroup(each.getLabels()), getValue(each));
+                        DataLabel dataLabel = new DataLabel();
+                        dataLabel.putAll(each.getLabels());
+                        dt.put(dataLabel, getValue(each));
                     }
                     lv.accept(meterEntity, dt);
                     send(lv, ss[0].getTimestamp());
@@ -203,10 +207,6 @@ private long getValue(Sample sample) {
         return Math.round(sample.getValue());
     }
 
-    private String composeGroup(ImmutableMap<String, String> labels) {
-        return composeGroup(labels, k -> true);
-    }
-
     private String composeGroup(ImmutableMap<String, String> labels, Predicate<String> filter) {
         return labels.keySet().stream().filter(filter).sorted().map(labels::get)
                      .collect(Collectors.joining("-"));
diff --git a/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4 b/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4
index ecd3ddc5d9ab..b274621717ee 100644
--- a/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4
+++ b/oap-server/mqe-grammar/src/main/antlr4/org/apache/skywalking/mqe/rt/grammar/MQEParser.g4
@@ -34,13 +34,12 @@ expression
     | trend L_PAREN metric COMMA INTEGER R_PAREN #trendOP
     | logical_operator L_PAREN expressionList R_PAREN #logicalOperatorOP
     | topN L_PAREN metric COMMA INTEGER COMMA order R_PAREN  #topNOP
-    | relabels L_PAREN expression COMMA label R_PAREN #relablesOP
+    | relabels L_PAREN expression COMMA label COMMA replaceLabel R_PAREN #relablesOP
     | aggregateLabels L_PAREN expression COMMA aggregateLabelsFunc R_PAREN #aggregateLabelsOp
     ;
 
 expressionList
-    : expression (COMMA expression)*
-    ;
+    : expression (COMMA expression)*;
 
 expressionNode:  metric| scalar;
 
@@ -49,14 +48,15 @@ mulDivMod:       MUL | DIV | MOD;
 compare:        (DEQ | NEQ | LTE | LT | GTE | GT) BOOL?;
 
 metricName:      NAME_STRING;
-metric:   metricName | metricName L_BRACE label? R_BRACE;
+metric:   metricName | metricName L_BRACE labelList? R_BRACE;
 
-//For now, we only have a single anonymous label with multi label values in a labeled metric.
-//To be able to use it in expressions, define `_` as the anonymous label name (key).
-labelName:       GENERAL_LABEL_NAME;
+labelName:       NAME_STRING | GENERAL_LABEL_NAME;
+labelNameList:   labelName (COMMA labelName)*;
 labelValue:      VALUE_STRING;
 label:           labelName EQ labelValue;
+labelList:       label (COMMA label)*;
 
+replaceLabel:    label;
 
 scalar:   INTEGER | DECIMAL;
 
@@ -87,5 +87,7 @@ order: ASC | DES;
 aggregateLabels:
     AGGREGATE_LABELS;
 
-aggregateLabelsFunc:
+aggregateLabelsFunc: aggregateLabelsFuncName (L_PAREN labelNameList R_PAREN)?;
+
+aggregateLabelsFuncName:
     AVG | SUM | MAX | MIN;
diff --git a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java
index 235abb30c88b..a07bd9499355 100644
--- a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java
+++ b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/MQEVisitorBase.java
@@ -18,9 +18,10 @@
 
 package org.apache.skywalking.mqe.rt;
 
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.mqe.rt.grammar.MQEParser;
 import org.apache.skywalking.mqe.rt.grammar.MQEParserBaseVisitor;
@@ -38,11 +39,11 @@
 import org.apache.skywalking.mqe.rt.type.MQEValues;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.query.enumeration.Step;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 
 @Slf4j
 public abstract class MQEVisitorBase extends MQEParserBaseVisitor<ExpressionResult> {
-    public final static String GENERAL_LABEL_NAME = "_";
     public final Step queryStep;
 
     protected MQEVisitorBase(final Step queryStep) {
@@ -141,7 +142,28 @@ public ExpressionResult visitAggregateLabelsOp(final MQEParser.AggregateLabelsOp
         }
 
         try {
-            return AggregateLabelsOp.doAggregateLabelsOp(expResult, funcType);
+            if (expResult.getResults().isEmpty()) {
+                return expResult;
+            }
+            List<String> labelNames = new ArrayList<>();
+            MQEParser.LabelNameListContext labelNameListContext = ctx.aggregateLabelsFunc().labelNameList();
+            if (null != labelNameListContext) {
+                for (MQEParser.LabelNameContext labelNameContext : labelNameListContext.labelName()) {
+                    if (expResult.getResults()
+                                 .get(0)
+                                 .getMetric()
+                                 .getLabels()
+                                 .stream()
+                                 .anyMatch(label -> label.getKey().equals(labelNameContext.getText()))) {
+                        labelNames.add(labelNameContext.getText());
+                    } else {
+                        expResult.setError(
+                            "The label [" + labelNameContext.getText() + "] does not exist in the result.");
+                        return expResult;
+                    }
+                }
+            }
+            return AggregateLabelsOp.doAggregateLabelsOp(expResult, funcType, labelNames);
         } catch (IllegalExpressionException e) {
             ExpressionResult result = new ExpressionResult();
             result.setType(ExpressionResultType.UNKNOWN);
@@ -197,25 +219,37 @@ public ExpressionResult visitRelablesOP(MQEParser.RelablesOPContext ctx) {
             result.setError("The result of expression [" + ctx.expression().getText() + "] is not a labeled result.");
             return result;
         }
+        KeyValue targetLabel = buildLabel(ctx.label());
+        KeyValue replaceLabel = buildLabel(ctx.replaceLabel().label());
 
-        List<String> relabelList = Collections.emptyList();
-        String newLabelValue = ctx.label().labelValue().getText();
-        String labelValueTrim = newLabelValue.substring(1, newLabelValue.length() - 1);
-        if (StringUtil.isNotBlank(labelValueTrim)) {
-            relabelList = Arrays.asList(labelValueTrim.split(Const.COMMA));
-        }
-        List<MQEValues> mqeValuesList = result.getResults();
+//        if (!targetLabel.getKey().equals(replaceLabel.getKey())) {
+//            result.setError("The target label name and replace label name must be the same.");
+//            return result;
+//        }
+        List<KeyValue> targetLabels = parseLabelValue(targetLabel, Const.COMMA);
+        List<KeyValue> replaceLabels = parseLabelValue(replaceLabel, Const.COMMA);
 
-        if (mqeValuesList.size() != relabelList.size()) {
-            // Reserve the original result type
-            result.setError("The number of relabels is not equal to the number of labels.");
+        Map<KeyValue, KeyValue> relabelMap = new HashMap<>();
+        if (targetLabels.isEmpty() || replaceLabels.isEmpty()) {
+            return result;
+        }
+        if (targetLabels.size() != replaceLabels.size()) {
+            result.setError(
+                "Targrt label [" + targetLabel.getKey() + "]: the number of relabel values is not equal to the number of replace label.");
             return result;
         }
-        // For now, we only have a single label named `label`
-        for (int i = 0; i < mqeValuesList.size(); i++) {
-            mqeValuesList.get(i).getMetric().getLabels().get(0).setValue(relabelList.get(i));
+        for (int i = 0; i < targetLabels.size(); i++) {
+            relabelMap.put(targetLabels.get(i), replaceLabels.get(i));
+        }
+        for (MQEValues mqeValues : result.getResults()) {
+            for (KeyValue label : mqeValues.getMetric().getLabels()) {
+                if (relabelMap.containsKey(label)) {
+                    KeyValue replaceLabelValue = relabelMap.get(label);
+                    label.setKey(replaceLabelValue.getKey());
+                    label.setValue(replaceLabelValue.getValue());
+                }
+            }
         }
-
         return result;
     }
 
@@ -287,4 +321,38 @@ public ExpressionResult visitTrendOP(MQEParser.TrendOPContext ctx) {
 
     @Override
     public abstract ExpressionResult visitMetric(MQEParser.MetricContext ctx);
+
+    protected KeyValue buildLabel(MQEParser.LabelContext ctx) {
+        String labelName = ctx.labelName().getText();
+        String labelValue = ctx.labelValue().getText();
+        String labelValueTrim = labelValue.substring(1, labelValue.length() - 1);
+        return new KeyValue(labelName, labelValueTrim);
+    }
+
+    protected List<KeyValue> buildLabels(MQEParser.LabelListContext ctx) {
+        List<KeyValue> labels = new ArrayList<>();
+        if (ctx != null) {
+            for (MQEParser.LabelContext labelContext : ctx.label()) {
+                labels.add(buildLabel(labelContext));
+            }
+        }
+        return labels;
+    }
+
+    protected List<KeyValue> parseLabelValue(KeyValue keyValue, String separator) {
+        List<KeyValue> labels = new ArrayList<>();
+        if (keyValue != null) {
+            if (StringUtil.isNotBlank(keyValue.getValue())) {
+                if (keyValue.getValue().indexOf(separator) > 0) {
+                    String[] subValues = keyValue.getValue().split(separator);
+                    for (String subValue : subValues) {
+                        labels.add(new KeyValue(keyValue.getKey(), subValue));
+                    }
+                } else {
+                    labels.add(keyValue);
+                }
+            }
+        }
+        return labels;
+    }
 }
diff --git a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/AggregateLabelsOp.java b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/AggregateLabelsOp.java
index 7ae816a84c72..fbcf3e4e61b7 100644
--- a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/AggregateLabelsOp.java
+++ b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/AggregateLabelsOp.java
@@ -18,7 +18,7 @@
 
 package org.apache.skywalking.mqe.rt.operation;
 
-import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
 import org.apache.skywalking.mqe.rt.exception.IllegalExpressionException;
 import org.apache.skywalking.mqe.rt.grammar.MQEParser;
@@ -32,60 +32,86 @@
 import org.apache.skywalking.mqe.rt.operation.aggregatelabels.MinAggregateLabelsFunc;
 import org.apache.skywalking.mqe.rt.operation.aggregatelabels.SumAggregateLabelsFunc;
 import org.apache.skywalking.mqe.rt.type.Metadata;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toList;
+
 public class AggregateLabelsOp {
 
     public static ExpressionResult doAggregateLabelsOp(ExpressionResult result,
-                                                       int funcType) throws IllegalExpressionException {
+                                                       int funcType,
+                                                       List<String> labelNames) throws IllegalExpressionException {
         switch (funcType) {
             case MQEParser.AVG:
-                return aggregateLabeledValueResult(result, AvgAggregateLabelsFunc::new);
+                return aggregateLabeledValueResult(result, labelNames, AvgAggregateLabelsFunc::new);
             case MQEParser.SUM:
-                return aggregateLabeledValueResult(result, SumAggregateLabelsFunc::new);
+                return aggregateLabeledValueResult(result, labelNames, SumAggregateLabelsFunc::new);
             case MQEParser.MAX:
-                return aggregateLabeledValueResult(result, MaxAggregateLabelsFunc::new);
+                return aggregateLabeledValueResult(result, labelNames, MaxAggregateLabelsFunc::new);
             case MQEParser.MIN:
-                return aggregateLabeledValueResult(result, MinAggregateLabelsFunc::new);
+                return aggregateLabeledValueResult(result, labelNames, MinAggregateLabelsFunc::new);
             default:
                 throw new IllegalExpressionException("Unsupported aggregateLabels function.");
         }
     }
 
     private static ExpressionResult aggregateLabeledValueResult(ExpressionResult expResult,
+                                                                List<String> labelNames,
                                                                 AggregateLabelsFuncFactory factory) {
         List<MQEValues> results = expResult.getResults();
         if (CollectionUtils.isEmpty(results)) {
             return expResult;
         }
 
-        List<MQEValue> combineTo = results.get(0).getValues();
-        for (int i = 0; i < combineTo.size(); i++) {
-            AggregateLabelsFunc aggregateLabelsFunc = factory.getAggregateLabelsFunc();
-            for (MQEValues result : results) {
-                MQEValue toCombine = result.getValues().get(i);
-                if (!toCombine.isEmptyValue()) {
-                    aggregateLabelsFunc.combine(toCombine.getDoubleValue());
-                }
+        LinkedHashMap<List<KeyValue>, List<MQEValues>> groupedResult = results.stream().collect(groupingBy(mqeValues -> getLabels(labelNames, mqeValues),
+                                                                                                          LinkedHashMap::new,
+                                                                                                          toList()));
+        if (groupedResult.size() == 1 && groupedResult.keySet().iterator().next().isEmpty()) {
+            expResult.setLabeledResult(false);
+        }
+        expResult.getResults().clear();
+        groupedResult.forEach((labels, mqeValuesList) -> {
+            if (mqeValuesList.isEmpty()) {
+                return;
             }
+            List<MQEValue> combineTo = mqeValuesList.get(0).getValues();
+            for (int i = 0; i < combineTo.size(); i++) {
+                AggregateLabelsFunc aggregateLabelsFunc = factory.getAggregateLabelsFunc();
+                for (MQEValues mqeValues : mqeValuesList) {
+                    MQEValue toCombine = mqeValues.getValues().get(i);
+                    if (!toCombine.isEmptyValue()) {
+                        aggregateLabelsFunc.combine(toCombine.getDoubleValue());
+                    }
+                }
 
-            MQEValue mqeValue = combineTo.get(i);
-            mqeValue.setTraceID(null);
-            mqeValue.setEmptyValue(true);
-            mqeValue.setDoubleValue(0);
+                MQEValue mqeValue = combineTo.get(i);
+                mqeValue.setTraceID(null);
+                mqeValue.setEmptyValue(true);
+                mqeValue.setDoubleValue(0);
 
-            Double result = aggregateLabelsFunc.getResult();
-            if (result != null) {
-                mqeValue.setEmptyValue(false);
-                mqeValue.setDoubleValue(result);
+                Double result = aggregateLabelsFunc.getResult();
+                if (result != null) {
+                    mqeValue.setEmptyValue(false);
+                    mqeValue.setDoubleValue(result);
+                }
             }
-        }
-
-        MQEValues mqeValues = new MQEValues();
-        mqeValues.setMetric(new Metadata());
-        mqeValues.setValues(combineTo);
-        expResult.setResults(Collections.singletonList(mqeValues));
-        expResult.setLabeledResult(false);
+            MQEValues mqeValues = new MQEValues();
+            Metadata metadata = new Metadata();
+            metadata.setLabels(labels);
+            mqeValues.setMetric(metadata);
+            mqeValues.setValues(combineTo);
+            expResult.getResults().add(mqeValues);
+        });
         return expResult;
     }
+
+    private static List<KeyValue> getLabels(final List<String> labelNames, final MQEValues mqeValues) {
+        List<KeyValue> a =
+         labelNames.stream().map(labelName -> mqeValues.getMetric().getLabels().stream().filter(label -> labelName.equals(label.getKey()))
+                                                           .findAny().orElseGet(() -> new KeyValue(labelName, ""))).collect(toList());
+        return a;
+    }
+
 }
diff --git a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
index b7a9e2c86694..c83a89504a3d 100644
--- a/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
+++ b/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java
@@ -19,8 +19,10 @@
 package org.apache.skywalking.mqe.rt.operation;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import org.apache.skywalking.mqe.rt.exception.IllegalExpressionException;
 import org.apache.skywalking.mqe.rt.type.ExpressionResult;
 import org.apache.skywalking.mqe.rt.type.ExpressionResultType;
@@ -256,20 +258,19 @@ private static ExpressionResult seriesNoLabeledWithLabeled(ExpressionResult seri
     private static ExpressionResult seriesLabeledWithLabeled(ExpressionResult seriesLeft,
                                                              ExpressionResult seriesRight,
                                                              int opType, LROp calculate) throws IllegalExpressionException {
-        Map<KeyValue, List<MQEValue>> labelMapR = new HashMap<>();
+        Map<Set<KeyValue>, List<MQEValue>> labelMapR = new HashMap<>();
         if (seriesLeft.getResults().size() != seriesRight.getResults().size()) {
             throw new IllegalExpressionException(
                 "Operation between labeled metrics should have the same label.");
         }
         seriesRight.getResults().forEach(mqeValuesR -> {
-            // For now, we only have a single anonymous label named `_`
-            labelMapR.put(mqeValuesR.getMetric().getLabels().get(0), mqeValuesR.getValues());
+            labelMapR.put(new HashSet<>(mqeValuesR.getMetric().getLabels()), mqeValuesR.getValues());
         });
         for (MQEValues mqeValuesL : seriesLeft.getResults()) {
             for (int i = 0; i < mqeValuesL.getValues().size(); i++) {
                 //reserve left metric info
                 MQEValue valueL = mqeValuesL.getValues().get(i);
-                List<MQEValue> mqeValuesR = labelMapR.get(mqeValuesL.getMetric().getLabels().get(0));
+                List<MQEValue> mqeValuesR = labelMapR.get(new HashSet<>(mqeValuesL.getMetric().getLabels()));
                 if (mqeValuesR == null) {
                     throw new IllegalExpressionException(
                         "Operation between labeled metrics should have the same label.");
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
index a42e73f5604a..7bd3b6ea5e18 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
@@ -19,7 +19,6 @@
 package org.apache.skywalking.oap.server.core.alarm.provider;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -54,7 +53,6 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.LabeledValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.LongValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.joda.time.LocalDateTime;
 import org.joda.time.Minutes;
@@ -367,14 +365,14 @@ private boolean isMatch() {
                 }
             } else {
                 // if the result has multiple labels, when there is one label match, then the result is match
-                // for example in 5 minutes, the sum(percentile{_='P50,P75'} > 1000) >= 3
-                // percentile{_='P50,P75'} result is:
+                // for example in 5 minutes, the sum(percentile{p='50,75'} > 1000) >= 3
+                // percentile{p='50,75'} result is:
                 // P50(1000,1100,1200,1000,500), > 1000 2 times
                 // P75(2000,1500,1200,1000,500), > 1000 3 times
-                // percentile{_='P50,P75'} > 1000 result is:
+                // percentile{p='50,75'} > 1000 result is:
                 // P50(0,1,1,0,0)
                 // P75(1,1,1,0,0)
-                // sum(percentile{_='P50,P75'} > 1000) >= 3 result is:
+                // sum(percentile{p='50,75'} > 1000) >= 3 result is:
                 // P50(0)
                 // P75(1)
                 // then the isMatch is 1
@@ -430,9 +428,6 @@ private LinkedList<Map<String, TraceLogMetric>> transformValues(LinkedList<Map<S
                     r.put(name, new TraceLogMetric(m.getTimeBucket(), new Number[] {((IntValueHolder) m).getValue()}));
                 } else if (m instanceof DoubleValueHolder) {
                     r.put(name, new TraceLogMetric(m.getTimeBucket(), new Number[] {((DoubleValueHolder) m).getValue()}));
-                } else if (m instanceof MultiIntValuesHolder) {
-                    int[] iArr = ((MultiIntValuesHolder) m).getValues();
-                    r.put(name, new TraceLogMetric(m.getTimeBucket(), Arrays.stream(iArr).boxed().toArray(Number[]::new)));
                 } else if (m instanceof LabeledValueHolder) {
                     DataTable dt = ((LabeledValueHolder) m).getValue();
                     TraceLogMetric l = new TraceLogMetric(
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java
index cc0b861339a1..7a200f38f113 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVerifyVisitor.java
@@ -19,8 +19,6 @@
 package org.apache.skywalking.oap.server.core.alarm.provider.expr.rt;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
@@ -34,13 +32,13 @@
 import org.apache.skywalking.mqe.rt.type.MQEValue;
 import org.apache.skywalking.mqe.rt.type.MQEValues;
 import org.apache.skywalking.mqe.rt.type.Metadata;
-import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.query.enumeration.Step;
 import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
+
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.GENERAL_LABEL_NAME;
 
 /**
  * Used for verify the alarm expression and get the metrics name when read the alarm rules.
@@ -85,26 +83,18 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) {
             result.setType(ExpressionResultType.TIME_SERIES_VALUES);
             return result;
         } else if (dataType == Column.ValueDataType.LABELED_VALUE) {
-            List<String> labelValues = Collections.emptyList();
-            if (ctx.label() != null) {
-                String labelValue = ctx.label().labelValue().getText();
-                String labelValueTrim = labelValue.substring(1, labelValue.length() - 1);
-                if (StringUtil.isNotBlank(labelValueTrim)) {
-                    labelValues = Arrays.asList(labelValueTrim.split(Const.COMMA));
-                }
-            }
+            List<KeyValue> queryLabels = buildLabels(ctx.labelList());
             ArrayList<MQEValues> mqeValuesList = new ArrayList<>();
-            if (CollectionUtils.isEmpty(labelValues)) {
+            if (CollectionUtils.isEmpty(queryLabels)) {
                 KeyValue label = new KeyValue(GENERAL_LABEL_NAME, GENERAL_LABEL_NAME);
                 Metadata metadata = new Metadata();
                 metadata.getLabels().add(label);
                 mockMqeValues.setMetric(metadata);
                 mqeValuesList.add(mockMqeValues);
             } else {
-                for (String value : labelValues) {
+                for (KeyValue queryLabel : queryLabels) {
                     Metadata metadata = new Metadata();
-                    KeyValue label = new KeyValue(GENERAL_LABEL_NAME, value);
-                    metadata.getLabels().add(label);
+                    metadata.getLabels().add(queryLabel);
                     mockMqeValues.setMetric(metadata);
                     mqeValuesList.add(mockMqeValues);
                 }
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java
index 712ff70e9a32..12150fca5c12 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/expr/rt/AlarmMQEVisitor.java
@@ -18,16 +18,12 @@
 
 package org.apache.skywalking.oap.server.core.alarm.provider.expr.rt;
 
-import com.google.common.base.Strings;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.mqe.rt.grammar.MQEParser;
 import org.apache.skywalking.mqe.rt.type.ExpressionResult;
@@ -35,7 +31,7 @@
 import org.apache.skywalking.mqe.rt.type.MQEValue;
 import org.apache.skywalking.mqe.rt.type.MQEValues;
 import org.apache.skywalking.mqe.rt.type.Metadata;
-import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DoubleValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.IntValueHolder;
@@ -43,15 +39,16 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.LongValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.mqe.rt.MQEVisitorBase;
-import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.core.query.enumeration.Step;
 import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.joda.time.LocalDateTime;
 
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.GENERAL_LABEL_NAME;
+import static org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO.Util.composeLabelConditions;
+
 @Slf4j
 public class AlarmMQEVisitor extends MQEVisitorBase {
     private final LinkedList<Map<String, Metrics>> metricsValues;
@@ -99,19 +96,12 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) {
                 mqeValuesList = buildMqeValuesList(timeValues);
             }
         } else if (dataType == Column.ValueDataType.LABELED_VALUE) {
-            List<String> labelValues = Collections.emptyList();
-            if (ctx.label() != null) {
-                String labelValue = ctx.label().labelValue().getText();
-                String labelValueTrim = labelValue.substring(1, labelValue.length() - 1);
-                if (StringUtil.isNotBlank(labelValueTrim)) {
-                    labelValues = Arrays.asList(labelValueTrim.split(Const.COMMA));
-                }
-            }
+            List<KeyValue> queryLabels = buildLabels(ctx.labelList());
             Map<String, DataTable> timeValues = labeledValuesMap.get(metricName);
             if (CollectionUtils.isEmpty(timeValues)) {
-                mqeValuesList = buildEmptyLabeledMQEValuesList(labelValues);
+                mqeValuesList = buildEmptyLabeledMQEValuesList(queryLabels);
             } else {
-                mqeValuesList = buildLabledMqeValuesList(timeValues, labelValues);
+                mqeValuesList = buildLabledMqeValuesList(timeValues, queryLabels);
             }
             result.setLabeledResult(true);
         } else {
@@ -173,13 +163,6 @@ private void initMetricsValues() {
                     initCommonMetricValues(metricName, ((IntValueHolder) metrics).getValue(), metrics.getTimeBucket());
                 } else if (metrics instanceof DoubleValueHolder) {
                     initCommonMetricValues(metricName, ((DoubleValueHolder) metrics).getValue(), metrics.getTimeBucket());
-                } else if (metrics instanceof MultiIntValuesHolder) {
-                    int[] ivalueArray = ((MultiIntValuesHolder) metrics).getValues();
-                    DataTable values = new DataTable();
-                    for (int i = 0; i < ivalueArray.length; i++) {
-                        values.put(String.valueOf(i), (long) ivalueArray[i]);
-                    }
-                    initLabeledMetricValues(metricName, values, metrics.getTimeBucket());
                 } else if (metrics instanceof LabeledValueHolder) {
                     DataTable values = ((LabeledValueHolder) metrics).getValue();
                     initLabeledMetricValues(metricName, values, metrics.getTimeBucket());
@@ -226,22 +209,15 @@ private List<MQEValues> buildMqeValuesList(Map<String, Double> timeValues) {
         return mqeValuesList;
     }
 
-    private List<MQEValues> buildLabledMqeValuesList(Map<String, DataTable> timeValues, List<String> labelValues) {
+    private List<MQEValues> buildLabledMqeValuesList(Map<String, DataTable> timeValues, List<KeyValue> queryLabels) {
         List<MQEValues> mqeValuesList = new ArrayList<>();
-        List<String> allLabelValues;
-        if (CollectionUtils.isEmpty(labelValues) || labelValues.stream().allMatch(Strings::isNullOrEmpty)) {
-            allLabelValues = timeValues.values().stream()
-                             .flatMap(dataTable -> dataTable.keys().stream())
-                             .distinct().collect(Collectors.toList());
-        } else {
-            allLabelValues = labelValues;
-        }
-        for (String label : allLabelValues) {
+        List<String> labelConditions = composeLabelConditions(queryLabels, timeValues.values());
+        for (String labelCondition : labelConditions) {
             MQEValues mqeValues = new MQEValues();
             for (String time : windowTimes) {
                 Metadata metadata = new Metadata();
                 DataTable dataTable = timeValues.getOrDefault(time, new DataTable());
-                Long metricValue = dataTable.get(label);
+                Long metricValue = dataTable.get(labelCondition);
                 MQEValue mqeValue = new MQEValue();
                 //use timeBucket as id here
                 mqeValue.setId(time);
@@ -250,8 +226,11 @@ private List<MQEValues> buildLabledMqeValuesList(Map<String, DataTable> timeValu
                 } else {
                     mqeValue.setEmptyValue(true);
                 }
-                KeyValue labelValue = new KeyValue(GENERAL_LABEL_NAME, label);
-                metadata.getLabels().add(labelValue);
+                DataLabel dataLabel = new DataLabel();
+                dataLabel.put(labelCondition);
+                for (Map.Entry<String, String> label : dataLabel.entrySet()) {
+                    metadata.getLabels().add(new KeyValue(label.getKey(), label.getValue()));
+                }
                 mqeValues.setMetric(metadata);
                 mqeValues.getValues().add(mqeValue);
             }
@@ -278,9 +257,9 @@ private ArrayList<MQEValues> buildEmptyMQEValuesList() {
         return mqeValuesList;
     }
 
-    private ArrayList<MQEValues> buildEmptyLabeledMQEValuesList(List<String> labelValues) {
+    private ArrayList<MQEValues> buildEmptyLabeledMQEValuesList(List<KeyValue> queryLabels) {
         ArrayList<MQEValues> mqeValuesList = new ArrayList<>();
-        if (CollectionUtils.isEmpty(labelValues)) {
+        if (CollectionUtils.isEmpty(queryLabels)) {
             MQEValues mqeValues = initMQEValues();
             KeyValue label = new KeyValue(GENERAL_LABEL_NAME, GENERAL_LABEL_NAME);
             Metadata metadata = new Metadata();
@@ -288,10 +267,9 @@ private ArrayList<MQEValues> buildEmptyLabeledMQEValuesList(List<String> labelVa
             mqeValues.setMetric(metadata);
             mqeValuesList.add(mqeValues);
         } else {
-            for (String labelValue : labelValues) {
+            for (KeyValue label : queryLabels) {
                 MQEValues mqeValues = initMQEValues();
                 Metadata metadata = new Metadata();
-                KeyValue label = new KeyValue(GENERAL_LABEL_NAME, labelValue);
                 metadata.getLabels().add(label);
                 mqeValues.setMetric(metadata);
                 mqeValuesList.add(mqeValues);
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 8a51c4316e1c..638db265e6aa 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
@@ -42,6 +42,9 @@ public class Const {
     public static final String POINT = ".";
     public static final String DOUBLE_COLONS_SPLIT = "::";
     public static final String BLANK_ENTITY_NAME = "_blank";
+    public static final String LEFT_BRACE = "{";
+    public static final String RIGHT_BRACE = "}";
+    public static final String EQUAL = "=";
 
     public static final class TLS_MODE {
         public static final String NON_TLS = "NONE";
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunction.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunction.java
index 64ab79a70eba..33af4489b58a 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunction.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunction.java
@@ -21,10 +21,11 @@
 import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.analysis.meter.Meter;
 import org.apache.skywalking.oap.server.core.analysis.meter.MeterEntity;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.metrics.IntList;
+import org.apache.skywalking.oap.server.core.analysis.metrics.LabeledValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.PercentileMetrics;
 import org.apache.skywalking.oap.server.core.query.type.Bucket;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
@@ -38,19 +39,20 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
-import java.util.stream.IntStream;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.PERCENTILE_LABEL_NAME;
+
 /**
  * PercentileFunction is the implementation of {@link PercentileMetrics} in the meter system. The major difference is
  * the PercentileFunction accepts the {@link PercentileArgument} as input rather than every single request.
  */
 @MeterFunction(functionName = "percentile")
 @Slf4j
-public abstract class PercentileFunction extends Meter implements AcceptableValue<PercentileFunction.PercentileArgument>, MultiIntValuesHolder {
+public abstract class PercentileFunction extends Meter implements AcceptableValue<PercentileFunction.PercentileArgument>, LabeledValueHolder {
     public static final String DATASET = "dataset";
     public static final String RANKS = "ranks";
     public static final String VALUE = "datatable_value";
@@ -183,7 +185,9 @@ public void calculate() {
                     int roof = roofs[rankIdx];
 
                     if (count >= roof) {
-                        percentileValues.put(String.valueOf(ranks.get(rankIdx)), Long.parseLong(key));
+                        DataLabel label = new DataLabel();
+                        label.put(PERCENTILE_LABEL_NAME, String.valueOf(ranks.get(rankIdx)));
+                        percentileValues.put(label, Long.parseLong(key));
                         loopIndex++;
                     } else {
                         break;
@@ -216,11 +220,8 @@ public Metrics toDay() {
     }
 
     @Override
-    public int[] getValues() {
-        return percentileValues.sortedValues(Comparator.comparingInt(Integer::parseInt))
-                               .stream()
-                               .flatMapToInt(l -> IntStream.of(l.intValue()))
-                               .toArray();
+    public DataTable getValue() {
+        return percentileValues;
     }
 
     @Override
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunction.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunction.java
index 085618850764..38ab223d10ea 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunction.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunction.java
@@ -24,10 +24,11 @@
 import org.apache.skywalking.oap.server.core.analysis.meter.function.AcceptableValue;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.MeterFunction;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.PercentileArgument;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.metrics.IntList;
+import org.apache.skywalking.oap.server.core.analysis.metrics.LabeledValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.core.query.type.Bucket;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
@@ -47,7 +48,8 @@
 import java.util.stream.Collector;
 import static java.util.stream.Collectors.groupingBy;
 import static java.util.stream.Collectors.mapping;
-import java.util.stream.IntStream;
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.PERCENTILE_LABEL_NAME;
+
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
@@ -65,7 +67,7 @@
  */
 @MeterFunction(functionName = "avgHistogramPercentile")
 @Slf4j
-public abstract class AvgHistogramPercentileFunction extends Meter implements AcceptableValue<PercentileArgument>, MultiIntValuesHolder {
+public abstract class AvgHistogramPercentileFunction extends Meter implements AcceptableValue<PercentileArgument>, LabeledValueHolder {
     private static final String DEFAULT_GROUP = "pD";
     public static final String DATASET = "dataset";
     public static final String RANKS = "ranks";
@@ -248,10 +250,13 @@ public void calculate() {
                             int roof = roofs[rankIdx];
 
                             if (count >= roof) {
+                                DataLabel label = new DataLabel();
                                 if (group.equals(DEFAULT_GROUP)) {
-                                    percentileValues.put(String.valueOf(ranks.get(rankIdx)), Long.parseLong(key));
+                                    label.put(PERCENTILE_LABEL_NAME, String.valueOf(ranks.get(rankIdx)));
+                                    percentileValues.put(label, Long.parseLong(key));
                                 } else {
-                                    percentileValues.put(String.format("%s:%s", group, ranks.get(rankIdx)), Long.parseLong(key));
+                                    label.put(PERCENTILE_LABEL_NAME, String.format("%s:%s", group, ranks.get(rankIdx)));
+                                    percentileValues.put(label, Long.parseLong(key));
                                 }
                                 loopIndex++;
                             } else {
@@ -288,11 +293,8 @@ public Metrics toDay() {
     }
 
     @Override
-    public int[] getValues() {
-        return percentileValues.sortedValues(Comparator.comparingInt(Integer::parseInt))
-                               .stream()
-                               .flatMapToInt(l -> IntStream.of(l.intValue()))
-                               .toArray();
+    public DataTable getValue() {
+        return percentileValues;
     }
 
     @Override
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunction.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunction.java
index b7476cf091de..e67f317a3ea7 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunction.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunction.java
@@ -24,10 +24,11 @@
 import org.apache.skywalking.oap.server.core.analysis.meter.function.AcceptableValue;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.MeterFunction;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.PercentileArgument;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.analysis.metrics.IntList;
+import org.apache.skywalking.oap.server.core.analysis.metrics.LabeledValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.core.query.type.Bucket;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.storage.StorageID;
@@ -46,7 +47,8 @@
 import java.util.stream.Collector;
 import static java.util.stream.Collectors.groupingBy;
 import static java.util.stream.Collectors.mapping;
-import java.util.stream.IntStream;
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.PERCENTILE_LABEL_NAME;
+
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
@@ -56,7 +58,7 @@
  */
 @MeterFunction(functionName = "sumHistogramPercentile")
 @Slf4j
-public abstract class SumHistogramPercentileFunction extends Meter implements AcceptableValue<PercentileArgument>, MultiIntValuesHolder {
+public abstract class SumHistogramPercentileFunction extends Meter implements AcceptableValue<PercentileArgument>, LabeledValueHolder {
     private static final String DEFAULT_GROUP = "pD";
     public static final String DATASET = "dataset";
     public static final String RANKS = "ranks";
@@ -215,10 +217,13 @@ public void calculate() {
                             int roof = roofs[rankIdx];
 
                             if (count >= roof) {
+                                DataLabel label = new DataLabel();
                                 if (group.equals(DEFAULT_GROUP)) {
-                                    percentileValues.put(String.valueOf(ranks.get(rankIdx)), Long.parseLong(key));
+                                    label.put(PERCENTILE_LABEL_NAME, String.valueOf(ranks.get(rankIdx)));
+                                    percentileValues.put(label, Long.parseLong(key));
                                 } else {
-                                    percentileValues.put(String.format("%s:%s", group, ranks.get(rankIdx)), Long.parseLong(key));
+                                    label.put(PERCENTILE_LABEL_NAME, String.format("%s:%s", group, ranks.get(rankIdx)));
+                                    percentileValues.put(label, Long.parseLong(key));
                                 }
                                 loopIndex++;
                             } else {
@@ -253,11 +258,8 @@ public Metrics toDay() {
     }
 
     @Override
-    public int[] getValues() {
-        return percentileValues.sortedValues(Comparator.comparingInt(Integer::parseInt))
-                               .stream()
-                               .flatMapToInt(l -> IntStream.of(l.intValue()))
-                               .toArray();
+    public DataTable getValue() {
+        return percentileValues;
     }
 
     @Override
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataLabel.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataLabel.java
new file mode 100644
index 000000000000..4b7ee3585b33
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataLabel.java
@@ -0,0 +1,92 @@
+/*
+ * 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.analysis.metrics;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import lombok.EqualsAndHashCode;
+import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+
+@EqualsAndHashCode(callSuper = true)
+public class DataLabel extends LinkedHashMap<String/*labelKey*/, String/*labelValue*/> {
+    public final static String GENERAL_LABEL_NAME = "_";
+    public final static String PERCENTILE_LABEL_NAME = "p";
+
+    /**
+     * Parse the labels String to a map.
+     *
+     * @param labels the String format is {key1=value1,key2=value1}, if not match the format will use `_` as the key and
+     *               the `labels string` as the value.
+     */
+    public void put(String labels) {
+        if (labels.startsWith(Const.LEFT_BRACE) && labels.endsWith(Const.RIGHT_BRACE)) {
+            String labelsStr = labels.substring(1, labels.length() - 1);
+            if (StringUtil.isNotEmpty(labelsStr)) {
+                String[] labelArr = labelsStr.split(Const.COMMA);
+                put(labelArr);
+            }
+        } else {
+            //set `_` as the key and the `labels string` as the value.
+            put(GENERAL_LABEL_NAME, labels);
+        }
+    }
+
+    private void put(String[] labels) {
+        for (String label : labels) {
+            int i = label.indexOf(Const.EQUAL);
+            if (i > 0) {
+                String key = label.substring(0, i);
+                String value = label.substring(i + 1);
+                put(key, value);
+            }
+        }
+    }
+
+    public String getLabelString(String key) {
+        return key + Const.EQUAL + get(key);
+    }
+
+    @Override
+    public String put(String key, String value) {
+        return super.put(key, value);
+    }
+
+    @Override
+    public String toString() {
+        Iterator<Map.Entry<String, String>> i = entrySet().iterator();
+        if (!i.hasNext()) {
+            return "{}";
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (; ; ) {
+            Map.Entry<String, String> e = i.next();
+            String key = e.getKey();
+            String value = e.getValue();
+            sb.append(key);
+            sb.append('=');
+            sb.append(value);
+            if (!i.hasNext()) {
+                return sb.append('}').toString();
+            }
+            sb.append(',');
+        }
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataTable.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataTable.java
index f77be3f00950..6e4d60003843 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataTable.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/DataTable.java
@@ -20,13 +20,18 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.GENERAL_LABEL_NAME;
 
 /**
  * DataTable includes a hashmap to store string key and long value. It enhanced the serialization capability.
@@ -57,6 +62,10 @@ public void put(String key, Long value) {
         data.put(key, value);
     }
 
+    public void put(DataLabel labels, Long value) {
+        data.put(labels.toString(), value);
+    }
+
     /**
      * Accumulate the value with existing value in the same given key.
      */
@@ -129,9 +138,13 @@ public String toStorageData() {
     public void toObject(String data) {
         String[] keyValues = data.split(Const.ARRAY_PARSER_SPLIT);
         for (String keyValue : keyValues) {
-            final String[] keyValuePair = keyValue.split(Const.KEY_VALUE_SPLIT);
-            if (keyValuePair.length == 2) {
-                this.data.put(keyValuePair[0], Long.parseLong(keyValuePair[1]));
+            int i = keyValue.lastIndexOf(Const.KEY_VALUE_SPLIT);
+            if (i > 0) {
+                String key = keyValue.substring(0, i);
+                String value = keyValue.substring(i + 1);
+                if (StringUtil.isNotEmpty(key) && StringUtil.isNotEmpty(value)) {
+                    this.data.put(key, Long.parseLong(value));
+                }
             }
         }
     }
@@ -183,4 +196,22 @@ public DataTable setMinValue(DataTable dataTable) {
         });
         return this;
     }
+
+    public Map<String, Set<String>> buildLabelIndex() {
+        Map<String, Set<String>> labelIndex = new HashMap<>();
+        for (String key : data.keySet()) {
+            if (key.startsWith(Const.LEFT_BRACE)) {
+                String labels = key.substring(1, key.length() - 1);
+                if (StringUtil.isNotEmpty(labels)) {
+                    String[] labelsArr = labels.split(Const.COMMA);
+                    for (String label : labelsArr) {
+                        labelIndex.computeIfAbsent(label, keys -> new HashSet<>()).add(key);
+                    }
+                }
+            } else {
+                labelIndex.computeIfAbsent(GENERAL_LABEL_NAME + Const.EQUAL + key, keys -> new HashSet<>()).add(key);
+            }
+        }
+        return labelIndex;
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java
index 46b095f455ae..0eb3a085c134 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/MultiIntValuesHolder.java
@@ -20,7 +20,9 @@
 
 /**
  * MultiIntValuesHolder always holds a set of int(s).
+ * Deprecated @since 10.0.0, use {@link LabeledValueHolder} instead.
  */
+@Deprecated
 public interface MultiIntValuesHolder {
     int[] getValues();
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java
index b50d983fef31..0a04db3c8c17 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics.java
@@ -36,7 +36,9 @@
  * This could calculate the multiple P50/75/90/95/99 values once for all.
  *
  * @since 7.0.0
+ * Deprecated since 10.0.0, use {@link PercentileMetrics2} instead.
  */
+@Deprecated
 @MetricsFunction(functionName = "percentile")
 public abstract class PercentileMetrics extends Metrics implements MultiIntValuesHolder {
     protected static final String DATASET = "dataset";
@@ -53,7 +55,7 @@ public abstract class PercentileMetrics extends Metrics implements MultiIntValue
 
     @Getter
     @Setter
-    @Column(name = VALUE, dataType = Column.ValueDataType.LABELED_VALUE, storageOnly = true)
+    @Column(name = VALUE, dataType = Column.ValueDataType.LABELED_VALUE, storageOnly = true, multiIntValues = true)
     @ElasticSearch.Column(legacyName = "value")
     @BanyanDB.MeasureField
     private DataTable percentileValues;
@@ -103,7 +105,7 @@ public final void calculate() {
                 roofs[i] = Math.round(total * RANKS[i] * 1.0f / 100);
             }
 
-            int count = 0;
+            long count = 0;
             final List<String> sortedKeys = dataset.sortedKeys(Comparator.comparingInt(Integer::parseInt));
 
             int loopIndex = 0;
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics2.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics2.java
new file mode 100644
index 000000000000..d8f34c1a2700
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/PercentileMetrics2.java
@@ -0,0 +1,136 @@
+/*
+ * 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.analysis.metrics;
+
+import java.util.Comparator;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Arg;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entrance;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.MetricsFunction;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.SourceFrom;
+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 static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.PERCENTILE_LABEL_NAME;
+
+/**
+ * Replace the deprecated {@link PercentileMetrics}.
+ * Calculate the multiple P50/75/90/95/99 values once for all
+ * and store the result in the format: `{p=50},value1|{p=75},value2|{p=90},value3|{p=95},value4|{p=99},value5`.
+ *
+ * @since 10.0.0
+ */
+@MetricsFunction(functionName = "percentile2")
+public abstract class PercentileMetrics2 extends Metrics implements LabeledValueHolder {
+    protected static final String DATASET = "dataset";
+    protected static final String VALUE = "datatable_value";
+    protected static final String PRECISION = "precision";
+
+    public static final int[] RANKS = {
+        50,
+        75,
+        90,
+        95,
+        99
+    };
+
+    @Getter
+    @Setter
+    @Column(name = VALUE, dataType = Column.ValueDataType.LABELED_VALUE, storageOnly = true)
+    @ElasticSearch.Column(legacyName = "value")
+    @BanyanDB.MeasureField
+    private DataTable percentileValues;
+    @Getter
+    @Setter
+    @Column(name = PRECISION, storageOnly = true)
+    @BanyanDB.MeasureField
+    private int precision;
+    @Getter
+    @Setter
+    @Column(name = DATASET, storageOnly = true)
+    @BanyanDB.MeasureField
+    private DataTable dataset;
+
+    private boolean isCalculated;
+
+    public PercentileMetrics2() {
+        percentileValues = new DataTable(RANKS.length);
+        dataset = new DataTable(30);
+    }
+
+    @Entrance
+    public final void combine(@SourceFrom int value, @Arg int precision) {
+        this.isCalculated = false;
+        this.precision = precision;
+
+        String index = String.valueOf(value / precision);
+        dataset.valueAccumulation(index, 1L);
+    }
+
+    @Override
+    public boolean combine(Metrics metrics) {
+        this.isCalculated = false;
+
+        PercentileMetrics2 percentileMetrics = (PercentileMetrics2) metrics;
+        this.dataset.append(percentileMetrics.dataset);
+        return true;
+    }
+
+    @Override
+    public final void calculate() {
+        if (!isCalculated) {
+            long total = dataset.sumOfValues();
+
+            int[] roofs = new int[RANKS.length];
+            for (int i = 0; i < RANKS.length; i++) {
+                roofs[i] = Math.round(total * RANKS[i] * 1.0f / 100);
+            }
+
+            long count = 0;
+            final List<String> sortedKeys = dataset.sortedKeys(Comparator.comparingInt(Integer::parseInt));
+
+            int loopIndex = 0;
+            for (String key : sortedKeys) {
+                final Long value = dataset.get(key);
+
+                count += value;
+                for (int rankIdx = loopIndex; rankIdx < roofs.length; rankIdx++) {
+                    int roof = roofs[rankIdx];
+
+                    if (count >= roof) {
+                        DataLabel label = new DataLabel();
+                        label.put(PERCENTILE_LABEL_NAME, String.valueOf(RANKS[rankIdx]));
+                        percentileValues.put(label.toString(), Long.parseLong(key) * precision);
+                        loopIndex++;
+                    } else {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public DataTable getValue() {
+        return percentileValues;
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/AggregationQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/AggregationQueryService.java
index cd4db6671710..d4a26b00ca44 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/AggregationQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/AggregationQueryService.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.oap.server.core.Const;
@@ -53,6 +54,9 @@ private IAggregationQueryDAO getAggregationQueryDAO() {
     }
 
     public List<SelectedRecord> sortMetrics(TopNCondition condition, Duration duration) throws IOException {
+        if (!condition.senseScope()) {
+            return Collections.emptyList();
+        }
         final String valueCName = ValueColumnMetadata.INSTANCE.getValueCName(condition.getName());
         List<KeyValue> additionalConditions = null;
         if (StringUtil.isNotEmpty(condition.getParentService())) {
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsQueryService.java
index 8e8f7e951aad..375c8b5e4e55 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsQueryService.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.server.core.query;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 import java.util.OptionalDouble;
 import lombok.extern.slf4j.Slf4j;
@@ -26,6 +27,7 @@
 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.KVInt;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
 import org.apache.skywalking.oap.server.core.query.type.NullableValue;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
@@ -54,8 +56,11 @@ private IMetricsQueryDAO getMetricQueryDAO() {
      * Read metrics average value in the duration of required metrics
      */
     public NullableValue readMetricsValue(MetricsCondition condition, Duration duration) throws IOException {
-        MetricsValues metricsValues = readMetricsValues(condition, duration);
         long defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
+        if (!condition.senseScope() || !condition.getEntity().isValid()) {
+            return new NullableValue(defaultValue, true);
+        }
+        MetricsValues metricsValues = readMetricsValues(condition, duration);
         if (!metricsValues.getValues().getValues().isEmpty()) {
            OptionalDouble avgValue = metricsValues.getValues().getValues().stream().filter(v -> !v.isEmptyValue()).mapToLong(
                KVInt::getValue).average();
@@ -71,6 +76,9 @@ public NullableValue readMetricsValue(MetricsCondition condition, Duration durat
      * Read time-series values in the duration of required metrics
      */
     public MetricsValues readMetricsValues(MetricsCondition condition, Duration duration) throws IOException {
+        if (!condition.senseScope() || !condition.getEntity().isValid()) {
+            return new MetricsValues();
+        }
         return getMetricQueryDAO().readMetricsValues(
             condition, ValueColumnMetadata.INSTANCE.getValueCName(condition.getName()), duration);
     }
@@ -81,16 +89,28 @@ public MetricsValues readMetricsValues(MetricsCondition condition, Duration dura
      * @param labels the labels you need to query.
      */
     public List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition,
-                                                        List<String> labels,
+                                                        List<KeyValue> labels,
                                                         Duration duration) throws IOException {
+        if (!condition.senseScope() || !condition.getEntity().isValid()) {
+            return Collections.emptyList();
+        }
         return getMetricQueryDAO().readLabeledMetricsValues(
             condition, ValueColumnMetadata.INSTANCE.getValueCName(condition.getName()), labels, duration);
     }
 
+    public List<MetricsValues> readLabeledMetricsValuesWithoutEntity(String metricsName,
+                                         List<KeyValue> labels,
+                                         Duration duration) throws IOException {
+        return getMetricQueryDAO().readLabeledMetricsValuesWithoutEntity(metricsName, ValueColumnMetadata.INSTANCE.getValueCName(metricsName), labels, duration);
+    }
+
     /**
      * Heatmap is bucket based value statistic result.
      */
     public HeatMap readHeatMap(MetricsCondition condition, Duration duration) throws IOException {
+        if (!condition.senseScope() || !condition.getEntity().isValid()) {
+            return new HeatMap();
+        }
         return getMetricQueryDAO().readHeatMap(
             condition, ValueColumnMetadata.INSTANCE.getValueCName(condition.getName()), duration);
     }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/RecordQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/RecordQueryService.java
index b10e8ec86958..c645909ec45c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/RecordQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/RecordQueryService.java
@@ -18,6 +18,7 @@
 
 package org.apache.skywalking.oap.server.core.query;
 
+import java.util.Collections;
 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;
@@ -48,6 +49,9 @@ private IRecordsQueryDAO getRecordsQueryDAO() {
     }
 
     public List<Record> readRecords(RecordCondition condition, Duration duration) throws IOException {
+        if (!condition.senseScope() || !condition.getParentEntity().isValid()) {
+            return Collections.emptyList();
+        }
         return getRecordsQueryDAO().readRecords(
             condition, ValueColumnMetadata.INSTANCE.getValueCName(condition.getName()), duration);
     }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
index 43aaae88af1d..1e77ec9d6532 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
@@ -77,6 +77,14 @@
      */
     ValueDataType dataType() default ValueDataType.NOT_VALUE;
 
+    /**
+     * Since 10.0.0, multi-value column is deprecated. Use {@link ValueDataType#LABELED_VALUE} instead.
+     * This annotation is used to mark the column is a multi-value column for compatibility.
+     * @return if this column is a multi-value column.
+     */
+    @Deprecated
+    boolean multiIntValues() default false;
+
     /**
      * ValueDataType represents the data structure of value column. The persistent way of the value column determine the
      * available ways to query the data.
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java
index 6aa6040125e3..58648a3bb4b3 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java
@@ -43,7 +43,16 @@ public void putIfAbsent(String modelName,
                             Column.ValueDataType dataType,
                             int defaultValue,
                             int scopeId) {
-        mapping.putIfAbsent(modelName, new ValueColumn(valueCName, dataType, defaultValue, scopeId));
+        this.putIfAbsent(modelName, valueCName, dataType, defaultValue, scopeId, false);
+    }
+
+    public void putIfAbsent(String modelName,
+                            String valueCName,
+                            Column.ValueDataType dataType,
+                            int defaultValue,
+                            int scopeId,
+                            boolean multiIntValues) {
+        mapping.putIfAbsent(modelName, new ValueColumn(valueCName, dataType, defaultValue, scopeId, multiIntValues));
     }
 
     public void overrideColumnName(String oldName, String newName) {
@@ -95,5 +104,8 @@ public static class ValueColumn {
         private final Column.ValueDataType dataType;
         private final int defaultValue;
         private final int scopeId;
+        // Will remove this field when `MultiIntValuesHolder` is removed in the future.
+        @Deprecated
+        private final boolean multiIntValues;
     }
 }
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 e5e5e9e429e2..1ab2928f19d3 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
@@ -267,8 +267,7 @@ private void retrieval(final Class<?> clazz,
                 if (column.dataType().isValue()) {
                     ValueColumnMetadata.INSTANCE.putIfAbsent(
                         modelName, column.name(),
-                        column.dataType(), column.defaultValue(), scopeId
-                    );
+                        column.dataType(), column.defaultValue(), scopeId, column.multiIntValues());
                 }
             }
         }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IMetricsQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IMetricsQueryDAO.java
index 6f5451312dd9..060a2b42bc70 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IMetricsQueryDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IMetricsQueryDAO.java
@@ -21,20 +21,29 @@
 import com.google.common.base.Strings;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
+import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 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.IntValues;
 import org.apache.skywalking.oap.server.core.query.type.KVInt;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
 import org.apache.skywalking.oap.server.core.storage.DAO;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
 
 import static java.util.stream.Collectors.toList;
 
@@ -44,16 +53,24 @@
  * @since 8.0.0
  */
 public interface IMetricsQueryDAO extends DAO {
-
+    int METRICS_VALUES_WITHOUT_ENTITY_LIMIT = 10;
     MetricsValues readMetricsValues(MetricsCondition condition,
                                     String valueColumnName,
                                     Duration duration) throws IOException;
 
     List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition,
                                                  String valueColumnName,
-                                                 List<String> labels,
+                                                 List<KeyValue> labels,
                                                  Duration duration) throws IOException;
 
+    /**
+     * Read metrics values without entity. Used for get the labels' metadata.
+     */
+    List<MetricsValues> readLabeledMetricsValuesWithoutEntity(String metricName,
+                                                              String valueColumnName,
+                                                              List<KeyValue> labels,
+                                                              Duration duration) throws IOException;
+
     HeatMap readHeatMap(MetricsCondition condition, String valueColumnName, Duration duration) throws IOException;
 
     class Util {
@@ -86,47 +103,137 @@ public static List<MetricsValues> sortValues(List<MetricsValues> origin,
         /**
          * Compose the multiple metric result based on conditions.
          */
-        public static List<MetricsValues> composeLabelValue(final MetricsCondition condition,
+        public static List<MetricsValues> composeLabelValue(final String metricName,
+                                                            final List<KeyValue> queryLabels,
+                                                            final List<String> ids,
+                                                            final Map<String, DataTable> idMap) {
+            final Optional<ValueColumnMetadata.ValueColumn> valueColumn
+                = ValueColumnMetadata.INSTANCE.readValueColumnDefinition(metricName);
+            if (valueColumn.isEmpty()) {
+                return Collections.emptyList();
+            }
+            //compatible with old version query
+            if (valueColumn.get().isMultiIntValues()) {
+                List<String> labelValues = buildLabelIndex(queryLabels, Const.COMMA).values()
+                                                                                    .stream()
+                                                                                    .flatMap(List::stream)
+                                                                                    .collect(Collectors.toList());
+                return composeLabelValueForMultiIntValues(metricName, labelValues, ids, idMap);
+            }
+            return composeLabelValueForMultipleLabels(metricName, queryLabels, ids, idMap);
+        }
+
+        public static List<String> composeLabelConditions(final List<KeyValue> queryLabels,
+                                                          final Collection<DataTable> metricValues) {
+            LinkedHashMap<String, List<String>> queryLabelIndex = buildLabelIndex(queryLabels, Const.COMMA);
+            List<String> labelConditions = new ArrayList<>();
+            if (queryLabelIndex.isEmpty()) {
+                labelConditions = metricValues.stream()
+                                      .flatMap(dataTable -> dataTable.keys().stream())
+                                      .distinct()
+                                      .filter(k -> k.startsWith(Const.LEFT_BRACE))
+                                      .collect(Collectors.toList());
+            } else {
+                List<Set<String>> keySets = new ArrayList<>();
+                for (Map.Entry<String, List<String>> queryLabel : queryLabelIndex.entrySet()) {
+                    Set<String> keySet = new HashSet<>();
+                    metricValues.forEach(dataTable -> {
+                        var metricLabelIndex = dataTable.buildLabelIndex();
+                        for (String labelValue : queryLabel.getValue()) {
+                            //union labels
+                            keySet.addAll(metricLabelIndex.getOrDefault(
+                                queryLabel.getKey() + Const.EQUAL + labelValue,
+                                new HashSet<>()
+                            ));
+                        }
+                    });
+                    if (!keySet.isEmpty()) {
+                        keySets.add(keySet);
+                    }
+                }
+                //intersection labels
+                keySets.stream().reduce((a, b) -> {
+                    a.retainAll(b);
+                    return a;
+                }).ifPresent(labelConditions::addAll);
+            }
+            return labelConditions;
+        }
+
+        private static List<MetricsValues> composeLabelValueForMultiIntValues(final String metricName,
             final List<String> labels,
             final List<String> ids,
             final Map<String, DataTable> idMap) {
             List<String> allLabels;
-            if (Objects.isNull(labels) || labels.size() < 1 || labels.stream().allMatch(Strings::isNullOrEmpty)) {
+            if (Objects.isNull(labels) || labels.isEmpty() || labels.stream().allMatch(Strings::isNullOrEmpty)) {
                 allLabels = idMap.values().stream()
                     .flatMap(dataTable -> dataTable.keys().stream())
-                    .distinct().collect(Collectors.toList());
+                    .distinct().filter(k -> !k.startsWith(Const.LEFT_BRACE)).collect(Collectors.toList());
             } else {
                 allLabels = labels;
             }
-            final int defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
-            final var labeledValues = new TreeSet<>(allLabels).stream()
-                                                              .flatMap(label -> ids.stream().map(id -> {
-                                                                  final var value = idMap.getOrDefault(id, new DataTable());
-                                                                  return Objects.nonNull(value.get(label)) ?
-                                                                      new LabeledValue(
-                                                                          label,
-                                                                          id,
-                                                                          value.get(label), false) :
-                                                                      new LabeledValue(
-                                                                          label,
-                                                                          id,
-                                                                          defaultValue, true);
-                                                              }))
-                                                              .collect(toList());
-            MetricsValues current = new MetricsValues();
-            List<MetricsValues> result = new ArrayList<>();
-            for (LabeledValue each : labeledValues) {
-                if (Objects.equals(current.getLabel(), each.label)) {
-                    current.getValues().addKVInt(each.kv);
-                } else {
-                    current = new MetricsValues();
-                    current.setLabel(each.label);
-                    current.getValues().addKVInt(each.kv);
-                    result.add(current);
+            return buildMetricsValues(metricName, ids, idMap, allLabels);
+        }
+
+        private static List<MetricsValues> composeLabelValueForMultipleLabels(final String metricName,
+                                                                              final List<KeyValue> queryLabels,
+                                                                              final List<String> ids,
+                                                                              final Map<String, DataTable> idMap) {
+            List<String> labelConditions = composeLabelConditions(queryLabels, idMap.values());
+            return buildMetricsValues(metricName, ids, idMap, labelConditions);
+        }
+    }
+
+    private static List<MetricsValues> buildMetricsValues(final String metricName,
+                                                          final List<String> ids,
+                                                          final Map<String, DataTable> idMap,
+                                                          final List<String> allLabels) {
+        final int defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(metricName);
+        final var labeledValues = new TreeSet<>(allLabels).stream()
+                                                          .flatMap(label -> ids.stream().map(id -> {
+                                                              final var value = idMap.getOrDefault(id, new DataTable());
+
+                                                              return Objects.nonNull(value.get(label)) ?
+                                                                  new LabeledValue(
+                                                                      label,
+                                                                      id,
+                                                                      value.get(label), false) :
+                                                                  new LabeledValue(
+                                                                      label,
+                                                                      id,
+                                                                      defaultValue, true);
+                                                          }))
+                                                          .collect(toList());
+        MetricsValues current = new MetricsValues();
+        List<MetricsValues> result = new ArrayList<>();
+        for (LabeledValue each : labeledValues) {
+            if (Objects.equals(current.getLabel(), each.label)) {
+                current.getValues().addKVInt(each.kv);
+            } else {
+                current = new MetricsValues();
+                current.setLabel(each.label);
+                current.getValues().addKVInt(each.kv);
+                result.add(current);
+            }
+        }
+        return result;
+    }
+
+    private static LinkedHashMap<String, List<String>> buildLabelIndex(List<KeyValue> queryLabels, String separator) {
+        LinkedHashMap<String, List<String>> labelIndex = new LinkedHashMap<>();
+        if (null != queryLabels) {
+            for (KeyValue keyValue : queryLabels) {
+                String labelName = keyValue.getKey();
+                String labelValue = keyValue.getValue();
+                if (StringUtil.isNotBlank(labelValue)) {
+                    String[] subValues = labelValue.split(separator);
+                    for (String subValue : subValues) {
+                        labelIndex.computeIfAbsent(labelName, key -> new ArrayList<>()).add(subValue);
+                    }
                 }
             }
-            return result;
         }
+        return labelIndex;
     }
 
     class LabeledValue {
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelName.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelName.java
index 4e2e1c740c75..63f8f86d5cc9 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelName.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelName.java
@@ -68,6 +68,10 @@ public static LabelName labelOf(String label) {
         return labelName;
     }
 
+    public static boolean isLabelName(String label) {
+        return DICTIONARY.containsKey(label);
+    }
+
     @JsonValue
     public String getLabel() {
         return this.label;
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelValuePair.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelValuePair.java
index c1f78c1f3fad..747ed01160ca 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelValuePair.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/LabelValuePair.java
@@ -26,6 +26,6 @@
 @RequiredArgsConstructor
 @EqualsAndHashCode
 public class LabelValuePair {
-    private final LabelName labelName;
+    private final String labelName;
     private final String labelValue;
 }
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/codec/MetricInfoSerializer.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/codec/MetricInfoSerializer.java
index 1644405844d0..b49e2a6c80c5 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/codec/MetricInfoSerializer.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/codec/MetricInfoSerializer.java
@@ -36,7 +36,7 @@ public void serialize(final MetricInfo value,
         {
             gen.writeStringField("__name__", value.getName());
             for (LabelValuePair label: value.getLabels()) {
-                gen.writeStringField(label.getLabelName().getLabel(), label.getLabelValue());
+                gen.writeStringField(label.getLabelName(), label.getLabelValue());
             }
         }
         gen.writeEndObject();
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/response/LabelsQueryRsp.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/response/LabelsQueryRsp.java
index 49dd537ececb..edbb05ef41ce 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/response/LabelsQueryRsp.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/entity/response/LabelsQueryRsp.java
@@ -22,10 +22,9 @@
 import java.util.List;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import org.apache.skywalking.oap.query.promql.entity.LabelName;
 
 @EqualsAndHashCode(callSuper = true)
 @Data
 public class LabelsQueryRsp extends QueryResponse {
-    private final List<LabelName> data = new ArrayList<>();
+    private final List<String> data = new ArrayList<>();
 }
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java
index 289dff725430..e47f0d20b437 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/handler/PromQLApiHandler.java
@@ -29,6 +29,9 @@
 import com.linecorp.armeria.server.annotation.Param;
 import com.linecorp.armeria.server.annotation.Path;
 import com.linecorp.armeria.server.annotation.Post;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
 import org.antlr.v4.runtime.misc.ParseCancellationException;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -40,8 +43,6 @@
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.apache.skywalking.oap.query.graphql.resolver.MetadataQueryV2;
-import org.apache.skywalking.oap.query.graphql.resolver.MetricsQuery;
-import org.apache.skywalking.oap.query.graphql.resolver.RecordsQuery;
 import org.apache.skywalking.oap.query.promql.PromQLConfig;
 import org.apache.skywalking.oap.query.promql.entity.ErrorType;
 import org.apache.skywalking.oap.query.promql.entity.LabelName;
@@ -71,16 +72,25 @@
 import org.apache.skywalking.oap.query.promql.rt.PromQLExprQueryVisitor;
 import org.apache.skywalking.oap.query.promql.rt.result.ParseResult;
 import org.apache.skywalking.oap.query.promql.rt.result.ScalarResult;
+import org.apache.skywalking.oap.server.core.CoreModule;
 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.manual.endpoint.EndpointTraffic;
 import org.apache.skywalking.oap.server.core.analysis.manual.instance.InstanceTraffic;
 import org.apache.skywalking.oap.server.core.analysis.manual.service.ServiceTraffic;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
+import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.DurationUtils;
 import org.apache.skywalking.oap.server.core.query.MetricDefinition;
+import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
+import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
+import org.apache.skywalking.oap.server.core.query.RecordQueryService;
 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.type.Endpoint;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
+import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
 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.annotation.Column;
@@ -89,23 +99,62 @@
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.promql.rt.grammar.PromQLLexer;
 import org.apache.skywalking.promql.rt.grammar.PromQLParser;
+import org.joda.time.DateTime;
 
 import static org.apache.skywalking.oap.query.promql.rt.PromOpUtils.formatDoubleValue;
 
 public class PromQLApiHandler {
     private final MetadataQueryV2 metadataQuery;
-    private final MetricsQuery metricsQuery;
-    private final RecordsQuery recordsQuery;
+    private final ModuleManager moduleManager;
     private final PromQLConfig config;
+    private MetricsMetadataQueryService metricsMetadataQueryService;
+    private MetricsQueryService metricsQueryService;
+    private AggregationQueryService aggregationQueryService;
+    private RecordQueryService recordQueryService;
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
     public PromQLApiHandler(ModuleManager moduleManager, PromQLConfig config) {
         this.metadataQuery = new MetadataQueryV2(moduleManager);
-        this.metricsQuery = new MetricsQuery(moduleManager);
-        this.recordsQuery = new RecordsQuery(moduleManager);
+        this.moduleManager = moduleManager;
         this.config = config;
     }
 
+    private MetricsMetadataQueryService getMetricsMetadataQueryService() {
+        if (metricsMetadataQueryService == null) {
+            this.metricsMetadataQueryService = moduleManager.find(CoreModule.NAME)
+                                                           .provider()
+                                                           .getService(MetricsMetadataQueryService.class);
+        }
+        return metricsMetadataQueryService;
+    }
+
+    private MetricsQueryService getMetricsQueryService() {
+        if (metricsQueryService == null) {
+            this.metricsQueryService = moduleManager.find(CoreModule.NAME)
+                                                    .provider()
+                                                    .getService(MetricsQueryService.class);
+        }
+        return metricsQueryService;
+    }
+
+    private AggregationQueryService getAggregationQueryService() {
+        if (aggregationQueryService == null) {
+            this.aggregationQueryService = moduleManager.find(CoreModule.NAME)
+                                                        .provider()
+                                                        .getService(AggregationQueryService.class);
+        }
+        return aggregationQueryService;
+    }
+
+    private RecordQueryService getRecordQueryService() {
+        if (recordQueryService == null) {
+            this.recordQueryService = moduleManager.find(CoreModule.NAME)
+                                                   .provider()
+                                                   .getService(RecordQueryService.class);
+        }
+        return recordQueryService;
+    }
+
     @Get
     @Path("/api/v1/metadata")
     public HttpResponse metadata(
@@ -114,7 +163,7 @@ public HttpResponse metadata(
         MetadataQueryRsp response = new MetadataQueryRsp();
         response.setStatus(ResultStatus.SUCCESS);
         String regex = metric.orElse("");
-        List<MetricDefinition> definitionList = metricsQuery.listMetrics(regex);
+        List<MetricDefinition> definitionList = getMetricsMetadataQueryService().listMetrics(regex);
         int inputLimit = limit.orElse(definitionList.size());
         int maxNum = Math.min(inputLimit, definitionList.size());
         for (int i = 0; i < maxNum; i++) {
@@ -127,8 +176,10 @@ public HttpResponse metadata(
     }
 
     /**
-     * OAP doesn't support query label by start/end,
-     * reserve these param to keep consistent with API protocol.
+     * If match[] is not present, return general labels.
+     * If end time is not present, use current time as default end time.
+     * The start param will be ignored, reserve this param to keep consistent with API protocol.
+     * Always query with day step.
      */
     @Get
     @Post
@@ -139,34 +190,33 @@ public HttpResponse labels(
         @Param("end") Optional<String> end) throws IOException {
         LabelsQueryRsp response = new LabelsQueryRsp();
         if (match.isPresent()) {
-            PromQLLexer lexer = new PromQLLexer(
-                CharStreams.fromString(match.get()));
-            lexer.addErrorListener(new ParseErrorListener());
-            PromQLParser parser = new PromQLParser(new CommonTokenStream(lexer));
-            parser.addErrorListener(new ParseErrorListener());
-            ParseTree tree;
+            MatcherSetResult parseResult;
             try {
-                tree = parser.expression();
+                parseResult = getMatcherSetResult(match.get());
             } catch (ParseCancellationException e) {
                 response.setStatus(ResultStatus.ERROR);
                 response.setErrorType(ErrorType.BAD_DATA);
                 response.setError(e.getMessage());
                 return jsonResponse(response);
             }
-            PromQLMatchVisitor visitor = new PromQLMatchVisitor();
-            MatcherSetResult parseResult = visitor.visit(tree);
             String metricName = parseResult.getMetricName();
             Optional<ValueColumnMetadata.ValueColumn> valueColumn = ValueColumnMetadata.INSTANCE.readValueColumnDefinition(
                 metricName);
             if (valueColumn.isPresent()) {
                 ValueColumnMetadata.ValueColumn metaData = valueColumn.get();
                 Scope scope = Scope.Finder.valueOf(metaData.getScopeId());
-                Column.ValueDataType dataType = metaData.getDataType();
-                response.getData().addAll(buildLabelNames(scope, dataType));
+                response.getData().addAll(buildLabelNames(scope, metaData));
+                if (Column.ValueDataType.LABELED_VALUE == valueColumn.get().getDataType()) {
+                    List<MetricsValues> matchedMetrics = getMatcherMetricsValues(parseResult, end);
+                    response.getData().addAll(buildLabelNamesFromQuery(matchedMetrics));
+                }
+                if (metaData.isMultiIntValues()) {
+                    response.getData().remove(DataLabel.GENERAL_LABEL_NAME);
+                }
             }
         } else {
             Arrays.stream(LabelName.values()).forEach(label -> {
-                response.getData().add(label);
+                response.getData().add(label.getLabel());
             });
         }
         response.setStatus(ResultStatus.SUCCESS);
@@ -174,8 +224,10 @@ public HttpResponse labels(
     }
 
     /**
-     * OAP doesn't support query label value by match/start/end,
-     * reserve these param to keep consistent with API protocol.
+     * If match[] is not present, return general labels values.
+     * If end time is not present, use current time as default end time.
+     * The start param will be ignored, reserve this param to keep consistent with API protocol.
+     * Always query with day step.
      */
     @Get
     @Path("/api/v1/label/{label_name}/values")
@@ -186,23 +238,41 @@ public HttpResponse labelValues(
         @Param("end") Optional<String> end) throws IOException {
         LabelValuesQueryRsp response = new LabelValuesQueryRsp();
         response.setStatus(ResultStatus.SUCCESS);
+        //general labels
+        if (LabelName.NAME.getLabel().equals(labelName)) {
+            getMetricsMetadataQueryService().listMetrics("").forEach(definition -> {
+                response.getData().add(definition.getName());
+            });
+            return jsonResponse(response);
+        } else if (LabelName.LAYER.getLabel().equals(labelName)) {
+            for (Layer layer : Layer.values()) {
+                response.getData().add(layer.name());
+            }
+            return jsonResponse(response);
+        } else if (LabelName.SCOPE.getLabel().equals(labelName)) {
+            for (Scope scope : Scope.values()) {
+                response.getData().add(scope.name());
+            }
+            return jsonResponse(response);
+        }
 
-        switch (LabelName.labelOf(labelName)) {
-            case NAME:
-                metricsQuery.listMetrics("").forEach(definition -> {
-                    response.getData().add(definition.getName());
-                });
-                break;
-            case LAYER:
-                for (Layer layer : Layer.values()) {
-                    response.getData().add(layer.name());
-                }
-                break;
-            case SCOPE:
-                for (Scope scope : Scope.values()) {
-                    response.getData().add(scope.name());
-                }
-                break;
+        if (match.isPresent()) {
+            MatcherSetResult parseResult;
+            try {
+                parseResult = getMatcherSetResult(match.get());
+            } catch (ParseCancellationException e) {
+                response.setStatus(ResultStatus.ERROR);
+                response.setErrorType(ErrorType.BAD_DATA);
+                response.setError(e.getMessage());
+                return jsonResponse(response);
+            }
+            String metricName = parseResult.getMetricName();
+            Optional<ValueColumnMetadata.ValueColumn> valueColumn = ValueColumnMetadata.INSTANCE.readValueColumnDefinition(
+                metricName);
+            if (valueColumn.isPresent() && Column.ValueDataType.LABELED_VALUE == valueColumn.get().getDataType()) {
+                List<MetricsValues> matchedMetrics = getMatcherMetricsValues(parseResult, end);
+                response.getData().addAll(buildLabelValuesFromQuery(matchedMetrics, labelName));
+            }
         }
 
         return jsonResponse(response);
@@ -219,24 +289,16 @@ public HttpResponse series(
         long endTS = formatTimestamp2Millis(end);
         Duration duration = DurationUtils.timestamp2Duration(startTS, endTS);
         SeriesQueryRsp response = new SeriesQueryRsp();
-        PromQLLexer lexer = new PromQLLexer(
-            CharStreams.fromString(match));
-        lexer.addErrorListener(new ParseErrorListener());
-        PromQLParser parser = new PromQLParser(new CommonTokenStream(lexer));
-        parser.addErrorListener(new ParseErrorListener());
-        ParseTree tree;
+        MatcherSetResult parseResult;
         try {
-            tree = parser.expression();
+            parseResult = getMatcherSetResult(match);
         } catch (ParseCancellationException e) {
             response.setStatus(ResultStatus.ERROR);
             response.setErrorType(ErrorType.BAD_DATA);
             response.setError(e.getMessage());
             return jsonResponse(response);
         }
-        PromQLMatchVisitor visitor = new PromQLMatchVisitor();
-        MatcherSetResult parseResult = visitor.visit(tree);
         String metricName = parseResult.getMetricName();
-
         Optional<ValueColumnMetadata.ValueColumn> valueColumn = ValueColumnMetadata.INSTANCE.readValueColumnDefinition(
             metricName);
         if (valueColumn.isPresent()) {
@@ -245,30 +307,30 @@ public HttpResponse series(
             Column.ValueDataType dataType = metaData.getDataType();
             response.getData().add(buildMetaMetricInfo(metricName, scope, dataType));
         } else if (Objects.equals(metricName, ServiceTraffic.INDEX_NAME)) {
-            String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE);
+            String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE.getLabel());
             if (StringUtil.isNotBlank(serviceName)) {
                 Service service = metadataQuery.findService(serviceName);
                 response.getData().add(buildMetricInfoFromTraffic(metricName, service));
             } else {
                 List<Service> services = metadataQuery.listServices(
-                    parseResult.getLabelMap().get(LabelName.LAYER));
+                    parseResult.getLabelMap().get(LabelName.LAYER.getLabel()));
                 services.forEach(service -> {
                     response.getData().add(buildMetricInfoFromTraffic(metricName, service));
                 });
             }
         } else if (Objects.equals(metricName, InstanceTraffic.INDEX_NAME)) {
-            String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE);
-            String layer = parseResult.getLabelMap().get(LabelName.LAYER);
+            String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE.getLabel());
+            String layer = parseResult.getLabelMap().get(LabelName.LAYER.getLabel());
             List<ServiceInstance> instances = metadataQuery.listInstances(
                 duration, IDManager.ServiceID.buildId(serviceName, Layer.valueOf(layer).isNormal()));
             instances.forEach(instance -> {
                 response.getData().add(buildMetricInfoFromTraffic(metricName, instance));
             });
         } else if (Objects.equals(metricName, EndpointTraffic.INDEX_NAME)) {
-            String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE);
-            String layer = parseResult.getLabelMap().get(LabelName.LAYER);
-            String keyword = parseResult.getLabelMap().getOrDefault(LabelName.KEYWORD, "");
-            String limit = parseResult.getLabelMap().getOrDefault(LabelName.LIMIT, "100");
+            String serviceName = parseResult.getLabelMap().get(LabelName.SERVICE.getLabel());
+            String layer = parseResult.getLabelMap().get(LabelName.LAYER.getLabel());
+            String keyword = parseResult.getLabelMap().getOrDefault(LabelName.KEYWORD.getLabel(), "");
+            String limit = parseResult.getLabelMap().getOrDefault(LabelName.LIMIT.getLabel(), "100");
             List<Endpoint> endpoints = metadataQuery.findEndpoint(
                 keyword, IDManager.ServiceID.buildId(serviceName, Layer.valueOf(layer).isNormal()),
                 Integer.parseInt(limit)
@@ -312,7 +374,7 @@ public HttpResponse query(
             return jsonResponse(response);
         }
         PromQLExprQueryVisitor visitor = new PromQLExprQueryVisitor(
-            metricsQuery, recordsQuery, duration, QueryType.INSTANT);
+            getMetricsQueryService(), getRecordQueryService(), getAggregationQueryService(), duration, QueryType.INSTANT);
         ParseResult parseResult = visitor.visit(tree);
 
         if (parseResult == null) {
@@ -374,7 +436,7 @@ public HttpResponse query_range(
         }
 
         PromQLExprQueryVisitor visitor = new PromQLExprQueryVisitor(
-            metricsQuery, recordsQuery, duration, QueryType.RANGE);
+            getMetricsQueryService(), getRecordQueryService(), getAggregationQueryService(), duration, QueryType.RANGE);
         ParseResult parseResult = visitor.visit(tree);
 
         if (parseResult == null) {
@@ -475,59 +537,79 @@ private static long formatTimestamp2Millis(String timestamp) {
         return Double.valueOf(timestamp).longValue() * 1000;
     }
 
-    private List<LabelName> buildLabelNames(Scope scope,
-                                            Column.ValueDataType dataType) {
-        List<LabelName> labelNames = new ArrayList<>();
-        labelNames.add(LabelName.LAYER);
-        labelNames.add(LabelName.SERVICE);
-        labelNames.add(LabelName.TOP_N);
-        labelNames.add(LabelName.ORDER);
-        if (Column.ValueDataType.LABELED_VALUE == dataType) {
-            labelNames.add(LabelName.LABELS);
-            labelNames.add(LabelName.RELABELS);
+    private List<String> buildLabelNames(Scope scope, ValueColumnMetadata.ValueColumn metaData) {
+        List<String> labelNames = new ArrayList<>();
+        labelNames.add(LabelName.LAYER.getLabel());
+        labelNames.add(LabelName.SERVICE.getLabel());
+        labelNames.add(LabelName.TOP_N.getLabel());
+        labelNames.add(LabelName.ORDER.getLabel());
+        if (metaData.isMultiIntValues()) {
+            labelNames.add(LabelName.LABELS.getLabel());
+            labelNames.add(LabelName.RELABELS.getLabel());
         }
         switch (scope) {
             case ServiceInstance:
-                labelNames.add(LabelName.SERVICE_INSTANCE);
-                labelNames.add(LabelName.PARENT_SERVICE);
+                labelNames.add(LabelName.SERVICE_INSTANCE.getLabel());
+                labelNames.add(LabelName.PARENT_SERVICE.getLabel());
                 break;
             case Endpoint:
-                labelNames.add(LabelName.ENDPOINT);
-                labelNames.add(LabelName.PARENT_SERVICE);
+                labelNames.add(LabelName.ENDPOINT.getLabel());
+                labelNames.add(LabelName.PARENT_SERVICE.getLabel());
                 break;
         }
         return labelNames;
     }
 
+    private List<String> buildLabelNamesFromQuery(List<MetricsValues> metricsValues) {
+        Set<String> labelNames = new LinkedHashSet<>();
+        metricsValues.forEach(metricsValue -> {
+            DataLabel dataLabel = new DataLabel();
+            dataLabel.put(metricsValue.getLabel());
+            labelNames.addAll(dataLabel.keySet());
+        });
+        return Arrays.asList(labelNames.toArray(new String[0]));
+    }
+
+    private List<String> buildLabelValuesFromQuery(List<MetricsValues> metricsValues, String labelName) {
+        Set<String> labelValues = new LinkedHashSet<>();
+        metricsValues.forEach(metricsValue -> {
+            DataLabel dataLabel = new DataLabel();
+            dataLabel.put(metricsValue.getLabel());
+            labelValues.add(dataLabel.get(labelName));
+        });
+        return Arrays.asList(labelValues.toArray(new String[0]));
+    }
+
+
     //Only return label names, don't support list the product of all the labels and label values.
     private MetricInfo buildMetaMetricInfo(String metricName,
                                            Scope scope,
                                            Column.ValueDataType dataType) {
         MetricInfo metricInfo = new MetricInfo(metricName);
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.LAYER, ""));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.TOP_N, ""));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.ORDER, ""));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.LAYER.getLabel(), ""));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.TOP_N.getLabel(), ""));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.ORDER.getLabel(), ""));
 
         if (Column.ValueDataType.LABELED_VALUE == dataType) {
-            metricInfo.getLabels().add(new LabelValuePair(LabelName.LABELS, ""));
-            metricInfo.getLabels().add(new LabelValuePair(LabelName.RELABELS, ""));
+            metricInfo.getLabels().add(new LabelValuePair(LabelName.LABELS.getLabel(), ""));
+            metricInfo.getLabels().add(new LabelValuePair(LabelName.RELABELS.getLabel(), ""));
         }
         switch (scope) {
             case Service:
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.Service.name()));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE, ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.Service.name()));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE.getLabel(), ""));
                 break;
             case ServiceInstance:
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.ServiceInstance.name()));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE, ""));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE_INSTANCE, ""));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.PARENT_SERVICE, ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.ServiceInstance.name()));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE.getLabel(), ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE_INSTANCE.getLabel(), ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.PARENT_SERVICE.getLabel(), ""));
                 break;
             case Endpoint:
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.Endpoint.name()));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE, ""));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.ENDPOINT, ""));
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.PARENT_SERVICE, ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.Endpoint.name()));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE.getLabel(), ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.ENDPOINT.getLabel(), ""));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.PARENT_SERVICE.getLabel(), ""));
                 break;
         }
         return metricInfo;
@@ -535,27 +617,63 @@ private MetricInfo buildMetaMetricInfo(String metricName,
 
     private MetricInfo buildMetricInfoFromTraffic(String metricName, Service service) {
         MetricInfo metricInfo = new MetricInfo(metricName);
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE, service.getName()));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.Service.name()));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.LAYER, service.getLayers().iterator().next()));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE.getLabel(), service.getName()));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.Service.name()));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.LAYER.getLabel(), service.getLayers().iterator().next()));
         return metricInfo;
     }
 
     private MetricInfo buildMetricInfoFromTraffic(String metricName, ServiceInstance instance) {
         MetricInfo metricInfo = new MetricInfo(metricName);
         metricInfo.getLabels()
-                  .add(new LabelValuePair(LabelName.SERVICE_INSTANCE, instance.getName()));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.ServiceInstance.name()));
+                  .add(new LabelValuePair(LabelName.SERVICE_INSTANCE.getLabel(), instance.getName()));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.ServiceInstance.name()));
         return metricInfo;
     }
 
     private MetricInfo buildMetricInfoFromTraffic(String metricName, Endpoint endpoint) {
         MetricInfo metricInfo = new MetricInfo(metricName);
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.ENDPOINT, endpoint.getName()));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.Endpoint.name()));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.ENDPOINT.getLabel(), endpoint.getName()));
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.Endpoint.name()));
         return metricInfo;
     }
 
+    private Duration getDayDurationFromTimestamp(long timeTS) {
+        Duration duration = new Duration();
+        DateTime dt = new DateTime(timeTS);
+        duration.setStep(Step.DAY);
+        duration.setStart(dt.toString(DurationUtils.YYYY_MM_DD));
+        duration.setEnd(dt.toString(DurationUtils.YYYY_MM_DD));
+        return duration;
+    }
+
+    private MatcherSetResult getMatcherSetResult(String matchString) {
+        PromQLLexer lexer = new PromQLLexer(
+            CharStreams.fromString(matchString));
+        lexer.addErrorListener(new ParseErrorListener());
+        PromQLParser parser = new PromQLParser(new CommonTokenStream(lexer));
+        parser.addErrorListener(new ParseErrorListener());
+        ParseTree tree = parser.expression();
+        PromQLMatchVisitor visitor = new PromQLMatchVisitor();
+        return visitor.visit(tree);
+    }
+
+    private List<MetricsValues> getMatcherMetricsValues(MatcherSetResult parseResult,  Optional<String> end) throws IOException {
+        String metricName = parseResult.getMetricName();
+        List<KeyValue> matchLabels = parseResult.getLabelMap().entrySet().stream().map(entry -> {
+            KeyValue keyValue = new KeyValue();
+            keyValue.setKey(entry.getKey());
+            keyValue.setValue(entry.getValue());
+            return keyValue;
+        }).collect(Collectors.toList());
+        long endTS = System.currentTimeMillis();
+        if (end.isPresent()) {
+            endTS = formatTimestamp2Millis(end.get());
+        }
+        Duration duration = getDayDurationFromTimestamp(endTS);
+        return getMetricsQueryService().readLabeledMetricsValuesWithoutEntity(metricName, matchLabels, duration);
+    }
+
     public enum QueryType {
         INSTANT,
         RANGE,
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 6ce891b325a5..c9fba0cbd09d 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
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.query.promql.rt;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -26,8 +27,6 @@
 import java.util.Map;
 import java.util.Optional;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.skywalking.oap.query.graphql.resolver.MetricsQuery;
-import org.apache.skywalking.oap.query.graphql.resolver.RecordsQuery;
 import org.apache.skywalking.oap.query.promql.entity.ErrorType;
 import org.apache.skywalking.oap.query.promql.entity.LabelName;
 import org.apache.skywalking.oap.query.promql.entity.LabelValuePair;
@@ -41,7 +40,11 @@
 import org.apache.skywalking.oap.query.promql.rt.result.ScalarResult;
 import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
+import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.DurationUtils;
+import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
+import org.apache.skywalking.oap.server.core.query.RecordQueryService;
 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.input.Duration;
@@ -49,6 +52,7 @@
 import org.apache.skywalking.oap.server.core.query.input.MetricsCondition;
 import org.apache.skywalking.oap.server.core.query.input.RecordCondition;
 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.MetricsValues;
 import org.apache.skywalking.oap.server.core.query.type.Record;
 import org.apache.skywalking.oap.server.core.query.type.SelectedRecord;
@@ -66,20 +70,24 @@
 import static org.apache.skywalking.oap.query.promql.rt.PromOpUtils.matrixScalarCompareOp;
 import static org.apache.skywalking.oap.query.promql.rt.PromOpUtils.scalarBinaryOp;
 import static org.apache.skywalking.oap.query.promql.rt.PromOpUtils.scalarCompareOp;
+import static org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel.GENERAL_LABEL_NAME;
 
 @Slf4j
 public class PromQLExprQueryVisitor extends PromQLParserBaseVisitor<ParseResult> {
-    private final MetricsQuery metricsQuery;
-    private final RecordsQuery recordsQuery;
     private final PromQLApiHandler.QueryType queryType;
+    private final MetricsQueryService metricsQueryService;
+    private final RecordQueryService recordQueryService;
+    private final AggregationQueryService aggregationQueryService;
     private Duration duration;
 
-    public PromQLExprQueryVisitor(final MetricsQuery metricsQuery,
-                                  final RecordsQuery recordsQuery,
+    public PromQLExprQueryVisitor(final MetricsQueryService metricsQueryService,
+                                  final RecordQueryService recordQueryService,
+                                  final AggregationQueryService aggregationQueryService,
                                   final Duration duration,
                                   final PromQLApiHandler.QueryType queryType) {
-        this.metricsQuery = metricsQuery;
-        this.recordsQuery = recordsQuery;
+        this.metricsQueryService = metricsQueryService;
+        this.recordQueryService = recordQueryService;
+        this.aggregationQueryService = aggregationQueryService;
         this.duration = duration;
         this.queryType = queryType;
     }
@@ -189,41 +197,48 @@ public ParseResult visitMetricInstant(PromQLParser.MetricInstantContext ctx) {
                 result.setErrorInfo("No labels found in the expression.");
                 return result;
             }
-            Map<LabelName, String> labelMap = new HashMap<>();
+            Map<LabelName, String> generalLabelMap = new HashMap<>();
+            Map<String, String> queryLabel = new HashMap<>();
             for (PromQLParser.LabelContext labelCtx : ctx.labelList().label()) {
                 String labelName = labelCtx.labelName().getText();
                 String labelValue = labelCtx.labelValue().getText();
                 String labelValueTrim = labelValue.substring(1, labelValue.length() - 1);
                 try {
-                    labelMap.put(LabelName.labelOf(labelName), labelValueTrim);
+                    if (LabelName.isLabelName(labelName)) {
+                        generalLabelMap.put(LabelName.labelOf(labelName), labelValueTrim);
+                    } else {
+                        queryLabel.put(labelName, labelValueTrim);
+                    }
                 } catch (IllegalArgumentException e) {
                     throw new IllegalExpressionException("Label:[" + labelName + "] is illegal.");
                 }
             }
             final Layer layer;
-            checkLabels(labelMap, LabelName.LAYER);
+            checkLabels(generalLabelMap, LabelName.LAYER);
             try {
-                layer = Layer.valueOf(labelMap.get(LabelName.LAYER));
+                layer = Layer.valueOf(generalLabelMap.get(LabelName.LAYER));
             } catch (IllegalArgumentException e) {
                 throw new IllegalExpressionException(
-                    "Layer:[" + labelMap.get(LabelName.LAYER) + "] is missing or illegal.");
+                    "Layer:[" + generalLabelMap.get(LabelName.LAYER) + "] is missing or illegal.");
             }
             ValueColumnMetadata.ValueColumn metaData = valueColumn.get();
             Scope scope = Scope.Finder.valueOf(metaData.getScopeId());
             Column.ValueDataType dataType = metaData.getDataType();
             MetricsRangeResult matrixResult = new MetricsRangeResult();
             matrixResult.setResultType(ParseResultType.METRICS_RANGE);
-            if (StringUtil.isNotBlank(labelMap.get(LabelName.TOP_N))) {
+            if (StringUtil.isNotBlank(generalLabelMap.get(LabelName.TOP_N))) {
                 if (Column.ValueDataType.SAMPLED_RECORD == dataType) {
-                    queryRecords(metricName, layer, scope, labelMap, matrixResult);
+                    queryRecords(metricName, layer, scope, generalLabelMap, matrixResult);
                 } else {
-                    queryTopN(metricName, layer, scope, labelMap, matrixResult);
+                    queryTopN(metricName, layer, scope, generalLabelMap, matrixResult);
                 }
             } else {
                 if (Column.ValueDataType.COMMON_VALUE == dataType) {
-                    metricsValuesQuery(metricName, layer, scope, labelMap, matrixResult);
+                    metricsValuesQuery(metricName, layer, scope, generalLabelMap, matrixResult);
                 } else if (Column.ValueDataType.LABELED_VALUE == dataType) {
-                    labeledMetricsValuesQuery(metricName, layer, scope, labelMap, matrixResult);
+                    //compatible with old version query, if true support use `labels` as the query label.
+                    boolean isMultiIntValues = valueColumn.get().isMultiIntValues();
+                    labeledMetricsValuesQuery(metricName, layer, scope, generalLabelMap, queryLabel, matrixResult, isMultiIntValues);
                 }
             }
             return matrixResult;
@@ -279,12 +294,12 @@ private void queryTopN(String metricName,
                            Map<LabelName, String> labelMap,
                            MetricsRangeResult matrixResult) throws IOException, IllegalExpressionException {
         TopNCondition topNCondition = buildTopNCondition(metricName, layer, scope, labelMap);
-        List<SelectedRecord> selectedRecords = metricsQuery.sortMetrics(topNCondition, duration);
+        List<SelectedRecord> selectedRecords = aggregationQueryService.sortMetrics(topNCondition, duration);
         for (SelectedRecord selectedRecord : selectedRecords) {
             MetricRangeData metricData = new MetricRangeData();
             MetricInfo metricInfo = buildMetricInfo(metricName, layer, scope, labelMap,
                                                     Optional.empty(),
-                                                    Optional.ofNullable(selectedRecord.getName()), Optional.empty()
+                                                    Optional.ofNullable(selectedRecord.getName()), Optional.empty(), false
             );
             metricData.setMetric(metricInfo);
             metricData.setValues(buildMatrixValues(duration, String.valueOf(selectedRecord.getValue())));
@@ -298,12 +313,12 @@ private void queryRecords(String metricName,
                               Map<LabelName, String> labelMap,
                               MetricsRangeResult matrixResult) throws IOException, IllegalExpressionException {
         RecordCondition recordCondition = buildRecordCondition(metricName, layer, scope, labelMap);
-        List<Record> records = recordsQuery.readRecords(recordCondition, duration);
+        List<Record> records = recordQueryService.readRecords(recordCondition, duration);
         for (Record record : records) {
             MetricRangeData metricData = new MetricRangeData();
             MetricInfo metricInfo = buildMetricInfo(metricName, layer, scope, labelMap,
                                                     Optional.empty(), Optional.empty(),
-                                                    Optional.ofNullable(record.getName())
+                                                    Optional.ofNullable(record.getName()), false
             );
             metricData.setMetric(metricInfo);
             metricData.setValues(buildMatrixValues(duration, String.valueOf(record.getValue())));
@@ -317,11 +332,11 @@ private void metricsValuesQuery(String metricName,
                                     Map<LabelName, String> labelMap,
                                     MetricsRangeResult matrixResult) throws IOException, IllegalExpressionException {
         MetricsCondition metricsCondition = buildMetricsCondition(metricName, layer, scope, labelMap);
-        MetricsValues metricsValues = metricsQuery.readMetricsValues(
+        MetricsValues metricsValues = metricsQueryService.readMetricsValues(
             metricsCondition, duration);
         MetricRangeData metricData = new MetricRangeData();
         MetricInfo metricInfo = buildMetricInfo(
-            metricName, layer, scope, labelMap, Optional.empty(), Optional.empty(), Optional.empty());
+            metricName, layer, scope, labelMap, Optional.empty(), Optional.empty(), Optional.empty(), false);
         metricData.setMetric(metricInfo);
         metricData.setValues(buildMatrixValues(duration, metricsValues));
         matrixResult.getMetricDataList().add(metricData);
@@ -330,41 +345,51 @@ private void metricsValuesQuery(String metricName,
     private void labeledMetricsValuesQuery(String metricName,
                                            Layer layer,
                                            Scope scope,
-                                           Map<LabelName, String> labelMap,
-                                           MetricsRangeResult matrixResult) throws IOException, IllegalExpressionException {
-        MetricsCondition metricsCondition = buildMetricsCondition(metricName, layer, scope, labelMap);
+                                           Map<LabelName, String> sysLabelMap,
+                                           Map<String, String> queryLabel,
+                                           MetricsRangeResult matrixResult,
+                                           boolean isMultiIntValues) throws IOException, IllegalExpressionException {
+        MetricsCondition metricsCondition = buildMetricsCondition(metricName, layer, scope, sysLabelMap);
         Map<String, String> relabelMap = new HashMap<>();
-        String queryLabels = labelMap.get(LabelName.LABELS);
-        List<String> queryLabelList = Collections.emptyList();
-        if (StringUtil.isNotBlank(queryLabels)) {
-            queryLabelList = Arrays.asList(queryLabels.split(Const.COMMA));
 
-            String relabels = labelMap.get(LabelName.RELABELS);
+        List<KeyValue> queryLabelList = new ArrayList<>();
+        if (isMultiIntValues) {
+            // compatible with old version query.
+            queryLabelList.add(new KeyValue(GENERAL_LABEL_NAME, sysLabelMap.get(LabelName.LABELS)));
+            String relabels = sysLabelMap.get(LabelName.RELABELS);
             List<String> relabelList = Collections.emptyList();
             if (StringUtil.isNotBlank(relabels)) {
                 relabelList = Arrays.asList(relabels.split(Const.COMMA));
             }
-            for (int i = 0; i < queryLabelList.size(); i++) {
+            List<String> labelValues = Arrays.asList(sysLabelMap.get(LabelName.LABELS).split(Const.COMMA));
+            for (int i = 0; i < labelValues.size(); i++) {
                 if (relabelList.size() > i) {
-                    relabelMap.put(queryLabelList.get(i), relabelList.get(i));
-                    continue;
+                    relabelMap.put(labelValues.get(i), relabelList.get(i));
                 }
-                relabelMap.put(queryLabelList.get(i), queryLabelList.get(i));
             }
+        } else {
+            for (Map.Entry<String, String> entry : queryLabel.entrySet()) {
+                queryLabelList.add(new KeyValue(entry.getKey(), entry.getValue()));
+            }
+            // as the percentile metric values changed from `0,1,2,3,4` to `50,75,90,95,99`,
+            // we don't need to relabel it for now.
+            // we should implement `label_replace()` function in the future.
         }
-        List<MetricsValues> metricsValuesList = metricsQuery.readLabeledMetricsValues(
+
+        List<MetricsValues> metricsValuesList = metricsQueryService.readLabeledMetricsValues(
             metricsCondition, queryLabelList, duration);
 
         for (MetricsValues metricsValues : metricsValuesList) {
             MetricRangeData metricData = new MetricRangeData();
             MetricInfo metricInfo = buildMetricInfo(
-                metricName, layer, scope, labelMap,
+                metricName, layer, scope, sysLabelMap,
                 Optional.ofNullable(relabelMap.getOrDefault(
                     metricsValues.getLabel(),
                     metricsValues.getLabel()
                 )),
                 Optional.empty(),
-                Optional.empty()
+                Optional.empty(),
+                isMultiIntValues
             );
             metricData.setMetric(metricInfo);
             metricData.setValues(buildMatrixValues(duration, metricsValues));
@@ -464,56 +489,68 @@ private MetricsCondition buildMetricsCondition(String metricName,
     private MetricInfo buildMetricInfo(String metricName,
                                        Layer layer,
                                        Scope scope,
-                                       Map<LabelName, String> labelMap,
+                                       Map<LabelName, String> sysLabelMap,
                                        Optional<String> valueLabel,
                                        Optional<String> topNEntityName,
-                                       Optional<String> recordName) throws IllegalExpressionException {
+                                       Optional<String> recordName,
+                                       boolean isMultiIntValues) throws IllegalExpressionException {
 
         MetricInfo metricInfo = new MetricInfo(metricName);
-        valueLabel.ifPresent(s -> metricInfo.getLabels().add(new LabelValuePair(LabelName.LABEL, s)));
-        metricInfo.getLabels().add(new LabelValuePair(LabelName.LAYER, layer.name()));
+        valueLabel.ifPresent(s ->
+                             {
+                                 if (isMultiIntValues) {
+                                     metricInfo.getLabels().add(new LabelValuePair(LabelName.LABELS.getLabel(), s));
+                                 } else {
+                                     DataLabel dataLabel = new DataLabel();
+                                     dataLabel.put(s);
+                                     for (Map.Entry<String, String> label : dataLabel.entrySet()) {
+                                         metricInfo.getLabels().add(new LabelValuePair(label.getKey(), label.getValue()));
+                                     }
+                                 }
+                             });
+        metricInfo.getLabels().add(new LabelValuePair(LabelName.LAYER.getLabel(), layer.name()));
         switch (scope) {
             case Service:
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.Service.name()));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.Service.name()));
                 if (topNEntityName.isPresent()) {
-                    metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE, topNEntityName.get()));
+                    metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE.getLabel(), topNEntityName.get()));
                 } else if (recordName.isPresent()) {
-                    metricInfo.getLabels().add(new LabelValuePair(LabelName.RECORD, recordName.get()));
+                    metricInfo.getLabels().add(new LabelValuePair(LabelName.RECORD.getLabel(), recordName.get()));
                 } else {
-                    checkLabels(labelMap, LabelName.SERVICE);
+                    checkLabels(sysLabelMap, LabelName.SERVICE);
                     metricInfo.getLabels()
-                              .add(new LabelValuePair(LabelName.SERVICE, labelMap.get(LabelName.SERVICE)));
+                              .add(new LabelValuePair(LabelName.SERVICE.getLabel(), sysLabelMap.get(LabelName.SERVICE)));
                 }
                 break;
             case ServiceInstance:
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.ServiceInstance.name()));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.ServiceInstance.name()));
                 if (topNEntityName.isPresent()) {
-                    metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE_INSTANCE, topNEntityName.get()));
+                    metricInfo.getLabels().add(new LabelValuePair(LabelName.SERVICE_INSTANCE.getLabel(), topNEntityName.get()));
                 } else if (recordName.isPresent()) {
-                    metricInfo.getLabels().add(new LabelValuePair(LabelName.RECORD, recordName.get()));
+                    metricInfo.getLabels().add(new LabelValuePair(LabelName.RECORD.getLabel(), recordName.get()));
                 } else {
-                    checkLabels(labelMap, LabelName.SERVICE, LabelName.SERVICE_INSTANCE);
+                    checkLabels(sysLabelMap, LabelName.SERVICE, LabelName.SERVICE_INSTANCE);
                     metricInfo.getLabels()
-                              .add(new LabelValuePair(LabelName.SERVICE, labelMap.get(LabelName.SERVICE)));
+                              .add(new LabelValuePair(LabelName.SERVICE.getLabel(), sysLabelMap.get(LabelName.SERVICE)));
                     metricInfo.getLabels()
                               .add(new LabelValuePair(
-                                  LabelName.SERVICE_INSTANCE,
-                                  labelMap.get(LabelName.SERVICE_INSTANCE)
+                                  LabelName.SERVICE_INSTANCE.getLabel(),
+                                  sysLabelMap.get(LabelName.SERVICE_INSTANCE)
                               ));
                 }
                 break;
             case Endpoint:
-                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE, Scope.Endpoint.name()));
+                metricInfo.getLabels().add(new LabelValuePair(LabelName.SCOPE.getLabel(), Scope.Endpoint.name()));
                 if (topNEntityName.isPresent()) {
-                    metricInfo.getLabels().add(new LabelValuePair(LabelName.ENDPOINT, topNEntityName.get()));
+                    metricInfo.getLabels().add(new LabelValuePair(LabelName.ENDPOINT.getLabel(), topNEntityName.get()));
                 } else if (recordName.isPresent()) {
-                    metricInfo.getLabels().add(new LabelValuePair(LabelName.RECORD, recordName.get()));
+                    metricInfo.getLabels().add(new LabelValuePair(LabelName.RECORD.getLabel(), recordName.get()));
                 } else {
-                    checkLabels(labelMap, LabelName.SERVICE, LabelName.ENDPOINT);
+                    checkLabels(sysLabelMap, LabelName.SERVICE, LabelName.ENDPOINT);
                     metricInfo.getLabels()
-                              .add(new LabelValuePair(LabelName.SERVICE, labelMap.get(LabelName.SERVICE)));
+                              .add(new LabelValuePair(LabelName.SERVICE.getLabel(), sysLabelMap.get(LabelName.SERVICE)));
                     metricInfo.getLabels()
-                              .add(new LabelValuePair(LabelName.ENDPOINT, labelMap.get(LabelName.ENDPOINT)));
+                              .add(new LabelValuePair(LabelName.ENDPOINT.getLabel(), sysLabelMap.get(LabelName.ENDPOINT)));
                 }
                 break;
         }
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLMatchVisitor.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLMatchVisitor.java
index 815b6432e9e7..7f1cee026fc2 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLMatchVisitor.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/PromQLMatchVisitor.java
@@ -19,8 +19,6 @@
 package org.apache.skywalking.oap.query.promql.rt;
 
 import java.util.Map;
-import org.apache.skywalking.oap.query.promql.entity.ErrorType;
-import org.apache.skywalking.oap.query.promql.entity.LabelName;
 import org.apache.skywalking.oap.query.promql.rt.result.MatcherSetResult;
 import org.apache.skywalking.oap.query.promql.rt.result.ParseResultType;
 import org.apache.skywalking.promql.rt.grammar.PromQLParser;
@@ -34,19 +32,13 @@ public MatcherSetResult visitMetricInstant(PromQLParser.MetricInstantContext ctx
         MatcherSetResult result = new MatcherSetResult();
         result.setResultType(ParseResultType.MATCH);
         result.setMetricName(metricName);
-        Map<LabelName, String> labelMap = result.getLabelMap();
+        Map<String, String> labelMap = result.getLabelMap();
         if (ctx.labelList() != null) {
             for (PromQLParser.LabelContext labelCtx : ctx.labelList().label()) {
                 String labelName = labelCtx.labelName().getText();
                 String labelValue = labelCtx.labelValue().getText();
                 String labelValueTrim = labelValue.substring(1, labelValue.length() - 1);
-                try {
-                    labelMap.put(LabelName.labelOf(labelName), labelValueTrim);
-                } catch (IllegalArgumentException e) {
-                    result.setErrorType(ErrorType.BAD_DATA);
-                    result.setErrorInfo("Label:[" + labelName + "] is illegal.");
-                    return result;
-                }
+                labelMap.put(labelName, labelValueTrim);
             }
         }
         return result;
diff --git a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/result/MatcherSetResult.java b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/result/MatcherSetResult.java
index b2e8c240daf9..c877edea9e85 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/result/MatcherSetResult.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/main/java/org/apache/skywalking/oap/query/promql/rt/result/MatcherSetResult.java
@@ -22,11 +22,10 @@
 import java.util.Map;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import org.apache.skywalking.oap.query.promql.entity.LabelName;
 
 @EqualsAndHashCode(callSuper = true)
 @Data
 public class MatcherSetResult extends ParseResult {
     private String metricName;
-    private Map<LabelName, String> labelMap = new HashMap<>();
+    private Map<String, String> labelMap = new HashMap<>();
 }
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java
index 9b36208bc36f..cd016b1620bd 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/mqe/rt/MQEVisitor.java
@@ -20,9 +20,8 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.mqe.rt.exception.IllegalExpressionException;
@@ -30,11 +29,13 @@
 import org.apache.skywalking.mqe.rt.type.MQEValue;
 import org.apache.skywalking.mqe.rt.type.MQEValues;
 import org.apache.skywalking.mqe.rt.type.Metadata;
-import org.apache.skywalking.oap.query.graphql.resolver.MetricsQuery;
-import org.apache.skywalking.oap.query.graphql.resolver.RecordsQuery;
-import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
+import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.DurationUtils;
+import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
 import org.apache.skywalking.oap.server.core.query.PointOfTime;
+import org.apache.skywalking.oap.server.core.query.RecordQueryService;
 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.Entity;
@@ -48,7 +49,7 @@
 import org.apache.skywalking.oap.server.core.query.type.SelectedRecord;
 import org.apache.skywalking.oap.server.core.storage.annotation.Column;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
-import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.mqe.rt.MQEVisitorBase;
 import org.apache.skywalking.mqe.rt.type.ExpressionResult;
 import org.apache.skywalking.mqe.rt.type.ExpressionResultType;
@@ -56,22 +57,49 @@
 
 @Slf4j
 public class MQEVisitor extends MQEVisitorBase {
-    private final MetricsQuery metricsQuery;
-    private final RecordsQuery recordsQuery;
     private final Entity entity;
     private final Duration duration;
+    private final ModuleManager moduleManager;
+    private MetricsQueryService metricsQueryService;
+    private AggregationQueryService aggregationQueryService;
+    private RecordQueryService recordQueryService;
 
-    public MQEVisitor(final MetricsQuery metricsQuery,
-                      final RecordsQuery recordsQuery,
+    public MQEVisitor(final ModuleManager moduleManager,
                       final Entity entity,
                       final Duration duration) {
         super(duration.getStep());
-        this.metricsQuery = metricsQuery;
-        this.recordsQuery = recordsQuery;
+        this.moduleManager = moduleManager;
         this.entity = entity;
         this.duration = duration;
     }
 
+    private MetricsQueryService getMetricsQueryService() {
+        if (metricsQueryService == null) {
+            this.metricsQueryService = moduleManager.find(CoreModule.NAME)
+                                                    .provider()
+                                                    .getService(MetricsQueryService.class);
+        }
+        return metricsQueryService;
+    }
+
+    private AggregationQueryService getAggregationQueryService() {
+        if (aggregationQueryService == null) {
+            this.aggregationQueryService = moduleManager.find(CoreModule.NAME)
+                                                        .provider()
+                                                        .getService(AggregationQueryService.class);
+        }
+        return aggregationQueryService;
+    }
+
+    private RecordQueryService getRecordQueryService() {
+        if (recordQueryService == null) {
+            this.recordQueryService = moduleManager.find(CoreModule.NAME)
+                                                  .provider()
+                                                  .getService(RecordQueryService.class);
+        }
+        return recordQueryService;
+    }
+
     @Override
     public ExpressionResult visitMetric(MQEParser.MetricContext ctx) {
         ExpressionResult result = new ExpressionResult();
@@ -105,24 +133,19 @@ public ExpressionResult visitMetric(MQEParser.MetricContext ctx) {
                     queryMetrics(metricName, this.duration, result);
                 }
             } else if (Column.ValueDataType.LABELED_VALUE == dataType) {
-                List<String> queryLabelList = Collections.emptyList();
+
+               // DataLabel dataLabel = new DataLabel();
                 if (ctx.parent instanceof MQEParser.TopNOPContext) {
                     throw new IllegalExpressionException(
                         "Metric: [" + metricName + "] is labeled value, dose not support top_n query.");
                 }
-                if (ctx.label() != null) {
-                    String labelValue = ctx.label().labelValue().getText();
-                    String labelValueTrim = labelValue.substring(1, labelValue.length() - 1);
-                    if (StringUtil.isNotBlank(labelValueTrim)) {
-                        queryLabelList = Arrays.asList(labelValueTrim.split(Const.COMMA));
-                    }
-                }
+                List<KeyValue> queryLabels = super.buildLabels(ctx.labelList());
                 if (ctx.parent instanceof MQEParser.TrendOPContext) {
                     MQEParser.TrendOPContext parent = (MQEParser.TrendOPContext) ctx.parent;
                     int trendRange = Integer.parseInt(parent.INTEGER().getText());
-                    queryLabeledMetrics(metricName, queryLabelList, getTrendQueryDuration(trendRange), result);
+                    queryLabeledMetrics(metricName, queryLabels, getTrendQueryDuration(trendRange), result);
                 } else {
-                    queryLabeledMetrics(metricName, queryLabelList, this.duration, result);
+                    queryLabeledMetrics(metricName, queryLabels, this.duration, result);
                 }
             } else if (Column.ValueDataType.SAMPLED_RECORD == dataType) {
                 if (ctx.parent instanceof MQEParser.TopNOPContext) {
@@ -164,7 +187,7 @@ private void querySortMetrics(String metricName,
         topNCondition.setParentService(entity.getServiceName());
         topNCondition.setOrder(order);
         topNCondition.setNormal(entity.getNormal());
-        List<SelectedRecord> selectedRecords = metricsQuery.sortMetrics(topNCondition, duration);
+        List<SelectedRecord> selectedRecords = getAggregationQueryService().sortMetrics(topNCondition, duration);
 
         List<MQEValue> mqeValueList = new ArrayList<>(selectedRecords.size());
         selectedRecords.forEach(selectedRecord -> {
@@ -188,7 +211,7 @@ private void queryRecords(String metricName, int topN, Order order, ExpressionRe
         recordCondition.setTopN(topN);
         recordCondition.setParentEntity(entity);
         recordCondition.setOrder(order);
-        List<Record> records = recordsQuery.readRecords(recordCondition, duration);
+        List<Record> records = getRecordQueryService().readRecords(recordCondition, duration);
 
         List<MQEValue> mqeValueList = new ArrayList<>(records.size());
         records.forEach(record -> {
@@ -211,8 +234,13 @@ private void queryMetrics(String metricName, Duration queryDuration, ExpressionR
         MetricsCondition metricsCondition = new MetricsCondition();
         metricsCondition.setName(metricName);
         metricsCondition.setEntity(entity);
-        MetricsValues metricsValues = metricsQuery.readMetricsValues(metricsCondition, queryDuration);
+        MetricsValues metricsValues = getMetricsQueryService().readMetricsValues(metricsCondition, queryDuration);
         List<PointOfTime> times = queryDuration.assembleDurationPoints();
+        if (metricsValues.getValues().getValues().size() != times.size()) {
+            log.warn("Metric: {} values size is not equal to duration points size, metrics values size: {}, duration points size: {}",
+                     metricName, metricsValues.getValues().getValues().size(), times.size());
+            return;
+        }
         List<MQEValue> mqeValueList = new ArrayList<>(times.size());
         for (int i = 0; i < times.size(); i++) {
             long retTimestamp = DurationUtils.INSTANCE.parseToDateTime(queryDuration.getStep(), times.get(i).getPoint())
@@ -233,16 +261,21 @@ private void queryMetrics(String metricName, Duration queryDuration, ExpressionR
     }
 
     private void queryLabeledMetrics(String metricName,
-                                     List<String> queryLabelList,
+                                     List<KeyValue> queryLabels,
                                      Duration queryDuration,
                                      ExpressionResult result) throws IOException {
         MetricsCondition metricsCondition = new MetricsCondition();
         metricsCondition.setName(metricName);
         metricsCondition.setEntity(entity);
-        List<MetricsValues> metricsValuesList = metricsQuery.readLabeledMetricsValues(
-            metricsCondition, queryLabelList, queryDuration);
+        List<MetricsValues> metricsValuesList = getMetricsQueryService().readLabeledMetricsValues(
+            metricsCondition, queryLabels, queryDuration);
         List<PointOfTime> times = queryDuration.assembleDurationPoints();
         metricsValuesList.forEach(metricsValues -> {
+            if (metricsValues.getValues().getValues().size() != times.size()) {
+                log.warn("Metric: {} values size is not equal to duration points size, metrics values size: {}, duration points size: {}",
+                         metricName, metricsValues.getValues().getValues().size(), times.size());
+                return;
+            }
             List<MQEValue> mqeValueList = new ArrayList<>(times.size());
             for (int i = 0; i < times.size(); i++) {
                 long retTimestamp = DurationUtils.INSTANCE.parseToDateTime(queryDuration.getStep(), times.get(i).getPoint())
@@ -258,8 +291,11 @@ private void queryLabeledMetrics(String metricName,
             }
 
             Metadata metadata = new Metadata();
-            KeyValue labelValue = new KeyValue(GENERAL_LABEL_NAME, metricsValues.getLabel());
-            metadata.getLabels().add(labelValue);
+            DataLabel dataLabel = new DataLabel();
+            dataLabel.put(metricsValues.getLabel());
+            for (Map.Entry<String, String> label : dataLabel.entrySet()) {
+                metadata.getLabels().add(new KeyValue(label.getKey(), label.getValue()));
+            }
             MQEValues mqeValues = new MQEValues();
             mqeValues.setValues(mqeValueList);
             mqeValues.setMetric(metadata);
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java
index 89cb999dfea2..1522278fb180 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsExpressionQuery.java
@@ -35,13 +35,11 @@
 import org.apache.skywalking.mqe.rt.grammar.MQEParser;
 
 public class MetricsExpressionQuery implements GraphQLQueryResolver {
-    private final MetricsQuery metricsQuery;
-    private final RecordsQuery recordsQuery;
+    private final ModuleManager moduleManager;
     private final DecimalFormat valueFormat = new DecimalFormat();
 
     public MetricsExpressionQuery(ModuleManager moduleManager) {
-        this.metricsQuery = new MetricsQuery(moduleManager);
-        this.recordsQuery = new RecordsQuery(moduleManager);
+        this.moduleManager = moduleManager;
         this.valueFormat.setGroupingUsed(false);
     }
 
@@ -60,7 +58,7 @@ public ExpressionResult execExpression(String expression, Entity entity, Duratio
             errorResult.setError(e.getMessage());
             return errorResult;
         }
-        MQEVisitor visitor = new MQEVisitor(metricsQuery, recordsQuery, entity, duration);
+        MQEVisitor visitor = new MQEVisitor(moduleManager, entity, duration);
         ExpressionResult parseResult = visitor.visit(tree);
 
         parseResult.getResults().forEach(mqeValues -> {
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java
index 37687ff22b7e..f9d8a4ee8574 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java
@@ -26,7 +26,9 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.metrics.DataLabel;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.MetricDefinition;
@@ -41,6 +43,7 @@
 import org.apache.skywalking.oap.server.core.query.input.TopNCondition;
 import org.apache.skywalking.oap.server.core.query.type.HeatMap;
 import org.apache.skywalking.oap.server.core.query.type.KVInt;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
 import org.apache.skywalking.oap.server.core.query.type.NullableValue;
 import org.apache.skywalking.oap.server.core.query.type.Record;
@@ -199,7 +202,10 @@ public List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition,
             }
             return labeledValues;
         }
-        return getMetricsQueryService().readLabeledMetricsValues(condition, labels, duration);
+        List<KeyValue> labelList = new ArrayList<>();
+        String labelValue = labels.stream().reduce((a, b) -> a + Const.COMMA + b).orElse("");
+        labelList.add(new KeyValue(DataLabel.GENERAL_LABEL_NAME, labelValue));
+        return getMetricsQueryService().readLabeledMetricsValues(condition, labelList, duration);
     }
 
     /**
diff --git a/oap-server/server-starter/src/main/resources/oal/browser.oal b/oap-server/server-starter/src/main/resources/oal/browser.oal
index a7a4458a8b6c..2f813ed996f8 100644
--- a/oap-server/server-starter/src/main/resources/oal/browser.oal
+++ b/oap-server/server-starter/src/main/resources/oal/browser.oal
@@ -51,13 +51,13 @@ browser_app_page_ttl_avg = from(BrowserAppPagePerf.ttlTime).longAvg();
 browser_app_page_first_pack_avg = from(BrowserAppPagePerf.firstPackTime).longAvg();
 browser_app_page_fmp_avg = from(BrowserAppPagePerf.fmpTime).longAvg();
 
-browser_app_page_fpt_percentile = from(BrowserAppPagePerf.fptTime).percentile(10);
-browser_app_page_ttl_percentile = from(BrowserAppPagePerf.ttlTime).percentile(10);
-browser_app_page_dom_ready_percentile = from(BrowserAppPagePerf.domReadyTime).percentile(10);
-browser_app_page_load_page_percentile = from(BrowserAppPagePerf.loadPageTime).percentile(10);
-browser_app_page_first_pack_percentile = from(BrowserAppPagePerf.firstPackTime).percentile(10);
-browser_app_page_fmp_percentile = from(BrowserAppPagePerf.fmpTime).percentile(10);
+browser_app_page_fpt_percentile = from(BrowserAppPagePerf.fptTime).percentile2(10);
+browser_app_page_ttl_percentile = from(BrowserAppPagePerf.ttlTime).percentile2(10);
+browser_app_page_dom_ready_percentile = from(BrowserAppPagePerf.domReadyTime).percentile2(10);
+browser_app_page_load_page_percentile = from(BrowserAppPagePerf.loadPageTime).percentile2(10);
+browser_app_page_first_pack_percentile = from(BrowserAppPagePerf.firstPackTime).percentile2(10);
+browser_app_page_fmp_percentile = from(BrowserAppPagePerf.fmpTime).percentile2(10);
 
 // Disable unnecessary hard core stream, targeting @Stream#name
 /////////
-//disable(browser_error_log);
\ No newline at end of file
+//disable(browser_error_log);
diff --git a/oap-server/server-starter/src/main/resources/oal/core.oal b/oap-server/server-starter/src/main/resources/oal/core.oal
index e79befafd7f0..a5ebcb18a291 100755
--- a/oap-server/server-starter/src/main/resources/oal/core.oal
+++ b/oap-server/server-starter/src/main/resources/oal/core.oal
@@ -20,7 +20,7 @@
 service_resp_time = from(Service.latency).longAvg();
 service_sla = from(Service.*).percent(status == true);
 service_cpm = from(Service.*).cpm();
-service_percentile = from(Service.latency).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_percentile = from(Service.latency).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
 service_apdex = from(Service.latency).apdex(name, status);
 service_mq_consume_count = from(Service.*).filter(type == RequestType.MQ).count();
 service_mq_consume_latency = from((str->long)Service.tag["transmission.latency"]).filter(type == RequestType.MQ).filter(tag["transmission.latency"] != null).longAvg();
@@ -32,8 +32,8 @@ service_relation_client_call_sla = from(ServiceRelation.*).filter(detectPoint ==
 service_relation_server_call_sla = from(ServiceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
 service_relation_client_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
 service_relation_server_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
-service_relation_client_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10); // Multiple values including p50, p75, p90, p95, p99
-service_relation_server_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_relation_client_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
+service_relation_server_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
 
 // Service Instance relation scope metrics for topology
 service_instance_relation_client_cpm = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.CLIENT).cpm();
@@ -42,8 +42,8 @@ service_instance_relation_client_call_sla = from(ServiceInstanceRelation.*).filt
 service_instance_relation_server_call_sla = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
 service_instance_relation_client_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
 service_instance_relation_server_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
-service_instance_relation_client_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10); // Multiple values including p50, p75, p90, p95, p99
-service_instance_relation_server_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_instance_relation_client_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
+service_instance_relation_server_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
 
 // Service Instance Scope metrics
 service_instance_sla = from(ServiceInstance.*).percent(status == true);
@@ -54,45 +54,45 @@ service_instance_cpm = from(ServiceInstance.*).cpm();
 endpoint_cpm = from(Endpoint.*).cpm();
 endpoint_resp_time = from(Endpoint.latency).longAvg();
 endpoint_sla = from(Endpoint.*).percent(status == true);
-endpoint_percentile = from(Endpoint.latency).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+endpoint_percentile = from(Endpoint.latency).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
 endpoint_mq_consume_latency = from((str->long)Endpoint.tag["transmission.latency"]).filter(type == RequestType.MQ).filter(tag["transmission.latency"] != null).longAvg();
 
 // Endpoint relation scope metrics
 endpoint_relation_cpm = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
 endpoint_relation_resp_time = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).longAvg();
 endpoint_relation_sla = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
-endpoint_relation_percentile = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+endpoint_relation_percentile = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
 
 database_access_resp_time = from(DatabaseAccess.latency).longAvg();
 database_access_sla = from(DatabaseAccess.*).percent(status == true);
 database_access_cpm = from(DatabaseAccess.*).cpm();
-database_access_percentile = from(DatabaseAccess.latency).percentile(10);
+database_access_percentile = from(DatabaseAccess.latency).percentile2(10);
 
 cache_read_resp_time = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).longAvg();
 cache_read_sla = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Read).percent(status == true);
 cache_read_cpm = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Read).cpm();
-cache_read_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).percentile(10);
+cache_read_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).percentile2(10);
 
 cache_write_resp_time = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).longAvg();
 cache_write_sla = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Write).percent(status == true);
 cache_write_cpm = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Write).cpm();
-cache_write_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).percentile(10);
+cache_write_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).percentile2(10);
 
 cache_access_resp_time = from(CacheAccess.latency).longAvg();
 cache_access_sla = from(CacheAccess.*).percent(status == true);
 cache_access_cpm = from(CacheAccess.*).cpm();
-cache_access_percentile = from(CacheAccess.latency).percentile(10);
+cache_access_percentile = from(CacheAccess.latency).percentile2(10);
 
 mq_service_consume_cpm = from(MQAccess.*).filter(operation == MQOperation.Consume).cpm();
 mq_service_consume_sla = from(MQAccess.*).filter(operation == MQOperation.Consume).percent(status == true);
 mq_service_consume_latency = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).longAvg();
-mq_service_consume_percentile = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile(10);
+mq_service_consume_percentile = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile2(10);
 mq_service_produce_cpm = from(MQAccess.*).filter(operation == MQOperation.Produce).cpm();
 mq_service_produce_sla = from(MQAccess.*).filter(operation == MQOperation.Produce).percent(status == true);
 
 mq_endpoint_consume_cpm = from(MQEndpointAccess.*).filter(operation == MQOperation.Consume).cpm();
 mq_endpoint_consume_latency = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).longAvg();
-mq_endpoint_consume_percentile = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile(10);
+mq_endpoint_consume_percentile = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile2(10);
 mq_endpoint_consume_sla = from(MQEndpointAccess.*).filter(operation == MQOperation.Consume).percent(status == true);
 mq_endpoint_produce_cpm = from(MQEndpointAccess.*).filter(operation == MQOperation.Produce).cpm();
 mq_endpoint_produce_sla = from(MQEndpointAccess.*).filter(operation == MQOperation.Produce).percent(status == true);
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-instance.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-instance.json
index f288e8892b96..a76c675ca4ea 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-instance.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-instance.json
@@ -531,11 +531,11 @@
       "isRoot": false,
       "isDefault": true,
       "expressions": [
-        "avg(meter_apisix_instance_http_status_matched{_='200'})",
-        "avg(meter_apisix_instance_http_status_matched{_='304'})",
-        "avg(meter_apisix_instance_http_status_matched{_='404'})",
-        "avg(meter_apisix_instance_http_status_matched{_='499'})",
-        "avg(meter_apisix_instance_http_status_matched{_='503'})"
+        "avg(meter_apisix_instance_http_status_matched{code='200'})",
+        "avg(meter_apisix_instance_http_status_matched{code='304'})",
+        "avg(meter_apisix_instance_http_status_matched{code='404'})",
+        "avg(meter_apisix_instance_http_status_matched{code='499'})",
+        "avg(meter_apisix_instance_http_status_matched{code='503'})"
       ],
       "expressionsConfig": [
         {
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-service.json
index 2068ddbf4987..d5f70e53d3da 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/apisix/apisix-service.json
@@ -416,11 +416,11 @@
       "isRoot": false,
       "isDefault": true,
       "expressions": [
-        "avg(meter_apisix_sv_http_status_matched{_='200'})",
-        "avg(meter_apisix_sv_http_status_matched{_='304'})",
-        "avg(meter_apisix_sv_http_status_matched{_='404'})",
-        "avg(meter_apisix_sv_http_status_matched{_='499'})",
-        "avg(meter_apisix_sv_http_status_matched{_='503'})"
+        "avg(meter_apisix_sv_http_status_matched{code='200'})",
+        "avg(meter_apisix_sv_http_status_matched{code='304'})",
+        "avg(meter_apisix_sv_http_status_matched{code='404'})",
+        "avg(meter_apisix_sv_http_status_matched{code='499'})",
+        "avg(meter_apisix_sv_http_status_matched{code='503'})"
       ],
       "expressionsConfig": [
         {
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/browser/browser-page.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/browser/browser-page.json
index 49edeb3d4ddb..2b7d32489330 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/browser/browser-page.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/browser/browser-page.json
@@ -35,7 +35,7 @@
                     "showYAxis": true
                   },
                   "expressions": [
-                    "relabels(browser_app_page_fmp_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(browser_app_page_fmp_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "metricMode": "Expression",
                   "typesOfMQE": [
@@ -91,7 +91,7 @@
                     "showYAxis": true
                   },
                   "expressions": [
-                    "relabels(browser_app_page_first_pack_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(browser_app_page_first_pack_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "metricMode": "Expression",
                   "typesOfMQE": [
@@ -147,7 +147,7 @@
                     "showYAxis": true
                   },
                   "expressions": [
-                    "relabels(browser_app_page_fpt_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(browser_app_page_fpt_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "metricMode": "Expression",
                   "typesOfMQE": [
@@ -203,7 +203,7 @@
                     "showYAxis": true
                   },
                   "expressions": [
-                    "relabels(browser_app_page_dom_ready_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(browser_app_page_dom_ready_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "metricMode": "Expression",
                   "typesOfMQE": [
@@ -259,7 +259,7 @@
                     "showYAxis": true
                   },
                   "expressions": [
-                    "relabels(browser_app_page_ttl_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(browser_app_page_ttl_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "metricMode": "Expression",
                   "typesOfMQE": [
@@ -315,7 +315,7 @@
                     "showYAxis": true
                   },
                   "expressions": [
-                    "relabels(browser_app_page_load_page_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(browser_app_page_load_page_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "metricMode": "Expression",
                   "typesOfMQE": [
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint-relation.json
index d1d77ab04f57..a69563de32a9 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint-relation.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint-relation.json
@@ -40,7 +40,7 @@
           },
           "metricMode": "Expression",
           "expressions": [
-            "relabels(endpoint_relation_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(endpoint_relation_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "typesOfMQE": [
             "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint.json
index e12978cc9ac4..0a7a7c4bf090 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-endpoint.json
@@ -57,7 +57,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(endpoint_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(endpoint_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-instance-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-instance-relation.json
index c2d7f0a9ced4..4cdf0ea13cdb 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-instance-relation.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-instance-relation.json
@@ -52,7 +52,7 @@
           },
           "metricMode": "Expression",
           "expressions": [
-            "relabels(service_instance_relation_client_percentile,_='P50,P75,P90,P95,P99')"
+            "relabels(service_instance_relation_client_percentile,p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "typesOfMQE": [
             "TIME_SERIES_VALUES"
@@ -279,7 +279,7 @@
           },
           "metricMode": "Expression",
           "expressions": [
-            "relabels(service_instance_relation_server_percentile,_='P50,P75,P90,P95,P99')"
+            "relabels(service_instance_relation_server_percentile,p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "typesOfMQE": [
             "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service-relation.json
index 72cecc1590e1..a340b5b53edb 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service-relation.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service-relation.json
@@ -177,7 +177,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(service_relation_server_percentile,_='P50,P75,P90,P95,P99')"
+                    "relabels(service_relation_server_percentile,p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ]
                 },
                 {
@@ -346,7 +346,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(service_relation_client_percentile,_='P50,P75,P90,P95,P99')"
+                    "relabels(service_relation_client_percentile,p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service.json
index e813c5d79f7b..03a440bcdce9 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/general/general-service.json
@@ -255,7 +255,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(service_percentile{_=\"0,1,2,3,4\"},_=\"P50,P75,P90,P95,P99\")"
+                    "relabels(service_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-endpoint.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-endpoint.json
index 71f82ddcee69..eaa3510f9297 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-endpoint.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-endpoint.json
@@ -52,7 +52,7 @@
                   ],
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(endpoint_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(endpoint_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-instance-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-instance-relation.json
index d1b18e4f492a..e687f4ecf5ac 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-instance-relation.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-instance-relation.json
@@ -62,7 +62,7 @@
           ],
           "metricMode": "Expression",
           "expressions": [
-            "relabels(service_instance_relation_client_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(service_instance_relation_client_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "typesOfMQE": [
             "TIME_SERIES_VALUES"
@@ -277,7 +277,7 @@
           ],
           "metricMode": "Expression",
           "expressions": [
-            "relabels(service_instance_relation_server_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(service_instance_relation_server_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "typesOfMQE": [
             "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service-relation.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service-relation.json
index a450c4ef1307..363694d92f0d 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service-relation.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service-relation.json
@@ -76,7 +76,7 @@
                   ],
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(service_relation_server_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(service_relation_server_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
@@ -222,7 +222,7 @@
                   ],
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(service_relation_client_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+                    "relabels(service_relation_client_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service.json
index bc9325b3923c..3760a4dc0e37 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/mesh/mesh-service.json
@@ -211,7 +211,7 @@
                   ],
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(service_percentile{_=\"0,1,2,3,4\"},_=\"P50,P75,P90,P95,P99\")"
+                    "relabels(service_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-instance.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-instance.json
index fe0d9eca0aff..7e8961a71767 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-instance.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-instance.json
@@ -210,9 +210,9 @@
       "isRoot": false,
       "isDefault": true,
       "expressions": [
-        "avg(meter_nginx_instance_http_status{_='200'})",
-        "avg(meter_nginx_instance_http_status{_='404'})",
-        "avg(meter_nginx_instance_http_status{_='500'})"
+        "avg(meter_nginx_instance_http_status{status='200'})",
+        "avg(meter_nginx_instance_http_status{status='404'})",
+        "avg(meter_nginx_instance_http_status{status='500'})"
       ],
       "expressionsConfig": [
         {
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-service.json
index 59b83f6c8cee..317f7fa1998e 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/nginx/nginx-service.json
@@ -290,9 +290,9 @@
       "isRoot": false,
       "isDefault": true,
       "expressions": [
-        "avg(meter_nginx_service_http_status{_='200'})",
-        "avg(meter_nginx_service_http_status{_='404'})",
-        "avg(meter_nginx_service_http_status{_='500'})"
+        "avg(meter_nginx_service_http_status{status='200'})",
+        "avg(meter_nginx_service_http_status{status='404'})",
+        "avg(meter_nginx_service_http_status{status='500'})"
       ],
       "expressionsConfig": [
         {
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json
index 99d0edf1d1f1..00f5453dc333 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/so11y_oap/so11y-instance.json
@@ -193,7 +193,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(meter_oap_instance_persistence_prepare_percentile{_='50,75,90,95,99'},_='P50,P75,P90,P95,P99')"
+                    "relabels(meter_oap_instance_persistence_prepare_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
@@ -219,7 +219,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(meter_oap_instance_persistence_execute_percentile{_='50,75,90,95,99'},_='P50,P75,P90,P95,P99')"
+                    "relabels(meter_oap_instance_persistence_execute_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
@@ -430,7 +430,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(meter_oap_instance_trace_latency_percentile{_='50,75,90,95,99'},_='P50,P75,P90,P95,P99')"
+                    "relabels(meter_oap_instance_trace_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
@@ -488,7 +488,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(meter_oap_instance_mesh_latency_percentile{_='50,75,90,95,99'},_='P50,P75,P90,P95,P99')"
+                    "relabels(meter_oap_instance_mesh_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
@@ -546,7 +546,7 @@
                   },
                   "metricMode": "Expression",
                   "expressions": [
-                    "relabels(meter_oap_instance_k8s_als_latency_percentile{_='50,75,90,95,99'},_='P50,P75,P90,P95,P99')"
+                    "relabels(meter_oap_instance_k8s_als_latency_percentile{p='50,75,90,95,99'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
                   ],
                   "typesOfMQE": [
                     "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_cache/virtual-cache-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_cache/virtual-cache-service.json
index 5154f30a3f29..c67051a7cbaf 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_cache/virtual-cache-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_cache/virtual-cache-service.json
@@ -165,7 +165,7 @@
             "showYAxis": true
           },
           "expressions": [
-            "relabels(cache_access_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(cache_access_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "metricMode": "Expression",
           "typesOfMQE": [
@@ -455,7 +455,7 @@
             "showYAxis": true
           },
           "expressions": [
-            "relabels(cache_read_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(cache_read_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "metricMode": "Expression",
           "typesOfMQE": [
@@ -548,7 +548,7 @@
             "showYAxis": true
           },
           "expressions": [
-            "relabels(cache_write_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(cache_write_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "metricMode": "Expression",
           "typesOfMQE": [
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_database/virtual-database-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_database/virtual-database-service.json
index 9e861801e57d..84386312d35f 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_database/virtual-database-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_database/virtual-database-service.json
@@ -142,7 +142,7 @@
           ],
           "metricMode": "Expression",
           "expressions": [
-            "relabels(database_access_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(database_access_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "typesOfMQE": [
             "TIME_SERIES_VALUES"
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-endpoint.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-endpoint.json
index 4f6e06f16b90..02e18c808cd5 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-endpoint.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-endpoint.json
@@ -128,7 +128,7 @@
             "showYAxis": true
           },
           "expressions": [
-            "relabels(mq_endpoint_consume_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(mq_endpoint_consume_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "metricMode": "Expression",
           "typesOfMQE": [
diff --git a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-service.json b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-service.json
index 388e3dae6c1e..3b81b5764c13 100644
--- a/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-service.json
+++ b/oap-server/server-starter/src/main/resources/ui-initialized-templates/virtual_mq/virtual-mq-service.json
@@ -128,7 +128,7 @@
             "showYAxis": true
           },
           "expressions": [
-            "relabels(mq_service_consume_percentile{_='0,1,2,3,4'},_='P50,P75,P90,P95,P99')"
+            "relabels(mq_service_consume_percentile{p='0,1,2,3,4'},p='50,75,90,95,99',p='P50,P75,P90,P95,P99')"
           ],
           "metricMode": "Expression",
           "typesOfMQE": [
diff --git a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBMetricsQueryDAO.java b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBMetricsQueryDAO.java
index 6ca8e2f88b01..5d98f933f13b 100644
--- a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBMetricsQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBMetricsQueryDAO.java
@@ -22,6 +22,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -41,6 +42,7 @@
 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.KeyValue;
 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;
@@ -49,6 +51,8 @@
 import org.apache.skywalking.oap.server.storage.plugin.banyandb.stream.AbstractBanyanDBDAO;
 import org.apache.skywalking.oap.server.storage.plugin.banyandb.util.ByteUtil;
 
+import static java.util.Objects.nonNull;
+
 @Slf4j
 public class BanyanDBMetricsQueryDAO extends AbstractBanyanDBDAO implements IMetricsQueryDAO {
     public BanyanDBMetricsQueryDAO(BanyanDBStorageClient client) {
@@ -101,7 +105,7 @@ private long extractFieldValue(MetadataRegistry.Schema schema, String fieldName,
     }
 
     @Override
-    public List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition, String valueColumnName, List<String> labels, Duration duration) throws IOException {
+    public List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition, String valueColumnName, List<KeyValue> labels, Duration duration) throws IOException {
         Map<Long, DataPoint> idMap = queryByEntityID(condition, valueColumnName, duration);
 
         List<PointOfTime> tsPoints = duration.assembleDurationPoints();
@@ -121,12 +125,59 @@ public List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition,
         }
 
         return Util.sortValues(
-                Util.composeLabelValue(condition, labels, ids, dataTableMap),
+                Util.composeLabelValue(condition.getName(), labels, ids, dataTableMap),
                 ids,
                 ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName())
         );
     }
 
+    public List<MetricsValues> readLabeledMetricsValuesWithoutEntity(final String metricsName,
+                                                    final String valueColumnName,
+                                                    final List<KeyValue> labels,
+                                                    final Duration duration) throws IOException {
+        long startTB = 0;
+        long endTB = 0;
+        if (nonNull(duration)) {
+            startTB = duration.getStartTimeBucketInSec();
+            endTB = duration.getEndTimeBucketInSec();
+        }
+        TimestampRange timestampRange = null;
+        if (startTB > 0 && endTB > 0) {
+            timestampRange = new TimestampRange(TimeBucket.getTimestamp(startTB), TimeBucket.getTimestamp(endTB));
+        }
+        MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(metricsName, duration.getStep());
+        if (schema == null) {
+            throw new IOException("schema is not registered");
+        }
+        MeasureQueryResponse resp = query(
+            schema, ImmutableSet.of(Metrics.ENTITY_ID), ImmutableSet.of(valueColumnName), timestampRange,
+            new QueryBuilder<MeasureQuery>() {
+                @Override
+                protected void apply(MeasureQuery query) {
+                    query.limit(METRICS_VALUES_WITHOUT_ENTITY_LIMIT);
+                }
+            }
+        );
+        if (resp.size() == 0) {
+            return Collections.emptyList();
+        }
+        List<String> ids = new ArrayList<>(resp.size());
+        Map<String, DataTable> dataTableMap = new HashMap<>();
+        for (final DataPoint dp : resp.getDataPoints()) {
+            long timeBucket = TimeBucket.getTimeBucket(dp.getTimestamp(), schema.getMetadata().getDownSampling());
+            String entityID = dp.getTagValue(Metrics.ENTITY_ID);
+            PointOfTime pt = new PointOfTime(timeBucket);
+            String id = pt.id(entityID);
+            ids.add(id);
+            dataTableMap.put(id, new DataTable(dp.getFieldValue(valueColumnName)));
+        }
+        return Util.sortValues(
+            Util.composeLabelValue(metricsName, labels, ids, dataTableMap),
+            ids,
+            ValueColumnMetadata.INSTANCE.getDefaultValue(metricsName)
+        );
+    }
+
     @Override
     public HeatMap readHeatMap(MetricsCondition condition, String valueColumnName, Duration duration) throws IOException {
         Map<Long, DataPoint> idMap = queryByEntityID(condition, valueColumnName, duration);
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetricsQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetricsQueryEsDAO.java
index 77ba74ac5227..48a9e014d7ba 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetricsQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/MetricsQueryEsDAO.java
@@ -24,6 +24,7 @@
 import java.util.Map;
 import java.util.Optional;
 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.RangeQueryBuilder;
 import org.apache.skywalking.library.elasticsearch.requests.search.Search;
@@ -32,6 +33,7 @@
 import org.apache.skywalking.library.elasticsearch.response.Documents;
 import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
 import org.apache.skywalking.library.elasticsearch.response.search.SearchHits;
+import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
 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;
@@ -40,12 +42,14 @@
 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.KeyValue;
 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.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.TimeRangeIndexNameGenerator;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.TimeSeriesUtils;
 
 public class MetricsQueryEsDAO extends EsDAO implements IMetricsQueryDAO {
@@ -108,7 +112,7 @@ public MetricsValues readMetricsValues(final MetricsCondition condition,
     @Override
     public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condition,
                                                         final String valueColumnName,
-                                                        final List<String> labels,
+                                                        final List<KeyValue> labels,
                                                         final Duration duration) {
         final String realValueColumn = IndexController.LogicIndicesRegister.getPhysicalColumnName(condition.getName(), valueColumnName);
         final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
@@ -143,12 +147,51 @@ public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condi
             }
         }
         return Util.sortValues(
-            Util.composeLabelValue(condition, labels, ids, idMap),
+            Util.composeLabelValue(condition.getName(), labels, ids, idMap),
             ids,
             ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName())
         );
     }
 
+    public List<MetricsValues> readLabeledMetricsValuesWithoutEntity(final String metricName,
+                                                    final String valueColumnName,
+                                                    final List<KeyValue> labels,
+                                                    final Duration duration) {
+        final SearchBuilder search = Search.builder().size(METRICS_VALUES_WITHOUT_ENTITY_LIMIT);
+        final BoolQueryBuilder query = Query.bool().must(Query.range(Metrics.TIME_BUCKET)
+                                                              .lte(duration.getEndTimeBucket())
+                                                              .gte(duration.getStartTimeBucket()));
+        if (IndexController.LogicIndicesRegister.isMergedTable(metricName)) {
+                query.must(Query.term(
+                IndexController.LogicIndicesRegister.METRIC_TABLE_NAME,
+                metricName
+            ));
+            search.query(query);
+        }
+        final SearchResponse response = getClient().search(new TimeRangeIndexNameGenerator(
+            IndexController.LogicIndicesRegister.getPhysicalTableName(metricName),
+            duration.getStartTimeBucketInSec(),
+            duration.getEndTimeBucketInSec()), search.build());
+        final String realValueColumn = IndexController.LogicIndicesRegister.getPhysicalColumnName(metricName, valueColumnName);
+        final List<PointOfTime> pointOfTimes = duration.assembleDurationPoints();
+        Map<String, DataTable> idMap = new HashMap<>();
+        List<String> ids = new ArrayList<>(pointOfTimes.size());
+        for (SearchHit searchHit : response.getHits()) {
+            if (searchHit.getSource().get(realValueColumn) != null) {
+                idMap.put(
+                    searchHit.getId(),
+                    new DataTable((String) searchHit.getSource().get(realValueColumn))
+                );
+                ids.add(searchHit.getId());
+            }
+        }
+        return Util.sortValues(
+            Util.composeLabelValue(metricName, labels, ids, idMap),
+            ids,
+            ValueColumnMetadata.INSTANCE.getDefaultValue(metricName)
+        );
+    }
+
     @Override
     public HeatMap readHeatMap(final MetricsCondition condition,
                                final String valueColumnName,
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 943e2a83cf17..09fee64d3dff 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,6 +18,8 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
+import java.util.ArrayList;
+import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
@@ -26,10 +28,12 @@
 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.KVInt;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 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.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.HashMap;
@@ -78,8 +82,6 @@ public MetricsValues readMetricsValues(final MetricsCondition condition,
                        .collect(Collectors.joining(", ", "(", ")"))
                 );
 
-            buildShardingCondition(sql, ids, entityId);
-
             jdbcClient.executeQuery(
                 sql.toString(),
                 resultSet -> {
@@ -104,7 +106,7 @@ public MetricsValues readMetricsValues(final MetricsCondition condition,
     @SneakyThrows
     public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condition,
                                                         final String valueColumnName,
-                                                        final List<String> labels,
+                                                        final List<KeyValue> labels,
                                                         final Duration duration) {
         final var idMap = new HashMap<String, DataTable>();
         final var tables = tableHelper.getTablesForRead(
@@ -129,8 +131,6 @@ public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condi
                        .collect(Collectors.joining(", ", "(", ")"))
                 );
 
-            buildShardingCondition(sql, ids, entityId);
-
             jdbcClient.executeQuery(
                 sql.toString(),
                 resultSet -> {
@@ -146,14 +146,59 @@ public List<MetricsValues> readLabeledMetricsValues(final MetricsCondition condi
                 },
                 ids.toArray(new Object[0]));
         }
-
         return Util.sortValues(
-            Util.composeLabelValue(condition, labels, ids, idMap),
+            Util.composeLabelValue(condition.getName(), labels, ids, idMap),
             ids,
             ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName())
         );
     }
 
+    @SneakyThrows
+    public List<MetricsValues> readLabeledMetricsValuesWithoutEntity(final String metricName,
+                                                    final String valueColumnName,
+                                                    final List<KeyValue> labels,
+                                                    final Duration duration) {
+        final var idMap = new HashMap<String, DataTable>();
+        final var tables = tableHelper.getTablesForRead(
+            metricName,
+            duration.getStartTimeBucket(),
+            duration.getEndTimeBucket()
+        );
+
+        for (final var table : tables) {
+            final var sql = new StringBuilder("select id, " + valueColumnName + " from " + table)
+                .append(" where ").append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? ")
+                .append(" and ")
+                .append(Metrics.TIME_BUCKET).append(" >= ? ")
+                .append(" and ")
+                .append(Metrics.TIME_BUCKET).append(" <= ?")
+                // Limit the number of results to avoid OOM
+                .append(" limit ").append(METRICS_VALUES_WITHOUT_ENTITY_LIMIT);
+
+            jdbcClient.executeQuery(
+                sql.toString(),
+                resultSet -> {
+                    while (resultSet.next()) {
+                        String id = resultSet.getString("id");
+                        DataTable multipleValues = new DataTable(resultSet.getString(valueColumnName));
+                        idMap.put(id, multipleValues);
+                    }
+                    return null;
+                },
+                metricName, duration.getStartTimeBucket(), duration.getEndTimeBucket());
+        }
+        final var result = idMap.entrySet()
+                                .stream()
+                                .limit(METRICS_VALUES_WITHOUT_ENTITY_LIMIT)
+                                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+        final var ids = new ArrayList<>(result.keySet());
+        return Util.sortValues(
+            Util.composeLabelValue(metricName, labels, ids, result),
+            ids,
+            ValueColumnMetadata.INSTANCE.getDefaultValue(metricName)
+        );
+    }
+
     @Override
     @SneakyThrows
     public HeatMap readHeatMap(final MetricsCondition condition,
@@ -183,8 +228,6 @@ public HeatMap readHeatMap(final MetricsCondition condition,
                        .collect(Collectors.joining(", ", "(", ")"))
                 );
 
-            buildShardingCondition(sql, ids, entityId);
-
             final int defaultValue = ValueColumnMetadata.INSTANCE.getDefaultValue(condition.getName());
 
             jdbcClient.executeQuery(
@@ -203,7 +246,4 @@ public HeatMap readHeatMap(final MetricsCondition condition,
 
         return heatMap;
     }
-
-    protected void buildShardingCondition(StringBuilder sql, List<String> parameters, String entityId) {
-    }
 }


Test patch:
diff --git a/oap-server/analyzer/meter-analyzer/src/test/java/org/apache/skywalking/oap/meter/analyzer/dsl/AnalyzerTest.java b/oap-server/analyzer/meter-analyzer/src/test/java/org/apache/skywalking/oap/meter/analyzer/dsl/AnalyzerTest.java
index 8618b7631e10..a1868fdfc95b 100644
--- a/oap-server/analyzer/meter-analyzer/src/test/java/org/apache/skywalking/oap/meter/analyzer/dsl/AnalyzerTest.java
+++ b/oap-server/analyzer/meter-analyzer/src/test/java/org/apache/skywalking/oap/meter/analyzer/dsl/AnalyzerTest.java
@@ -163,18 +163,18 @@ public void testLabeled() {
         AvgLabeledFunction t3Cn = actValues.get(IDManager.ServiceInstanceID.buildId(
             IDManager.ServiceID.buildId("t3", true), "cn"));
 
-        assertEquals(50L, t1.getSummation().get(""), 0.0);
-        assertEquals(1L, t1.getCount().get(""), 0.0);
-
-        assertEquals(50L, t1Us.getSummation().get(""), 0.0);
-        assertEquals(100L, t1Us.getSummation().get("10.0.0.1"), 0.0);
-        assertEquals(1L, t1Us.getCount().get(""), 0.0);
-        assertEquals(1L, t1Us.getCount().get("10.0.0.1"), 0.0);
-
-        assertEquals(51L, t3Cn.getSummation().get(""), 0.0);
-        assertEquals(3L, t3Cn.getSummation().get("10.0.0.1"), 0.0);
-        assertEquals(1L, t3Cn.getCount().get(""), 0.0);
-        assertEquals(1L, t3Cn.getCount().get("10.0.0.1"), 0.0);
+        assertEquals(50L, t1.getSummation().get("{instance=}"), 0.0);
+        assertEquals(1L, t1.getCount().get("{instance=}"), 0.0);
+
+        assertEquals(50L, t1Us.getSummation().get("{instance=}"), 0.0);
+        assertEquals(100L, t1Us.getSummation().get("{instance=10.0.0.1}"), 0.0);
+        assertEquals(1L, t1Us.getCount().get("{instance=}"), 0.0);
+        assertEquals(1L, t1Us.getCount().get("{instance=10.0.0.1}"), 0.0);
+
+        assertEquals(51L, t3Cn.getSummation().get("{instance=}"), 0.0);
+        assertEquals(3L, t3Cn.getSummation().get("{instance=10.0.0.1}"), 0.0);
+        assertEquals(1L, t3Cn.getCount().get("{instance=}"), 0.0);
+        assertEquals(1L, t3Cn.getCount().get("{instance=10.0.0.1}"), 0.0);
     }
 
     @Test
diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregateLabelsOpTest.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregateLabelsOpTest.java
index 49a4cf99c47b..690cc4ee22ac 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregateLabelsOpTest.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregateLabelsOpTest.java
@@ -18,6 +18,8 @@
 
 package org.apache.skywalking.mqe.rt;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.skywalking.mqe.rt.grammar.MQEParser;
 import org.apache.skywalking.mqe.rt.operation.AggregateLabelsOp;
 import org.apache.skywalking.mqe.rt.type.ExpressionResult;
@@ -32,22 +34,81 @@ public class AggregateLabelsOpTest {
 
     @Test
     public void seriesLabeledTest() throws Exception {
-        ExpressionResult avgReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(), MQEParser.AVG);
+        ExpressionResult avgReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(),
+                                                                           MQEParser.AVG,
+                                                                           new ArrayList<>());
+        // aggregate no label
+        assertEquals(1, avgReduce.getResults().size());
+        assertEquals(0, avgReduce.getResults().get(0).getMetric().getLabels().size());
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, avgReduce.getType());
         assertEquals((100f + 101f) / 2, avgReduce.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals((300f + 301f) / 2, avgReduce.getResults().get(0).getValues().get(1).getDoubleValue());
 
-        ExpressionResult sumReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(), MQEParser.SUM);
+        // sum label
+        ExpressionResult sumReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(),
+                                                                           MQEParser.SUM,
+                                                                           List.of("label")
+        );
+        assertEquals(2, sumReduce.getResults().size());
+        assertEquals(1, sumReduce.getResults().get(0).getMetric().getLabels().size());
+        assertEquals("label", sumReduce.getResults().get(0).getMetric().getLabels().get(0).getKey());
+        assertEquals(1, sumReduce.getResults().get(1).getMetric().getLabels().size());
+        assertEquals("label", sumReduce.getResults().get(1).getMetric().getLabels().get(0).getKey());
+        assertEquals(ExpressionResultType.TIME_SERIES_VALUES, sumReduce.getType());
+        assertEquals(100, sumReduce.getResults().get(0).getValues().get(0).getDoubleValue());
+        assertEquals(300, sumReduce.getResults().get(0).getValues().get(1).getDoubleValue());
+        assertEquals(101, sumReduce.getResults().get(1).getValues().get(0).getDoubleValue());
+        assertEquals(301, sumReduce.getResults().get(1).getValues().get(1).getDoubleValue());
+
+        // sum label2
+        sumReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(),
+                                                                           MQEParser.SUM,
+                                                                           List.of("label2")
+        );
+        assertEquals(1, sumReduce.getResults().size());
+        assertEquals(1, sumReduce.getResults().get(0).getMetric().getLabels().size());
+        assertEquals("label2", sumReduce.getResults().get(0).getMetric().getLabels().get(0).getKey());
+        assertEquals("21", sumReduce.getResults().get(0).getMetric().getLabels().get(0).getValue());
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, sumReduce.getType());
         assertEquals(100f + 101f, sumReduce.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals(300f + 301f, sumReduce.getResults().get(0).getValues().get(1).getDoubleValue());
 
-        ExpressionResult minReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(), MQEParser.MIN);
+        // sum label and label2
+        sumReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(),
+                                                          MQEParser.SUM,
+                                                          List.of("label", "label2")
+        );
+        assertEquals(2, sumReduce.getResults().size());
+        assertEquals(2, sumReduce.getResults().get(0).getMetric().getLabels().size());
+        assertEquals("label", sumReduce.getResults().get(0).getMetric().getLabels().get(0).getKey());
+        assertEquals("1", sumReduce.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("label2", sumReduce.getResults().get(0).getMetric().getLabels().get(1).getKey());
+        assertEquals("21", sumReduce.getResults().get(0).getMetric().getLabels().get(1).getValue());
+        assertEquals("label", sumReduce.getResults().get(1).getMetric().getLabels().get(0).getKey());
+        assertEquals("2", sumReduce.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("label2", sumReduce.getResults().get(1).getMetric().getLabels().get(1).getKey());
+        assertEquals("21", sumReduce.getResults().get(1).getMetric().getLabels().get(1).getValue());
+        assertEquals(2, sumReduce.getResults().get(1).getMetric().getLabels().size());
+        assertEquals(ExpressionResultType.TIME_SERIES_VALUES, sumReduce.getType());
+        assertEquals(100, sumReduce.getResults().get(0).getValues().get(0).getDoubleValue());
+        assertEquals(300, sumReduce.getResults().get(0).getValues().get(1).getDoubleValue());
+        assertEquals(101, sumReduce.getResults().get(1).getValues().get(0).getDoubleValue());
+        assertEquals(301, sumReduce.getResults().get(1).getValues().get(1).getDoubleValue());
+
+        // min label2
+        ExpressionResult minReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(),
+                                                                           MQEParser.MIN,
+                                                                           List.of("label2")
+        );
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, minReduce.getType());
         assertEquals(100f, minReduce.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals(300f, minReduce.getResults().get(0).getValues().get(1).getDoubleValue());
 
-        ExpressionResult maxReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(), MQEParser.MAX);
+        // max label2
+        ExpressionResult maxReduce = AggregateLabelsOp.doAggregateLabelsOp(mockData.newSeriesLabeledResult(),
+                                                                           MQEParser.MAX,
+                                                                           List.of("label2")
+        );
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, maxReduce.getType());
         assertEquals(101f, maxReduce.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals(301f, maxReduce.getResults().get(0).getValues().get(1).getDoubleValue());
diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregationOpTest.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregationOpTest.java
index 21f71ca08e47..a0fd9f80fb1c 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregationOpTest.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/AggregationOpTest.java
@@ -67,55 +67,79 @@ public void seriesNoLabeledTest() throws Exception {
     public void seriesLabeledTest() throws Exception {
         ExpressionResult avg = AggregationOp.doAggregationOp(mockData.newSeriesLabeledResult(), MQEParser.AVG);
         assertEquals(ExpressionResultType.SINGLE_VALUE, avg.getType());
-        //label=1
+        //label=1, label2=21
         assertNull(avg.getResults().get(0).getValues().get(0).getId());
+        assertEquals("1", avg.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", avg.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(200, avg.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertNull(avg.getResults().get(1).getValues().get(0).getId());
+        assertEquals("2", avg.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", avg.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(201, avg.getResults().get(1).getValues().get(0).getDoubleValue());
 
         ExpressionResult count = AggregationOp.doAggregationOp(mockData.newSeriesLabeledResult(), MQEParser.COUNT);
         assertEquals(ExpressionResultType.SINGLE_VALUE, avg.getType());
-        //label=1
+        //label=1, label2=21
         assertNull(count.getResults().get(0).getValues().get(0).getId());
+        assertEquals("1", count.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", count.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(2, count.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertNull(count.getResults().get(1).getValues().get(0).getId());
+        assertEquals("2", count.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", count.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(2, count.getResults().get(1).getValues().get(0).getDoubleValue());
 
         ExpressionResult sum = AggregationOp.doAggregationOp(mockData.newSeriesLabeledResult(), MQEParser.SUM);
         assertEquals(ExpressionResultType.SINGLE_VALUE, avg.getType());
-        //label=1
+        //label=1, label2=21
         assertNull(sum.getResults().get(0).getValues().get(0).getId());
+        assertEquals("1", sum.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", sum.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(400, sum.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertNull(sum.getResults().get(1).getValues().get(0).getId());
+        assertEquals("2", sum.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", sum.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(402, sum.getResults().get(1).getValues().get(0).getDoubleValue());
 
         ExpressionResult latest = AggregationOp.doAggregationOp(mockData.newSeriesLabeledResult(), MQEParser.LATEST);
         assertEquals(ExpressionResultType.SINGLE_VALUE, avg.getType());
-        //label=1
+        //label=1, label2=21
+        assertEquals("1", latest.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", latest.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("300", latest.getResults().get(0).getValues().get(0).getId());
         assertEquals(300, latest.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
+        assertEquals("2", latest.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", latest.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("300", latest.getResults().get(1).getValues().get(0).getId());
         assertEquals(301, latest.getResults().get(1).getValues().get(0).getDoubleValue());
 
         ExpressionResult max = AggregationOp.doAggregationOp(mockData.newSeriesLabeledResult(), MQEParser.MAX);
         assertEquals(ExpressionResultType.SINGLE_VALUE, avg.getType());
-        //label=1
+        //label=1, label2=21
+        assertEquals("1", max.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", max.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("300", max.getResults().get(0).getValues().get(0).getId());
         assertEquals(300, max.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
+        assertEquals("2", max.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", max.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("300", max.getResults().get(1).getValues().get(0).getId());
         assertEquals(301, max.getResults().get(1).getValues().get(0).getDoubleValue());
 
         ExpressionResult min = AggregationOp.doAggregationOp(mockData.newSeriesLabeledResult(), MQEParser.MIN);
         assertEquals(ExpressionResultType.SINGLE_VALUE, avg.getType());
-        //label=1
+        //label=1, label2=21
+        assertEquals("1", min.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", min.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", min.getResults().get(0).getValues().get(0).getId());
         assertEquals(100, min.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
+        assertEquals("2", min.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", min.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", min.getResults().get(1).getValues().get(0).getId());
         assertEquals(101, min.getResults().get(1).getValues().get(0).getDoubleValue());
     }
diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
index 016f04d73197..74b458c106ba 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/BinaryOpTest.java
@@ -79,14 +79,16 @@ public void seriesLabeledTest() throws Exception {
         //seriesLabeled + seriesNoLabeled
         ExpressionResult add = BinaryOp.doBinaryOp(mockData.newSeriesLabeledResult(), mockData.newSeriesNoLabeledResult(), MQEParser.ADD);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(0).getValues().get(0).getId());
         assertEquals(200, add.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(0).getValues().get(1).getId());
         assertEquals(600, add.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(1).getValues().get(0).getId());
         assertEquals(201, add.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(1).getValues().get(1).getId());
@@ -95,14 +97,16 @@ public void seriesLabeledTest() throws Exception {
         //seriesLabeled + seriesLabeled
         add = BinaryOp.doBinaryOp(mockData.newSeriesLabeledResult(), mockData.newSeriesLabeledResult(), MQEParser.ADD);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(0).getValues().get(0).getId());
         assertEquals(200, add.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(0).getValues().get(1).getId());
         assertEquals(600, add.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(1).getValues().get(0).getId());
         assertEquals(202, add.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(1).getValues().get(1).getId());
@@ -111,14 +115,16 @@ public void seriesLabeledTest() throws Exception {
         //seriesNoLabeled - seriesLabeled
         add = BinaryOp.doBinaryOp(mockData.newSeriesNoLabeledResult(), mockData.newSeriesLabeledResult(), MQEParser.SUB);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(0).getValues().get(0).getId());
         assertEquals(0, add.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(0).getValues().get(1).getId());
         assertEquals(0, add.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(1).getValues().get(0).getId());
         assertEquals(-1, add.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(1).getValues().get(1).getId());
@@ -147,14 +153,16 @@ public void many2OneTest() throws Exception {
         //seriesLabeled + single
         add = BinaryOp.doBinaryOp(mockData.newSeriesLabeledResult(), mockData.newSingleResult(1000), MQEParser.ADD);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(0).getValues().get(0).getId());
         assertEquals(1100, add.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(0).getValues().get(1).getId());
         assertEquals(1300, add.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", add.getResults().get(1).getValues().get(0).getId());
         assertEquals(1101, add.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", add.getResults().get(1).getValues().get(1).getId());
@@ -183,14 +191,16 @@ public void one2ManyTest() throws Exception {
         //single - seriesLabeled
         sub = BinaryOp.doBinaryOp(mockData.newSingleResult(1000), mockData.newSeriesLabeledResult(), MQEParser.SUB);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, sub.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", sub.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", sub.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", sub.getResults().get(0).getValues().get(0).getId());
         assertEquals(900, sub.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", sub.getResults().get(0).getValues().get(1).getId());
         assertEquals(700, sub.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", sub.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", sub.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", sub.getResults().get(1).getValues().get(0).getId());
         assertEquals(899, sub.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", sub.getResults().get(1).getValues().get(1).getId());
@@ -209,32 +219,36 @@ public void single2SingleTest() throws IllegalExpressionException {
         add = BinaryOp.doBinaryOp(
             mockData.newSingleLabeledResult(100, 200), mockData.newSingleResult(100), MQEParser.ADD);
         assertEquals(ExpressionResultType.SINGLE_VALUE, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(200, add.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(300, add.getResults().get(1).getValues().get(0).getDoubleValue());
 
         //nolabeled + labeled
         add = BinaryOp.doBinaryOp(
             mockData.newSingleResult(100), mockData.newSingleLabeledResult(100, 200), MQEParser.ADD);
         assertEquals(ExpressionResultType.SINGLE_VALUE, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(200, add.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", add.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(300, add.getResults().get(1).getValues().get(0).getDoubleValue());
 
         //labeled + labeled
         add = BinaryOp.doBinaryOp(
             mockData.newSingleLabeledResult(100, 102), mockData.newSingleLabeledResult(100, 200), MQEParser.ADD);
         assertEquals(ExpressionResultType.SINGLE_VALUE, add.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", add.getResults().get(0).getMetric().getLabels().get(0).getValue());
         assertEquals(200, add.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", add.getResults().get(1).getMetric().getLabels().get(0).getValue());
         assertEquals(302, add.getResults().get(1).getValues().get(0).getDoubleValue());
     }
diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/CompareOPTest.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/CompareOPTest.java
index b0fc02cd5f93..b112cd9ce10d 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/CompareOPTest.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/CompareOPTest.java
@@ -77,14 +77,16 @@ public void seriesLabeledTest() throws Exception {
                                                     mockData.newSeriesNoLabeledResult(100, 200), MQEParser.GT
         );
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(0).getValues().get(0).getId());
         assertEquals(0, gt.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(0).getValues().get(1).getId());
         assertEquals(1, gt.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(1).getValues().get(0).getId());
         assertEquals(1, gt.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(1).getValues().get(1).getId());
@@ -95,14 +97,16 @@ public void seriesLabeledTest() throws Exception {
                                    mockData.newSeriesLabeledResult(100, 300, 101, 200), MQEParser.GT
         );
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(0).getValues().get(0).getId());
         assertEquals(1, gt.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(0).getValues().get(1).getId());
         assertEquals(0, gt.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(1).getValues().get(0).getId());
         assertEquals(0, gt.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(1).getValues().get(1).getId());
@@ -113,14 +117,16 @@ public void seriesLabeledTest() throws Exception {
                                    mockData.newSeriesLabeledResult(100, 300, 101, 201), MQEParser.GT
         );
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(0).getValues().get(0).getId());
         assertEquals(1, gt.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(0).getValues().get(1).getId());
         assertEquals(0, gt.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(1).getValues().get(0).getId());
         assertEquals(0, gt.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(1).getValues().get(1).getId());
@@ -152,14 +158,16 @@ public void many2OneTest() throws Exception {
                                    mockData.newSingleResult(101), MQEParser.GT
         );
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(0).getValues().get(0).getId());
         assertEquals(0, gt.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(0).getValues().get(1).getId());
         assertEquals(1, gt.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(1).getValues().get(0).getId());
         assertEquals(0, gt.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(1).getValues().get(1).getId());
@@ -190,14 +198,16 @@ public void one2ManyTest() throws Exception {
         gt = CompareOp.doCompareOP(mockData.newSingleResult(101),
                                    mockData.newSeriesLabeledResult(100, 200, 200, 100), MQEParser.GT);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(0).getValues().get(0).getId());
         assertEquals(1, gt.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(0).getValues().get(1).getId());
         assertEquals(0, gt.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", gt.getResults().get(1).getValues().get(0).getId());
         assertEquals(0, gt.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", gt.getResults().get(1).getValues().get(1).getId());
@@ -216,33 +226,39 @@ public void single2SingleTest() throws IllegalExpressionException {
         gt = CompareOp.doCompareOP(
             mockData.newSingleLabeledResult(100, 200), mockData.newSingleResult(100), MQEParser.GT);
         assertEquals(ExpressionResultType.SINGLE_VALUE, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(0, gt.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
         assertEquals(1, gt.getResults().get(1).getValues().get(0).getDoubleValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
 
         //nolabeled > labeled
         gt = CompareOp.doCompareOP(
             mockData.newSingleResult(101), mockData.newSingleLabeledResult(100, 200), MQEParser.GT);
         assertEquals(ExpressionResultType.SINGLE_VALUE, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(1, gt.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(0, gt.getResults().get(1).getValues().get(0).getDoubleValue());
 
         //labeled > labeled
         gt = CompareOp.doCompareOP(
             mockData.newSingleLabeledResult(100, 202), mockData.newSingleLabeledResult(100, 200), MQEParser.GT);
         assertEquals(ExpressionResultType.SINGLE_VALUE, gt.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", gt.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals(0, gt.getResults().get(0).getValues().get(0).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", gt.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", gt.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals(1, gt.getResults().get(1).getValues().get(0).getDoubleValue());
     }
 }
diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MathematicalFunctionOpTest.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MathematicalFunctionOpTest.java
index ba5a46824ec6..e63f6a96801d 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MathematicalFunctionOpTest.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MathematicalFunctionOpTest.java
@@ -56,7 +56,6 @@ public void seriesNoLabeledTest() throws Exception {
         assertEquals("300", floor.getResults().get(0).getValues().get(1).getId());
         assertEquals(300, floor.getResults().get(0).getValues().get(1).getDoubleValue());
 
-        MQEParser.ParameterContext parameterContext = new MQEParser.ParameterContext(null, 0);
         ExpressionResult round = MathematicalFunctionOp.doFunction1Op(
             mockData.newSeriesNoLabeledResult(100.111, 300.222), MQEParser.ROUND, 2);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, ceil.getType());
@@ -71,14 +70,16 @@ public void seriesLabeledTest() throws Exception {
         ExpressionResult abs = MathematicalFunctionOp.doFunction0Op(
             mockData.newSeriesLabeledResult(-100.111, -300, -101.333, -301.666), MQEParser.ABS);
         assertEquals(ExpressionResultType.TIME_SERIES_VALUES, abs.getType());
-        //label=1
+        //label=1, label2=21
         assertEquals("1", abs.getResults().get(0).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", abs.getResults().get(0).getMetric().getLabels().get(1).getValue());
         assertEquals("100", abs.getResults().get(0).getValues().get(0).getId());
         assertEquals(100.111, abs.getResults().get(0).getValues().get(0).getDoubleValue());
         assertEquals("300", abs.getResults().get(0).getValues().get(1).getId());
         assertEquals(300, abs.getResults().get(0).getValues().get(1).getDoubleValue());
-        //label=2
+        //label=2, label2=21
         assertEquals("2", abs.getResults().get(1).getMetric().getLabels().get(0).getValue());
+        assertEquals("21", abs.getResults().get(1).getMetric().getLabels().get(1).getValue());
         assertEquals("100", abs.getResults().get(1).getValues().get(0).getId());
         assertEquals(101.333, abs.getResults().get(1).getValues().get(0).getDoubleValue());
         assertEquals("300", abs.getResults().get(1).getValues().get(1).getId());
diff --git a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java
index b4c56ccd904e..92fa7a8a6e33 100644
--- a/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java
+++ b/oap-server/mqe-rt/src/test/java/org/apache/skywalking/mqe/rt/MockData.java
@@ -52,10 +52,12 @@ public ExpressionResult newSeriesLabeledResult() {
         seriesLabeled.setType(ExpressionResultType.TIME_SERIES_VALUES);
         MQEValues mqeValues1 = new MQEValues();
         mqeValues1.setMetric(newMetadata("label", "1"));
+        mqeValues1.getMetric().getLabels().add(new KeyValue("label2", "21"));
         mqeValues1.getValues().add(newMQEValue("100", 100));
         mqeValues1.getValues().add(newMQEValue("300", 300));
         MQEValues mqeValues2 = new MQEValues();
         mqeValues2.setMetric(newMetadata("label", "2"));
+        mqeValues2.getMetric().getLabels().add(new KeyValue("label2", "21"));
         mqeValues2.getValues().add(newMQEValue("100", 101));
         mqeValues2.getValues().add(newMQEValue("300", 301));
         seriesLabeled.getResults().add(mqeValues1);
@@ -69,10 +71,12 @@ public ExpressionResult newSeriesLabeledResult(double id1001, double id3001, dou
         seriesLabeled.setType(ExpressionResultType.TIME_SERIES_VALUES);
         MQEValues mqeValues1 = new MQEValues();
         mqeValues1.setMetric(newMetadata("label", "1"));
+        mqeValues1.getMetric().getLabels().add(new KeyValue("label2", "21"));
         mqeValues1.getValues().add(newMQEValue("100", id1001));
         mqeValues1.getValues().add(newMQEValue("300", id3001));
         MQEValues mqeValues2 = new MQEValues();
         mqeValues2.setMetric(newMetadata("label", "2"));
+        mqeValues2.getMetric().getLabels().add(new KeyValue("label2", "21"));
         mqeValues2.getValues().add(newMQEValue("100", id1002));
         mqeValues2.getValues().add(newMQEValue("300", id3002));
         seriesLabeled.getResults().add(mqeValues1);
@@ -115,9 +119,11 @@ public ExpressionResult newSingleLabeledResult(double id1001, double id1002) {
         result.setType(ExpressionResultType.SINGLE_VALUE);
         MQEValues mqeValues1 = new MQEValues();
         mqeValues1.setMetric(newMetadata("label", "1"));
+        mqeValues1.getMetric().getLabels().add(new KeyValue("label2", "21"));
         mqeValues1.getValues().add(newMQEValue("100", id1001));
         MQEValues mqeValues2 = new MQEValues();
         mqeValues2.setMetric(newMetadata("label", "2"));
+        mqeValues2.getMetric().getLabels().add(new KeyValue("label2", "21"));
         mqeValues2.getValues().add(newMQEValue("100", id1002));
         result.getResults().add(mqeValues1);
         result.getResults().add(mqeValues2);
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java
index 350c0f1e3484..8843102be015 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRuleTest.java
@@ -31,7 +31,6 @@
 import org.apache.skywalking.oap.server.core.analysis.metrics.IntValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.LabeledValueHolder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.metrics.MultiIntValuesHolder;
 import org.apache.skywalking.oap.server.core.query.enumeration.Scope;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
@@ -157,50 +156,18 @@ public void testAlarmMetricsOutOfDate() throws IllegalExpressionException {
         Assertions.assertEquals(0, alarmMessages.size());
     }
 
-    @Test
-    public void testMultipleValuesAlarm() throws IllegalExpressionException {
-        AlarmRule alarmRule = new AlarmRule();
-        alarmRule.setAlarmRuleName("endpoint_multiple_values_rule");
-        alarmRule.setExpression("sum(endpoint_multiple_values > 50) >= 3");
-        alarmRule.getIncludeMetrics().add("endpoint_multiple_values");
-        alarmRule.setPeriod(15);
-        alarmRule.setMessage("response percentile of endpoint {name} is lower than expected values");
-        alarmRule.setTags(new HashMap<String, String>() {{
-            put("key", "value");
-        }});
-        RunningRule runningRule = new RunningRule(alarmRule);
-
-        DateTime startTime = DateTime.now();
-        long timeInPeriod1 = TimeBucket.getMinuteTimeBucket(startTime.minusMinutes(6).getMillis());
-        long timeInPeriod2 = TimeBucket.getMinuteTimeBucket(startTime.minusMinutes(4).getMillis());
-        long timeInPeriod3 = TimeBucket.getMinuteTimeBucket(startTime.minusMinutes(2).getMillis());
-
-        runningRule.in(getMetaInAlarm(123, "endpoint_multiple_values"), getMultipleValueMetrics(timeInPeriod1, 70, 60, 40, 40, 40));
-        runningRule.in(getMetaInAlarm(123, "endpoint_multiple_values"), getMultipleValueMetrics(timeInPeriod2, 60, 60, 40, 40, 40));
-
-        // check at startTime - 4
-        List<AlarmMessage> alarmMessages = runningRule.check();
-        Assertions.assertEquals(0, alarmMessages.size());
-
-        // check at now
-        runningRule.moveTo(startTime.toLocalDateTime());
-        runningRule.in(getMetaInAlarm(123, "endpoint_multiple_values"), getMultipleValueMetrics(timeInPeriod3, 74, 60, 40, 40, 40));
-        alarmMessages = runningRule.check();
-        Assertions.assertEquals(1, alarmMessages.size());
-    }
-
     @Test
     public void testLabeledAlarm() throws IllegalExpressionException {
         ValueColumnMetadata.INSTANCE.putIfAbsent(
             "endpoint_labeled", "testColumn", Column.ValueDataType.LABELED_VALUE, 0, Scope.Endpoint.getScopeId());
         AlarmRule alarmRule = new AlarmRule();
-        alarmRule.setExpression("sum(endpoint_labeled{_='95,99'} > 10) >= 3");
+        alarmRule.setExpression("sum(endpoint_labeled{p='95,99'} > 10) >= 3");
         alarmRule.getIncludeMetrics().add("endpoint_labeled");
-        assertLabeled(alarmRule, "50,17|99,11", "75,15|95,12|99,12", "90,1|99,20", 1);
+        assertLabeled(alarmRule, "{p=50},17|{p=99},11", "{p=75},15|{p=95},12|{p=99},12", "{p=90},1|{p=99},20", 1);
         alarmRule.setExpression("sum(endpoint_labeled > 10) >= 3");
-        assertLabeled(alarmRule, "50,17|99,11", "75,15|95,12|99,12", "90,1|99,20", 1);
+        assertLabeled(alarmRule, "{p=50},17|{p=99},11", "{p=75},15|{p=95},12|{p=99},12", "{p=90},1|{p=99},20", 1);
         alarmRule.setExpression("sum(endpoint_labeled{_='50'} > 10) >= 3");
-        assertLabeled(alarmRule, "50,17|99,11", "75,15|95,12|99,12", "90,1|99,20", 0);
+        assertLabeled(alarmRule, "{p=50},17|{p=99},11", "{p=75},15|{p=95},12|{p=99},12", "{p=90},1|{p=99},20", 0);
     }
 
     @Test
@@ -495,14 +462,6 @@ private Metrics getMetrics(long timeBucket, int value) {
         return mockMetrics;
     }
 
-    private Metrics getMultipleValueMetrics(long timeBucket, int... values) {
-        MockMultipleValueMetrics mockMultipleValueMetrics = new MockMultipleValueMetrics();
-        mockMultipleValueMetrics.setValues(values);
-        mockMultipleValueMetrics.setTimeBucket(timeBucket);
-        return mockMultipleValueMetrics;
-
-    }
-
     private Metrics getLabeledValueMetrics(long timeBucket, String values) {
         MockLabeledValueMetrics mockLabeledValueMetrics = new MockLabeledValueMetrics();
         mockLabeledValueMetrics.setValue(new DataTable(values));
@@ -570,59 +529,6 @@ public int remoteHashCode() {
         }
     }
 
-    private class MockMultipleValueMetrics extends Metrics implements MultiIntValuesHolder {
-        private int[] values;
-
-        public void setValues(int[] values) {
-            this.values = values;
-        }
-
-        @Override
-        protected StorageID id0() {
-            return null;
-        }
-
-        @Override
-        public boolean combine(Metrics metrics) {
-            return true;
-        }
-
-        @Override
-        public void calculate() {
-
-        }
-
-        @Override
-        public Metrics toHour() {
-            return null;
-        }
-
-        @Override
-        public Metrics toDay() {
-            return null;
-        }
-
-        @Override
-        public int[] getValues() {
-            return values;
-        }
-
-        @Override
-        public int remoteHashCode() {
-            return 0;
-        }
-
-        @Override
-        public void deserialize(RemoteData remoteData) {
-
-        }
-
-        @Override
-        public RemoteData.Builder serialize() {
-            return null;
-        }
-    }
-
     private class MockLabeledValueMetrics extends Metrics implements LabeledValueHolder {
 
         @Getter
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunctionTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunctionTest.java
index 69915d289750..4c9ec4951f8c 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunctionTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/PercentileFunctionTest.java
@@ -102,7 +102,7 @@ public void testFunction() {
         );
 
         inst.calculate();
-        final int[] values = inst.getValues();
+        final DataTable values = inst.getValue();
         /**
          * Expected percentile dataset
          * <pre>
@@ -112,10 +112,7 @@ public void testFunction() {
          *     250, 80 <- P90
          * </pre>
          */
-        Assertions.assertArrayEquals(new int[] {
-            100,
-            250
-        }, values);
+        Assertions.assertEquals(new DataTable("{p=50},100|{p=90},250"), values);
     }
 
     @Test
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunctionTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunctionTest.java
index c1067563d78c..9ce21be907ed 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunctionTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/avg/AvgHistogramPercentileFunctionTest.java
@@ -99,7 +99,7 @@ public void testFunction() {
         );
 
         inst.calculate();
-        final int[] values = inst.getValues();
+        final DataTable values = inst.getValue();
         /**
          * Expected percentile dataset
          * <pre>
@@ -109,10 +109,7 @@ public void testFunction() {
          *     250, 40 <- P90
          * </pre>
          */
-        Assertions.assertArrayEquals(new int[] {
-            100,
-            250
-        }, values);
+        Assertions.assertEquals(new DataTable("{p=50},100|{p=90},250"), values);
     }
 
     @Test
@@ -211,7 +208,7 @@ public void testFunctionWhenGroupContainsColon() {
                 40
             }
         );
-        valuesA.setGroup("localhost:3306/swtest");
+        valuesA.setGroup("localhost:3306/swtestA");
 
         PercentileFunctionInst inst = new PercentileFunctionInst();
         inst.accept(
@@ -224,13 +221,13 @@ public void testFunctionWhenGroupContainsColon() {
         BucketedValues valuesB = new BucketedValues(
             BUCKETS,
             new long[] {
-                10,
-                20,
                 30,
-                40
+                40,
+                20,
+                10
             }
         );
-        valuesA.setGroup("localhost:3306/swtest");
+        valuesB.setGroup("localhost:3306/swtestB");
 
         inst.accept(
             MeterEntity.newService("service-test", Layer.GENERAL),
@@ -251,8 +248,11 @@ public void testFunctionWhenGroupContainsColon() {
          *     250, 40 <- P90
          * </pre>
          */
-        assertEquals(new Long(100), values.get("localhost:3306/swtest:50"));
-        assertEquals(new Long(250), values.get("localhost:3306/swtest:90"));
+        assertEquals(
+            new DataTable(
+                "{p=localhost:3306/swtestB:50},50|{p=localhost:3306/swtestA:50},100|{p=localhost:3306/swtestB:90},100|{p=localhost:3306/swtestA:90},250"),
+            values
+        );
     }
 
     private static class PercentileFunctionInst extends AvgHistogramPercentileFunction {
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunctionTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunctionTest.java
index d695e796fcc7..226e40091b90 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunctionTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/analysis/meter/function/sum/SumHistogramPercentileFunctionTest.java
@@ -99,7 +99,7 @@ public void testFunction() {
         );
 
         inst.calculate();
-        final int[] values = inst.getValues();
+        final DataTable values = inst.getValue();
         /**
          * Expected percentile dataset
          * <pre>
@@ -109,10 +109,7 @@ public void testFunction() {
          *     250, 80 <- P90
          * </pre>
          */
-        Assertions.assertArrayEquals(new int[] {
-            100,
-            250
-        }, values);
+        Assertions.assertEquals(new DataTable("{p=50},100|{p=90},250"), values);
     }
 
     @Test
@@ -201,7 +198,7 @@ public void testFunctionWhenGroupContainsColon() {
                 40
             }
         );
-        valuesA.setGroup("localhost:3306/swtest");
+        valuesA.setGroup("localhost:3306/swtestA");
 
         PercentileFunctionInst inst = new PercentileFunctionInst();
         inst.accept(
@@ -214,13 +211,13 @@ public void testFunctionWhenGroupContainsColon() {
         BucketedValues valuesB = new BucketedValues(
             BUCKETS,
             new long[] {
-                10,
-                20,
                 30,
-                40
+                40,
+                20,
+                10
             }
         );
-        valuesB.setGroup("localhost:3306/swtest");
+        valuesB.setGroup("localhost:3306/swtestB");
 
         inst.accept(
             MeterEntity.newService("service-test", Layer.GENERAL),
@@ -241,8 +238,11 @@ public void testFunctionWhenGroupContainsColon() {
          *     250, 80 <- P90
          * </pre>
          */
-        assertEquals(new Long(100), values.get("localhost:3306/swtest:50"));
-        assertEquals(new Long(250), values.get("localhost:3306/swtest:90"));
+        assertEquals(
+            new DataTable(
+                "{p=localhost:3306/swtestB:50},50|{p=localhost:3306/swtestA:50},100|{p=localhost:3306/swtestB:90},100|{p=localhost:3306/swtestA:90},250"),
+            values
+        );
     }
 
     private static class PercentileFunctionInst extends SumHistogramPercentileFunction {
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/query/MetricsQueryUtilTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/query/MetricsQueryUtilTest.java
index cf7b786bcff7..d4e160bfe6cf 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/query/MetricsQueryUtilTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/storage/query/MetricsQueryUtilTest.java
@@ -19,8 +19,10 @@
 package org.apache.skywalking.oap.server.core.storage.query;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import org.apache.skywalking.oap.server.core.analysis.metrics.DataTable;
 import org.apache.skywalking.oap.server.core.query.input.MetricsCondition;
+import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.query.type.MetricsValues;
 import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
 import org.junit.jupiter.api.BeforeEach;
@@ -48,46 +50,45 @@ public class MetricsQueryUtilTest {
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][] {
             {
-                asList("200", "400"),
+                asList(new KeyValue("status", "200"), new KeyValue("status", "400")),
                 asList("202007291425", "202007291426"),
-                of("202007291425", new DataTable("200,1|400,2"), "202007291426", new DataTable("200,3|400,8")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
+                of("202007291425", new DataTable("{status=200},1|{status=400},2"), "202007291426", new DataTable("{status=200},3|{status=400},8")),
+                "[{\"label\":\"{status=200}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
+                    "{\"label\":\"{status=400}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
             },
             {
-                asList("400", "200"),
+                asList(new KeyValue("status", "200"), new KeyValue("status", "400")),
                 asList("202007291425", "202007291426"),
-                of("202007291425", new DataTable("200,1|400,2"), "202007291426", new DataTable("200,3|400,8")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
+                of("202007291425", new DataTable("{status=200},1|{status=400},2"), "202007291426", new DataTable("{status=200},3|{status=400},8")),
+                "[{\"label\":\"{status=200}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
+                    "{\"label\":\"{status=400}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
             },
             {
                 Collections.emptyList(),
                 asList("202007291425", "202007291426"),
-                of("202007291425", new DataTable("200,1|400,2"), "202007291426", new DataTable("200,3|400,8")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
+                of("202007291425", new DataTable("{status=200},1|{status=400},2"), "202007291426", new DataTable("{status=200},3|{status=400},8")),
+                "[{\"label\":\"{status=200}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
+                    "{\"label\":\"{status=400}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
             },
             {
-                Collections.singletonList("200"),
+                Collections.singletonList(new KeyValue("status", "200")),
                 asList("202007291425", "202007291426"),
-                of("202007291425", new DataTable("200,1|400,2"), "202007291426", new DataTable("200,3|400,8")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}]"
+                of("202007291425", new DataTable("{status=200},1|{status=400},2"), "202007291426", new DataTable("{status=200},3|{status=400},8")),
+                "[{\"label\":\"{status=200}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}]"
             },
             {
-                asList("200", "400", "500"),
+                asList(new KeyValue("status", "200"), new KeyValue("status", "400"), new KeyValue("status", "500")),
                 asList("202007291425", "202007291426"),
-                of("202007291425", new DataTable("200,1|400,2"), "202007291426", new DataTable("200,3|400,8")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}," +
-                    "{\"label\":\"500\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":true},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":true}]}}]"
+                of("202007291425", new DataTable("{status=200},1|{status=400},2"), "202007291426", new DataTable("{status=200},3|{status=400},8")),
+                "[{\"label\":\"{status=200}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}," +
+                    "{\"label\":\"{status=400}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":8,\"isEmptyValue\":false}]}}]"
             },
             {
-                asList("200", "400"),
+                asList(new KeyValue("status", "200"), new KeyValue("status", "400")),
                 asList("202007291425", "202007291426"),
-                of("202007291425", new DataTable("200,1|400,2")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":true}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":true}]}}]"
+                of("202007291425", new DataTable("{status=200},1|{status=400},2")),
+                "[{\"label\":\"{status=200}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":true}]}}," +
+                    "{\"label\":\"{status=400}\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":true}]}}]"
             },
         });
     }
@@ -101,17 +102,18 @@ public void setup() {
 
     @ParameterizedTest
     @MethodSource("data")
-    public void testComposeLabelValue(final List<String> queryConditionLabels,
+    public void testComposeLabelValue(final List<KeyValue> queryConditionLabels,
                                       final List<String> datePoints,
                                       final Map<String, DataTable> valueColumnData,
                                       final String expectedResult) {
         MetricsCondition condition = new MetricsCondition();
         condition.setName(MODULE_NAME);
         List<MetricsValues> result = IMetricsQueryDAO.Util.sortValues(
-            IMetricsQueryDAO.Util.composeLabelValue(condition, queryConditionLabels, datePoints, valueColumnData),
+            IMetricsQueryDAO.Util.composeLabelValue(condition.getName(), queryConditionLabels, datePoints, valueColumnData),
             datePoints, DEFAULT_VALUE
         );
-        assertThat(new Gson().toJson(result)).isEqualTo(expectedResult);
+        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+        assertThat(gson.toJson(result)).isEqualTo(expectedResult);
     }
 
 }
diff --git a/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/rt/parser/PromQLExprQueryVisitorTest.java b/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/rt/parser/PromQLExprQueryVisitorTest.java
index 2830b7969a03..60109c8a64ea 100644
--- a/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/rt/parser/PromQLExprQueryVisitorTest.java
+++ b/oap-server/server-query-plugin/promql-plugin/src/test/java/org/apache/skywalking/promql/rt/parser/PromQLExprQueryVisitorTest.java
@@ -25,8 +25,6 @@
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
-import org.apache.skywalking.oap.query.graphql.resolver.MetricsQuery;
-import org.apache.skywalking.oap.query.graphql.resolver.RecordsQuery;
 import org.apache.skywalking.oap.query.promql.entity.TimeValuePair;
 import org.apache.skywalking.oap.query.promql.handler.PromQLApiHandler;
 import org.apache.skywalking.oap.query.promql.rt.result.ParseResultType;
@@ -34,8 +32,11 @@
 import org.apache.skywalking.oap.query.promql.rt.result.ParseResult;
 import org.apache.skywalking.oap.query.promql.rt.PromQLExprQueryVisitor;
 import org.apache.skywalking.oap.query.promql.rt.result.ScalarResult;
+import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.DurationUtils;
+import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
 import org.apache.skywalking.oap.server.core.query.PointOfTime;
+import org.apache.skywalking.oap.server.core.query.RecordQueryService;
 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.MetricsCondition;
@@ -56,8 +57,9 @@
 import static org.mockito.Mockito.mock;
 
 public class PromQLExprQueryVisitorTest {
-    private MetricsQuery metricsQuery;
-    private RecordsQuery recordsQuery;
+    private MetricsQueryService metricsQueryService;
+    private RecordQueryService recordQueryService;
+    private AggregationQueryService aggregationQueryService;
     private Duration duration;
     private static final long TIME_2023022010 = DurationUtils.INSTANCE.parseToDateTime(
                                                            Step.HOUR, 2023022010)
@@ -126,14 +128,15 @@ public void setup() {
                                                  0,
                                                  DefaultScopeDefine.SERVICE
         );
-        metricsQuery = mock(MetricsQuery.class);
-        recordsQuery = mock(RecordsQuery.class);
+        metricsQueryService = mock(MetricsQueryService.class);
+        recordQueryService = mock(RecordQueryService.class);
+        aggregationQueryService = mock(AggregationQueryService.class);
         duration = new Duration();
         duration.setStep(Step.HOUR);
         duration.setStart("2023-02-20 10");
         duration.setEnd("2023-02-20 12");
         Mockito.doReturn(mockMetricsValues())
-               .when(metricsQuery)
+               .when(metricsQueryService)
                .readMetricsValues(any(MetricsCondition.class), any(Duration.class));
     }
 
@@ -160,7 +163,7 @@ public void test(String name,
         CommonTokenStream tokens = new CommonTokenStream(lexer);
         PromQLParser parser = new PromQLParser(tokens);
         ParseTree tree = parser.expression();
-        PromQLExprQueryVisitor visitor = new PromQLExprQueryVisitor(metricsQuery, recordsQuery, duration, queryType);
+        PromQLExprQueryVisitor visitor = new PromQLExprQueryVisitor(metricsQueryService, recordQueryService, aggregationQueryService, duration, queryType);
         ParseResult parseResult = visitor.visit(tree);
         Assertions.assertEquals(wantType, parseResult.getResultType());
         switch (parseResult.getResultType()) {
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetricsTest.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetricsTest.java
index f0d79539532c..e1d15ca5b63c 100644
--- a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetricsTest.java
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetricsTest.java
@@ -146,11 +146,11 @@ public void testReceiveMetrics() throws Throwable {
         String serviceId = IDManager.ServiceID.buildId("zabbix::test-01-hostname", true);
         Assertions.assertEquals(serviceId, avgLabeledFunction.getEntityId());
         Assertions.assertEquals(serviceId, avgLabeledFunction.getServiceId());
-        Assertions.assertEquals(1, avgLabeledFunction.getSummation().get("avg1"), 0.0);
-        Assertions.assertEquals(2, avgLabeledFunction.getSummation().get("avg5"), 0.0);
-        Assertions.assertEquals(3, avgLabeledFunction.getSummation().get("avg15"), 0.0);
-        Assertions.assertEquals(1, avgLabeledFunction.getCount().get("avg1"), 0.0);
-        Assertions.assertEquals(1, avgLabeledFunction.getCount().get("avg5"), 0.0);
-        Assertions.assertEquals(1, avgLabeledFunction.getCount().get("avg15"), 0.0);
+        Assertions.assertEquals(1, avgLabeledFunction.getSummation().get("{2=avg1}"), 0.0);
+        Assertions.assertEquals(2, avgLabeledFunction.getSummation().get("{2=avg5}"), 0.0);
+        Assertions.assertEquals(3, avgLabeledFunction.getSummation().get("{2=avg15}"), 0.0);
+        Assertions.assertEquals(1, avgLabeledFunction.getCount().get("{2=avg1}"), 0.0);
+        Assertions.assertEquals(1, avgLabeledFunction.getCount().get("{2=avg5}"), 0.0);
+        Assertions.assertEquals(1, avgLabeledFunction.getCount().get("{2=avg15}"), 0.0);
     }
 }
diff --git a/test/e2e-v2/cases/alarm/alarm-settings.yml b/test/e2e-v2/cases/alarm/alarm-settings.yml
index abcc8c130aa9..aec113e994ab 100755
--- a/test/e2e-v2/cases/alarm/alarm-settings.yml
+++ b/test/e2e-v2/cases/alarm/alarm-settings.yml
@@ -27,7 +27,7 @@ rules:
       - webhook.custom
   # service_percentile > 10ms
   service_percentile_rule:
-    expression: sum(service_percentile{_='0,1,2,3,4'} > 10) >= 3
+    expression: sum(service_percentile{p='50,75,90,95,99'} > 10) >= 3
     period: 10
     silence-period: 1
     message: Percentile response time of service {name} alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 10, p75 > 10, p90 > 10, p95 > 10, p99 > 10.
diff --git a/test/e2e-v2/cases/apisix/expected/metrics-has-connection-value-label.yml b/test/e2e-v2/cases/apisix/expected/metrics-has-connection-value-label.yml
index 8fed2a881469..3fd8e41c03eb 100644
--- a/test/e2e-v2/cases/apisix/expected/metrics-has-connection-value-label.yml
+++ b/test/e2e-v2/cases/apisix/expected/metrics-has-connection-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
 - metric:
     labels:
-      - key: _
+      - key: state
         value: "reading"
   values:
     {{- contains .values }}
@@ -31,7 +31,7 @@ results:
     {{- end}}
 - metric:
     labels:
-      - key: _
+      - key: state
         value: "waiting"
   values:
     {{- contains .values }}
diff --git a/test/e2e-v2/cases/apisix/expected/metrics-has-latency-value-label.yml b/test/e2e-v2/cases/apisix/expected/metrics-has-latency-value-label.yml
index d335184b84b2..730fee5ef2ff 100644
--- a/test/e2e-v2/cases/apisix/expected/metrics-has-latency-value-label.yml
+++ b/test/e2e-v2/cases/apisix/expected/metrics-has-latency-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
 - metric:
     labels:
-      - key: _
+      - key: p
         value: "apisix:50"
   values:
     {{- contains .values }}
@@ -31,7 +31,7 @@ results:
     {{- end}}
 - metric:
     labels:
-      - key: _
+      - key: p
         value: "apisix:99"
   values:
     {{- contains .values }}
@@ -44,7 +44,7 @@ results:
     {{- end}}
 - metric:
     labels:
-      - key: _
+      - key: p
         value: "request:99"
   values:
     {{- contains .values }}
diff --git a/test/e2e-v2/cases/apisix/expected/metrics-has-status-value-label.yml b/test/e2e-v2/cases/apisix/expected/metrics-has-status-value-label.yml
index 5b3701534ae5..d1d5641455c2 100644
--- a/test/e2e-v2/cases/apisix/expected/metrics-has-status-value-label.yml
+++ b/test/e2e-v2/cases/apisix/expected/metrics-has-status-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
 - metric:
     labels:
-      - key: _
+      - key: code
         value: "200"
   values:
     {{- contains .values }}
diff --git a/test/e2e-v2/cases/browser/expected/metrics-has-value-percentile.yml b/test/e2e-v2/cases/browser/expected/metrics-has-value-percentile.yml
index c8f04b0ea437..8d82892480be 100644
--- a/test/e2e-v2/cases/browser/expected/metrics-has-value-percentile.yml
+++ b/test/e2e-v2/cases/browser/expected/metrics-has-value-percentile.yml
@@ -16,70 +16,57 @@
 type: TIME_SERIES_VALUES
 results:
   {{- contains .results }}
-  - metric:
-      labels:
-        - key: _
-          value: "P50"
-    values:
-      {{- contains .values }}
-      - id: {{ notEmpty .id }}
-        value: {{ .value }}
-        traceid: null
-      - id: {{ notEmpty .id }}
-        value: null
-        traceid: null
-      {{- end}}
-  - metric:
-      labels:
-        - key: _
-          value: "P75"
-    values:
-      {{- contains .values }}
-      - id: {{ notEmpty .id }}
-        value: {{ .value }}
-        traceid: null
-      - id: {{ notEmpty .id }}
-        value: null
-        traceid: null
-      {{- end}}
-  - metric:
-      labels:
-        - key: _
-          value: "P90"
-    values:
-      {{- contains .values }}
-      - id: {{ notEmpty .id }}
-        value: {{ .value }}
-        traceid: null
-      - id: {{ notEmpty .id }}
-        value: null
-        traceid: null
-      {{- end}}
-  - metric:
-        labels:
-          - key: _
-            value: "P95"
-      values:
-        {{- contains .values }}
-        - id: {{ notEmpty .id }}
-          value: {{ .value }}
-          traceid: null
-        - id: {{ notEmpty .id }}
-          value: null
-          traceid: null
-        {{- end}}
-  - metric:
-      labels:
-        - key: _
-          value: "P99"
-    values:
-      {{- contains .values }}
-      - id: {{ notEmpty .id }}
-        value: {{ .value }}
-        traceid: null
-      - id: {{ notEmpty .id }}
-        value: null
-        traceid: null
-      {{- end}}
+- metric:
+    labels:
+      - key: p
+        value: "50"
+  values:
+    {{- contains .values }}
+    - id: {{ notEmpty .id }}
+      value: {{ .value }}
+      traceid: null
+    - id: {{ notEmpty .id }}
+      value: null
+      traceid: null
+    {{- end}}
+- metric:
+    labels:
+      - key: p
+        value: "75"
+  values:
+    {{- contains .values }}
+    - id: {{ notEmpty .id }}
+      value: {{ .value }}
+      traceid: null
+    - id: {{ notEmpty .id }}
+      value: null
+      traceid: null
+    {{- end}}
+- metric:
+    labels:
+      - key: p
+        value: "90"
+  values:
+    {{- contains .values }}
+    - id: {{ notEmpty .id }}
+      value: {{ .value }}
+      traceid: null
+    - id: {{ notEmpty .id }}
+      value: null
+      traceid: null
+    {{- end}}
+- metric:
+    labels:
+      - key: p
+        value: "99"
+  values:
+    {{- contains .values }}
+    - id: {{ notEmpty .id }}
+      value: {{ .value }}
+      traceid: null
+    - id: {{ notEmpty .id }}
+      value: null
+      traceid: null
+    {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/clickhouse/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/clickhouse/expected/metrics-has-value-label.yml
index a94c3c4ba00c..3d71dad534ca 100644
--- a/test/e2e-v2/cases/clickhouse/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/clickhouse/expected/metrics-has-value-label.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: service_instance_id
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/elasticsearch/elasticsearch-cases.yaml b/test/e2e-v2/cases/elasticsearch/elasticsearch-cases.yaml
index ca9cd4ee8213..778742a65681 100644
--- a/test/e2e-v2/cases/elasticsearch/elasticsearch-cases.yaml
+++ b/test/e2e-v2/cases/elasticsearch/elasticsearch-cases.yaml
@@ -20,7 +20,7 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service ls
     expected: expected/service.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_cluster_health_status --service-name=elasticsearch::cluster-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-color.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_cluster_breakers_tripped --service-name=elasticsearch::cluster-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_cluster_cpu_usage_avg --service-name=elasticsearch::cluster-e2e
@@ -52,7 +52,7 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance ls --service-name=elasticsearch::cluster-e2e
     expected: expected/instance.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_rules --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-node.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_jvm_memory_heap_used --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_jvm_memory_nonheap_used --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
@@ -60,11 +60,11 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_jvm_memory_heap_max --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_jvm_memory_pool_peak_used --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-pool.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_jvm_gc_count --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-gc.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_jvm_gc_time --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-gc.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_process_cpu_percent --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_indices_docs --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
@@ -106,9 +106,9 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_indices_translog_size --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_breakers_tripped --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-breaker.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_breakers_estimated_size --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-breaker.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_indices_docs --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_indices_docs_deleted_total --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
@@ -128,9 +128,9 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_network_receive_bytes --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_disk_usage_percent --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-mount.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_node_disk_usage --service-name=elasticsearch::cluster-e2e --instance-name=node-e2e
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-mount.yml
 
   # endpoint cases
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql endpoint ls --service-name=elasticsearch::cluster-e2e
@@ -200,7 +200,7 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_index_stats_indexing_throttle_time_seconds_total --service-name=elasticsearch::cluster-e2e --endpoint-name=e2e-index-0
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_index_indices_shards_docs --service-name=elasticsearch::cluster-e2e --endpoint-name=e2e-index-0
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-primary.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_index_indices_docs_primary_rate --service-name=elasticsearch::cluster-e2e --endpoint-name=e2e-index-0
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_index_stats_indexing_index_total_req_rate --service-name=elasticsearch::cluster-e2e --endpoint-name=e2e-index-0
@@ -216,4 +216,4 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_index_search_suggest_avg_time --service-name=elasticsearch::cluster-e2e --endpoint-name=e2e-index-0
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_elasticsearch_index_search_scroll_avg_time --service-name=elasticsearch::cluster-e2e --endpoint-name=e2e-index-0
-    expected: expected/metrics-has-value.yml
\ No newline at end of file
+    expected: expected/metrics-has-value.yml
diff --git a/test/e2e-v2/cases/meter/expected/metrics-has-value-percentile.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-breaker.yml
similarity index 56%
rename from test/e2e-v2/cases/meter/expected/metrics-has-value-percentile.yml
rename to test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-breaker.yml
index 9f9935ba8f6b..597fe507fd35 100644
--- a/test/e2e-v2/cases/meter/expected/metrics-has-value-percentile.yml
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-breaker.yml
@@ -13,35 +13,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-{{- contains . }}
-- key: 0
-  value:
-  {{- contains .value }}
-  - key: {{ notEmpty .key }}
-    value: {{ gt .value 0 }}
-  {{- end }}
-- key: 1
-  value:
-  {{- contains .value }}
-  - key: {{ notEmpty .key }}
-    value: {{ gt .value 0 }}
-  {{- end }}
-- key: 2
-  value:
-  {{- contains .value }}
-  - key: {{ notEmpty .key }}
-    value: {{ gt .value 0 }}
-  {{- end }}
-- key: 3
-  value:
-  {{- contains .value }}
-  - key: {{ notEmpty .key }}
-    value: {{ gt .value 0 }}
-  {{- end }}
-- key: 4
-  value:
-  {{- contains .value }}
-  - key: {{ notEmpty .key }}
-    value: {{ gt .value 0 }}
-  {{- end }}
-{{- end }}
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: breaker
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-color.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-color.yml
new file mode 100644
index 000000000000..851c6351a48d
--- /dev/null
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-color.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: color
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/redis/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-gc.yml
similarity index 98%
rename from test/e2e-v2/cases/redis/expected/metrics-has-value-label.yml
rename to test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-gc.yml
index a94c3c4ba00c..719fbdb38dd9 100644
--- a/test/e2e-v2/cases/redis/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-gc.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: gc
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-mount.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-mount.yml
new file mode 100644
index 000000000000..0e210ea22a59
--- /dev/null
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-mount.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: mount
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-node.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-node.yml
new file mode 100644
index 000000000000..b11014e49fdf
--- /dev/null
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-node.yml
@@ -0,0 +1,41 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: es_master_node
+          value: {{ .value }}
+        - key: es_ingest_node
+          value: {{ .value }}
+        - key: es_client_node
+          value: {{ .value }}
+        - key: es_data_node
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-pool.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-pool.yml
new file mode 100644
index 000000000000..ad6bd8c54bcf
--- /dev/null
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-pool.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: pool
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-primary.yml b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-primary.yml
new file mode 100644
index 000000000000..f06e3ff79483
--- /dev/null
+++ b/test/e2e-v2/cases/elasticsearch/expected/metrics-has-value-label-primary.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: primary
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/gateway/expected/metrics-has-value-percentile.yml b/test/e2e-v2/cases/gateway/expected/metrics-has-value-percentile.yml
index a94c3c4ba00c..0e662e432fd5 100644
--- a/test/e2e-v2/cases/gateway/expected/metrics-has-value-percentile.yml
+++ b/test/e2e-v2/cases/gateway/expected/metrics-has-value-percentile.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: p
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/istio/metrics/e2e.yaml b/test/e2e-v2/cases/istio/metrics/e2e.yaml
index 9e22f30d40b6..a58434a208a6 100644
--- a/test/e2e-v2/cases/istio/metrics/e2e.yaml
+++ b/test/e2e-v2/cases/istio/metrics/e2e.yaml
@@ -195,13 +195,13 @@ verify:
 
     # service instance labeled metrics: e2e::productpage, label: e2e::details
     - query: |
-        swctl --display yaml --base-url=http://${service_skywalking_ui_host}:${service_skywalking_ui_80}/graphql metrics exec --expression=envoy_cluster_membership_healthy{_=\"e2e::details\"} --service-name=e2e::productpage --instance-name=$( \
+        swctl --display yaml --base-url=http://${service_skywalking_ui_host}:${service_skywalking_ui_80}/graphql metrics exec --expression=envoy_cluster_membership_healthy{cluster_name=\"e2e::details\"} --service-name=e2e::productpage --instance-name=$( \
           swctl --display yaml --base-url=http://${service_skywalking_ui_host}:${service_skywalking_ui_80}/graphql instance list --service-name=e2e::productpage | yq e '.[0].name' -
         )
       expected: expected/metrics-has-value-label.yml
     # service instance labeled metrics: e2e::productpage, label: e2e::details
     - query: |
-        swctl --display yaml --base-url=http://${service_skywalking_ui_host}:${service_skywalking_ui_80}/graphql metrics exec --expression=envoy_cluster_membership_healthy{_=\"e2e::details\"} --service-name=e2e::istio-ingressgateway --instance-name=$( \
+        swctl --display yaml --base-url=http://${service_skywalking_ui_host}:${service_skywalking_ui_80}/graphql metrics exec --expression=envoy_cluster_membership_healthy{cluster_name=\"e2e::details\"} --service-name=e2e::istio-ingressgateway --instance-name=$( \
           swctl --display yaml --base-url=http://${service_skywalking_ui_host}:${service_skywalking_ui_80}/graphql instance list --service-name=e2e::istio-ingressgateway | yq e '.[0].name' -
         )
       expected: expected/metrics-has-value-label.yml
diff --git a/test/e2e-v2/cases/istio/metrics/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/istio/metrics/expected/metrics-has-value-label.yml
index f104821907b4..5e2caa95e842 100644
--- a/test/e2e-v2/cases/istio/metrics/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/istio/metrics/expected/metrics-has-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: cluster_name
           value: e2e::details
     values:
       {{- contains .values }}
diff --git a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-gc-label.yml b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-gc-label.yml
index 32b9ad9a37ab..c7ab630ae021 100644
--- a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-gc-label.yml
+++ b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-gc-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: gc
           value: "G1 Young Generation"
     values:
       {{- contains .values }}
@@ -31,7 +31,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: gc
           value: "G1 Old Generation"
     values:
       {{- contains .values }}
@@ -43,4 +43,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-instance-label.yml b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-instance-label.yml
index 0b1bf730f972..17a1a9bf3299 100644
--- a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-instance-label.yml
+++ b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-instance-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: delayedOperation
           value: "Produce"
     values:
       {{- contains .values }}
@@ -31,7 +31,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: delayedOperation
           value: "Fetch"
     values:
       {{- contains .values }}
@@ -43,4 +43,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-jvm-label.yml b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-jvm-label.yml
index e0bac368583e..01c0c684be6d 100644
--- a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-jvm-label.yml
+++ b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-jvm-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: area
           value: "heap"
     values:
       {{- contains .values }}
@@ -30,4 +30,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-service-label.yml b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-service-label.yml
index c39b4ecf0422..7e7739786899 100644
--- a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-service-label.yml
+++ b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-service-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-      - key: _
+      - key: broker
         value: broker1:7071
     values:
       {{- contains .values }}
@@ -30,4 +30,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-source-label.yml b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-source-label.yml
index 55fd7676e807..c1c7e66a544e 100644
--- a/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-source-label.yml
+++ b/test/e2e-v2/cases/kafka/kafka-monitoring/expected/metrics-has-value-source-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: request
           value: "Produce"
     values:
       {{- contains .values }}
@@ -31,7 +31,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: request
           value: "FetchFollower"
     values:
       {{- contains .values }}
@@ -44,7 +44,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: request
           value: "FetchConsumer"
     values:
       {{- contains .values }}
@@ -56,4 +56,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-assert.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-assert.yml
new file mode 100644
index 000000000000..65f46708524c
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-assert.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: assert_type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-count.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-count.yml
new file mode 100644
index 000000000000..c07f2c2f0711
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-count.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: count_type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-csr.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-csr.yml
new file mode 100644
index 000000000000..3adabbb74b65
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-csr.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: csr_type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-database.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-database.yml
new file mode 100644
index 000000000000..ef06d00a0233
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-database.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: database
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-doc.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-doc.yml
new file mode 100644
index 000000000000..043ab3ab01ff
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-doc.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: doc_op_type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-ins.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-ins.yml
new file mode 100644
index 000000000000..3d71dad534ca
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-ins.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: service_instance_id
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-legacy.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-legacy.yml
new file mode 100644
index 000000000000..6fad1a02c00a
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-legacy.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: legacy_op_type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-member.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-member.yml
new file mode 100644
index 000000000000..e3fd1c20c7aa
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-member.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: member_state
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-op.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-op.yml
new file mode 100644
index 000000000000..50c860977f85
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-op.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: op_type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-version.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-version.yml
new file mode 100644
index 000000000000..71da7190d028
--- /dev/null
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label-version.yml
@@ -0,0 +1,37 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: edition
+          value: {{ .value }}
+        - key: mongodb
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label.yml
index a94c3c4ba00c..ddca546b826d 100644
--- a/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/mongodb/expected/metrics-has-value-label.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: rs_nm
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/mongodb/mongodb-cases.yaml b/test/e2e-v2/cases/mongodb/mongodb-cases.yaml
index b6178214b49f..208aeccdf391 100644
--- a/test/e2e-v2/cases/mongodb/mongodb-cases.yaml
+++ b/test/e2e-v2/cases/mongodb/mongodb-cases.yaml
@@ -20,7 +20,7 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service ls
     expected: expected/service.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_uptime --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-ins.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_data_size --service-name=mongodb::replset
     expected: expected/metrics-has-value-label.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_collection_count --service-name=mongodb::replset
@@ -28,23 +28,23 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_object_count --service-name=mongodb::replset
     expected: expected/metrics-has-value-label.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_document_avg_qps --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-doc.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_operation_avg_qps --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-legacy.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_connections --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-ins.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_cursor_avg --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-csr.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_repl_lag --service-name=mongodb::replset
     expected: expected/metrics-has-value-label.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_db_data_size --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-database.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_db_index_size --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-database.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_db_collection_count --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-database.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_cluster_db_index_count --service-name=mongodb::replset
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-database.yml
 
   # instance cases
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance ls --service-name=mongodb::replset
@@ -58,9 +58,9 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_memory_usage --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_version --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-version.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_rs_state --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-member.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_cpu_total_percentage --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_network_bytes_in --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
@@ -88,21 +88,21 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_transactions_inactive --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_document_qps --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-doc.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_operation_qps --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-legacy.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_repl_operation_qps --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-legacy.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_operation_latency --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-op.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_cursor --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-csr.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_mem_virtual --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_mem_resident --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_asserts --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-assert.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_repl_buffer_count --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_repl_buffer_size --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
@@ -110,10 +110,10 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_repl_buffer_size_max --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_queued_operation --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-count.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_write_wait_num --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_write_wait_timeout_num --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_mongodb_node_write_wait_time --service-name=mongodb::replset --instance-name=mongodb-exporter-1:9216
-    expected: expected/metrics-has-value.yml
\ No newline at end of file
+    expected: expected/metrics-has-value.yml
diff --git a/test/e2e-v2/cases/mqe/docker-compose.yml b/test/e2e-v2/cases/mqe/docker-compose.yml
index be02077e5ea8..7832ef055df9 100644
--- a/test/e2e-v2/cases/mqe/docker-compose.yml
+++ b/test/e2e-v2/cases/mqe/docker-compose.yml
@@ -20,6 +20,8 @@ services:
     extends:
       file: ../../script/docker-compose/base-compose.yml
       service: oap
+    volumes:
+      - ./oal/core.oal:/skywalking/config/oal/core.oal
     ports:
       - 12800
     networks:
diff --git a/test/e2e-v2/cases/mqe/expected/labels-old.yml b/test/e2e-v2/cases/mqe/expected/labels-old.yml
new file mode 100644
index 000000000000..1c0ffe628501
--- /dev/null
+++ b/test/e2e-v2/cases/mqe/expected/labels-old.yml
@@ -0,0 +1,59 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+{{- contains .results }}
+  - metric:
+      labels:
+        - key: _
+          value: "0"
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  - metric:
+      labels:
+        - key: _
+          value: "1"
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  - metric:
+      labels:
+        - key: _
+          value: "2"
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+{{- end}}
+error: null
diff --git a/test/e2e-v2/cases/mqe/expected/relabels-OP.yml b/test/e2e-v2/cases/mqe/expected/relabels-OP.yml
index 202fb5904be5..a23a6ec3260b 100644
--- a/test/e2e-v2/cases/mqe/expected/relabels-OP.yml
+++ b/test/e2e-v2/cases/mqe/expected/relabels-OP.yml
@@ -18,7 +18,7 @@ results:
 {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "P50"
     values:
       {{- contains .values }}
@@ -31,7 +31,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "P75"
     values:
       {{- contains .values }}
@@ -44,7 +44,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "P90"
     values:
       {{- contains .values }}
diff --git a/test/e2e-v2/cases/mqe/expected/relabels-binary-OP.yml b/test/e2e-v2/cases/mqe/expected/relabels-binary-OP.yml
index d9888226f43f..38f9499893ef 100644
--- a/test/e2e-v2/cases/mqe/expected/relabels-binary-OP.yml
+++ b/test/e2e-v2/cases/mqe/expected/relabels-binary-OP.yml
@@ -18,7 +18,7 @@ results:
 {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "P50"
     values:
       {{- contains .values }}
@@ -31,8 +31,8 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
-          value: "P75"
+        - key: p
+          value: "75"
     values:
       {{- contains .values }}
       - id: {{ notEmpty .id }}
@@ -44,8 +44,8 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
-          value: "P90"
+        - key: p
+          value: "90"
     values:
       {{- contains .values }}
       - id: {{ notEmpty .id }}
diff --git a/test/e2e-v2/cases/mqe/mqe-cases.yaml b/test/e2e-v2/cases/mqe/mqe-cases.yaml
index 4ff8c1e2aeae..197336934318 100644
--- a/test/e2e-v2/cases/mqe/mqe-cases.yaml
+++ b/test/e2e-v2/cases/mqe/mqe-cases.yaml
@@ -45,13 +45,15 @@ cases:
     expected: expected/topN-OP-instance.yml
 
   # select labels and relabels
-  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="relabels(service_percentile{_='0,1,2'},_='P50,P75,P90')" --service-name=e2e-service-provider
+  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="relabels(relabels(service_percentile{p='50,75,90'},p='50,75',p='P50,P75'),p='90',p='P90')" --service-name=e2e-service-provider
     expected: expected/relabels-OP.yml
+  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="service_percentile_old{_='0,1,2'}" --service-name=e2e-service-provider
+    expected: expected/labels-old.yml
 
   # relabels and calculate
-  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="relabels(service_percentile{_='0,1,2'},_='P50,P75,P90')/relabels(service_percentile{_='0,1,2'},_='P50,P75,P90')" --service-name=e2e-service-provider
+  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="relabels(service_percentile{p='50,75,90'},p='50',p='P50')/relabels(service_percentile{p='50,75,90'},p='50',p='P50')" --service-name=e2e-service-provider
     expected: expected/relabels-binary-OP.yml
-  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="relabels(service_percentile{_='0,1,2'}/service_percentile{_='0,1,2'},_='P50,P75,P90')" --service-name=e2e-service-provider
+  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="relabels(service_percentile{p='50,75,90'}/service_percentile{p='50,75,90'},p='50',p='P50')" --service-name=e2e-service-provider
     expected: expected/relabels-binary-OP.yml
 
   # aggregateLabels-OP
diff --git a/test/e2e-v2/cases/mqe/oal/core.oal b/test/e2e-v2/cases/mqe/oal/core.oal
new file mode 100755
index 000000000000..c40593d9bfae
--- /dev/null
+++ b/test/e2e-v2/cases/mqe/oal/core.oal
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ */
+
+// Service scope metrics
+service_resp_time = from(Service.latency).longAvg();
+service_sla = from(Service.*).percent(status == true);
+service_cpm = from(Service.*).cpm();
+service_percentile = from(Service.latency).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
+service_percentile_old = from(Service.latency).percentile(10); // old version, use percentile func, need compatible with old version
+service_apdex = from(Service.latency).apdex(name, status);
+service_mq_consume_count = from(Service.*).filter(type == RequestType.MQ).count();
+service_mq_consume_latency = from((str->long)Service.tag["transmission.latency"]).filter(type == RequestType.MQ).filter(tag["transmission.latency"] != null).longAvg();
+
+// Service relation scope metrics for topology
+service_relation_client_cpm = from(ServiceRelation.*).filter(detectPoint == DetectPoint.CLIENT).cpm();
+service_relation_server_cpm = from(ServiceRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
+service_relation_client_call_sla = from(ServiceRelation.*).filter(detectPoint == DetectPoint.CLIENT).percent(status == true);
+service_relation_server_call_sla = from(ServiceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
+service_relation_client_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
+service_relation_server_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
+service_relation_client_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_relation_server_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+
+// Service Instance relation scope metrics for topology
+service_instance_relation_client_cpm = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.CLIENT).cpm();
+service_instance_relation_server_cpm = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
+service_instance_relation_client_call_sla = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.CLIENT).percent(status == true);
+service_instance_relation_server_call_sla = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
+service_instance_relation_client_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
+service_instance_relation_server_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
+service_instance_relation_client_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_instance_relation_server_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+
+// Service Instance Scope metrics
+service_instance_sla = from(ServiceInstance.*).percent(status == true);
+service_instance_resp_time = from(ServiceInstance.latency).longAvg();
+service_instance_cpm = from(ServiceInstance.*).cpm();
+
+// Endpoint scope metrics
+endpoint_cpm = from(Endpoint.*).cpm();
+endpoint_resp_time = from(Endpoint.latency).longAvg();
+endpoint_sla = from(Endpoint.*).percent(status == true);
+endpoint_percentile = from(Endpoint.latency).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
+endpoint_mq_consume_latency = from((str->long)Endpoint.tag["transmission.latency"]).filter(type == RequestType.MQ).filter(tag["transmission.latency"] != null).longAvg();
+
+// Endpoint relation scope metrics
+endpoint_relation_cpm = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
+endpoint_relation_resp_time = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).longAvg();
+endpoint_relation_sla = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
+endpoint_relation_percentile = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+
+database_access_resp_time = from(DatabaseAccess.latency).longAvg();
+database_access_sla = from(DatabaseAccess.*).percent(status == true);
+database_access_cpm = from(DatabaseAccess.*).cpm();
+database_access_percentile = from(DatabaseAccess.latency).percentile(10);
+
+cache_read_resp_time = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).longAvg();
+cache_read_sla = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Read).percent(status == true);
+cache_read_cpm = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Read).cpm();
+cache_read_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).percentile(10);
+
+cache_write_resp_time = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).longAvg();
+cache_write_sla = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Write).percent(status == true);
+cache_write_cpm = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Write).cpm();
+cache_write_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).percentile(10);
+
+cache_access_resp_time = from(CacheAccess.latency).longAvg();
+cache_access_sla = from(CacheAccess.*).percent(status == true);
+cache_access_cpm = from(CacheAccess.*).cpm();
+cache_access_percentile = from(CacheAccess.latency).percentile(10);
+
+mq_service_consume_cpm = from(MQAccess.*).filter(operation == MQOperation.Consume).cpm();
+mq_service_consume_sla = from(MQAccess.*).filter(operation == MQOperation.Consume).percent(status == true);
+mq_service_consume_latency = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).longAvg();
+mq_service_consume_percentile = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile(10);
+mq_service_produce_cpm = from(MQAccess.*).filter(operation == MQOperation.Produce).cpm();
+mq_service_produce_sla = from(MQAccess.*).filter(operation == MQOperation.Produce).percent(status == true);
+
+mq_endpoint_consume_cpm = from(MQEndpointAccess.*).filter(operation == MQOperation.Consume).cpm();
+mq_endpoint_consume_latency = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).longAvg();
+mq_endpoint_consume_percentile = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile(10);
+mq_endpoint_consume_sla = from(MQEndpointAccess.*).filter(operation == MQOperation.Consume).percent(status == true);
+mq_endpoint_produce_cpm = from(MQEndpointAccess.*).filter(operation == MQOperation.Produce).cpm();
+mq_endpoint_produce_sla = from(MQEndpointAccess.*).filter(operation == MQOperation.Produce).percent(status == true);
diff --git a/test/e2e-v2/cases/nginx/e2e.yaml b/test/e2e-v2/cases/nginx/e2e.yaml
index 16c0488089af..8fcfa49831eb 100644
--- a/test/e2e-v2/cases/nginx/e2e.yaml
+++ b/test/e2e-v2/cases/nginx/e2e.yaml
@@ -49,17 +49,17 @@ verify:
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_http_requests --service-name=nginx::e2e-test
       expected: expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_http_latency --service-name=nginx::e2e-test
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-percentile.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_http_bandwidth --service-name=nginx::e2e-test
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-type.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_http_connections --service-name=nginx::e2e-test
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-state.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_http_status --service-name=nginx::e2e-test
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-status.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_http_requests_increment --service-name=nginx::e2e-test
       expected: expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_service_error_log_count --service-name=nginx::e2e-test
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-level.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql logs list --service-name=nginx::e2e-test
       expected: expected/logs.yml
 
@@ -69,15 +69,15 @@ verify:
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_instance_http_requests --service-name=nginx::e2e-test --instance-name=e2e-test-instance
       expected: expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_instance_http_latency --service-name=nginx::e2e-test --instance-name=e2e-test-instance
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-percentile.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_instance_http_bandwidth --service-name=nginx::e2e-test --instance-name=e2e-test-instance
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-type.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_instance_http_status --service-name=nginx::e2e-test --instance-name=e2e-test-instance
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-status.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_instance_http_requests_increment --service-name=nginx::e2e-test --instance-name=e2e-test-instance
       expected: expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_instance_error_log_count --service-name=nginx::e2e-test --instance-name=e2e-test-instance
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-level.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql logs list --service-name=nginx::e2e-test --instance-name=e2e-test-instance
       expected: expected/logs.yml
 
@@ -87,10 +87,10 @@ verify:
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_endpoint_http_requests --service-name=nginx::e2e-test --endpoint-name=/test/**
       expected: expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_endpoint_http_latency --service-name=nginx::e2e-test --endpoint-name=/test/**
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-percentile.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_endpoint_http_bandwidth --service-name=nginx::e2e-test --endpoint-name=/test/**
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-type.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_endpoint_http_status --service-name=nginx::e2e-test --endpoint-name=/test/**
-      expected: expected/metrics-has-value-label.yml
+      expected: expected/metrics-has-value-label-status.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_nginx_endpoint_http_requests_increment --service-name=nginx::e2e-test --endpoint-name=/test/**
-      expected: expected/metrics-has-value.yml
\ No newline at end of file
+      expected: expected/metrics-has-value.yml
diff --git a/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-level.yml b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-level.yml
new file mode 100644
index 000000000000..8cad5822c0ad
--- /dev/null
+++ b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-level.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: level
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/nginx/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-percentile.yml
similarity index 98%
rename from test/e2e-v2/cases/nginx/expected/metrics-has-value-label.yml
rename to test/e2e-v2/cases/nginx/expected/metrics-has-value-label-percentile.yml
index a94c3c4ba00c..0e662e432fd5 100644
--- a/test/e2e-v2/cases/nginx/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-percentile.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: p
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-state.yml b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-state.yml
new file mode 100644
index 000000000000..ca75192102ac
--- /dev/null
+++ b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-state.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: state
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-status.yml b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-status.yml
new file mode 100644
index 000000000000..45beb535df29
--- /dev/null
+++ b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-status.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: status
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-type.yml b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-type.yml
new file mode 100644
index 000000000000..8083746040c9
--- /dev/null
+++ b/test/e2e-v2/cases/nginx/expected/metrics-has-value-label-type.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: type
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label-datname.yml b/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label-datname.yml
new file mode 100644
index 000000000000..1f4aeaf11243
--- /dev/null
+++ b/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label-datname.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: datname
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label.yml
index a94c3c4ba00c..3d71dad534ca 100644
--- a/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/postgresql/expected/metrics-has-value-label.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: service_instance_id
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/postgresql/postgresql-cases.yaml b/test/e2e-v2/cases/postgresql/postgresql-cases.yaml
index 6ec2d9b736d0..8aeacbcfacd9 100644
--- a/test/e2e-v2/cases/postgresql/postgresql-cases.yaml
+++ b/test/e2e-v2/cases/postgresql/postgresql-cases.yaml
@@ -58,20 +58,20 @@ cases:
 
 
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_cache_hit_rate --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_fetched_rows_rate --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_inserted_rows_rate --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_updated_rows_rate  --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_returned_rows_rate  --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_deleted_rows_rate --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
 
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_pg_instance_active_sessions --service-name=postgresql::postgres:5432 --instance-name=postgres-exporter:9187
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-datname.yml
   # slow sql
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql records list --name=top_n_database_statement --service-name=postgresql::postgres:5432 |yq e 'to_entries | with(.[] ; .value=(.value | to_entries))' -
     expected:  expected/db-has-value.yml
diff --git a/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-client-value-label.yml b/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-client-value-label.yml
index 3d284ebd5a1f..884f11531327 100644
--- a/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-client-value-label.yml
+++ b/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-client-value-label.yml
@@ -20,7 +20,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: p
           value: {{ .value }}
         {{- end}}
     values:
@@ -33,4 +33,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-http1-value-label.yml b/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-http1-value-label.yml
index 069b320b3616..aa1f19ed3d41 100644
--- a/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-http1-value-label.yml
+++ b/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-http1-value-label.yml
@@ -19,7 +19,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "50"
     values:
       {{- contains .values }}
@@ -32,7 +32,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "70"
     values:
       {{- contains .values }}
@@ -45,7 +45,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "90"
     values:
       {{- contains .values }}
@@ -58,7 +58,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: p
           value: "99"
     values:
       {{- contains .values }}
diff --git a/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-server-value-label.yml b/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-server-value-label.yml
index 4ca39b22cffa..884f11531327 100644
--- a/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-server-value-label.yml
+++ b/test/e2e-v2/cases/profiling/ebpf/network/expected/metrics-has-server-value-label.yml
@@ -20,7 +20,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: p
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/promql/docker-compose.yml b/test/e2e-v2/cases/promql/docker-compose.yml
index 774d836d4c3c..314631750737 100644
--- a/test/e2e-v2/cases/promql/docker-compose.yml
+++ b/test/e2e-v2/cases/promql/docker-compose.yml
@@ -23,6 +23,8 @@ services:
     environment:
       SW_STORAGE: elasticsearch
       SW_STORAGE_ES_CLUSTER_NODES: es:9200
+    volumes:
+      - ./oal/core.oal:/skywalking/config/oal/core.oal
     ports:
       - 9090
     depends_on:
@@ -58,7 +60,7 @@ services:
   es:
     image: elastic/elasticsearch:7.10.2
     ports:
-      - 9200
+      - 9200:9200
     networks:
       - e2e
     environment:
diff --git a/test/e2e-v2/cases/promql/expected/endpoint-labeled-metric-label.yml b/test/e2e-v2/cases/promql/expected/endpoint-labeled-metric-label.yml
index d893a004ec4d..043c901f461d 100644
--- a/test/e2e-v2/cases/promql/expected/endpoint-labeled-metric-label.yml
+++ b/test/e2e-v2/cases/promql/expected/endpoint-labeled-metric-label.yml
@@ -20,10 +20,9 @@
     "service",
     "top_n",
     "order",
-    "labels",
-    "relabels",
     "endpoint",
-    "parent_service"
+    "parent_service",
+    "p"
   ]
 }
 
diff --git a/test/e2e-v2/cases/promql/expected/endpoint-metric-labeled-matrix.yml b/test/e2e-v2/cases/promql/expected/endpoint-metric-labeled-matrix.yml
index aa015278d150..0dbddcfe0159 100644
--- a/test/e2e-v2/cases/promql/expected/endpoint-metric-labeled-matrix.yml
+++ b/test/e2e-v2/cases/promql/expected/endpoint-metric-labeled-matrix.yml
@@ -20,7 +20,7 @@ data:
     {{- contains .data.result }}
     - metric:
         __name__: endpoint_percentile
-        label: P50
+        p: 50
         layer: GENERAL
         scope: Endpoint
         service: e2e-service-consumer
@@ -32,7 +32,7 @@ data:
         {{- end}}
     - metric:
         __name__: endpoint_percentile
-        label: P75
+        p: 75
         layer: GENERAL
         scope: Endpoint
         service: e2e-service-consumer
@@ -44,7 +44,7 @@ data:
         {{- end}}
     - metric:
         __name__: endpoint_percentile
-        label: P90
+        p: 90
         layer: GENERAL
         scope: Endpoint
         service: e2e-service-consumer
diff --git a/test/e2e-v2/cases/meter/expected/record-has-value.yml b/test/e2e-v2/cases/promql/expected/service-labeled-metric-label-old.yml
similarity index 74%
rename from test/e2e-v2/cases/meter/expected/record-has-value.yml
rename to test/e2e-v2/cases/promql/expected/service-labeled-metric-label-old.yml
index 4551156ea09a..784adb18b22e 100644
--- a/test/e2e-v2/cases/meter/expected/record-has-value.yml
+++ b/test/e2e-v2/cases/promql/expected/service-labeled-metric-label-old.yml
@@ -13,17 +13,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-{{- contains . }}
-- key: 0
-  value:
-  {{- contains .value }}
-  - key: name
-    value: {{ notEmpty .value}}
-  - key: id
-    value: {{ notEmpty .value}}
-  - key: value
-    value: {{ notEmpty .value}}
-  - key: refid
-    value: {{ notEmpty .value}}
-  {{- end }}
-{{- end }}
\ No newline at end of file
+{
+  "status": "success",
+  "data": [
+    "layer",
+    "service",
+    "top_n",
+    "order",
+    "labels",
+    "relabels"
+  ]
+}
diff --git a/test/e2e-v2/cases/promql/expected/service-labeled-metric-label-p.yml b/test/e2e-v2/cases/promql/expected/service-labeled-metric-label-p.yml
new file mode 100644
index 000000000000..7e2768dece03
--- /dev/null
+++ b/test/e2e-v2/cases/promql/expected/service-labeled-metric-label-p.yml
@@ -0,0 +1,25 @@
+# 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.
+
+{
+  "status": "success",
+  "data": [
+    "layer",
+    "service",
+    "top_n",
+    "order",
+    "p"
+  ]
+}
diff --git a/test/e2e-v2/cases/promql/expected/service-labeled-metric-label.yml b/test/e2e-v2/cases/promql/expected/service-labeled-metric-label.yml
index 784adb18b22e..48a28b958a25 100644
--- a/test/e2e-v2/cases/promql/expected/service-labeled-metric-label.yml
+++ b/test/e2e-v2/cases/promql/expected/service-labeled-metric-label.yml
@@ -19,8 +19,6 @@
     "layer",
     "service",
     "top_n",
-    "order",
-    "labels",
-    "relabels"
+    "order"
   ]
 }
diff --git a/test/e2e-v2/cases/promql/expected/service-metric-labeled-compare-matrix.yml b/test/e2e-v2/cases/promql/expected/service-metric-labeled-compare-matrix.yml
index febeadd69bb5..74eb925af364 100644
--- a/test/e2e-v2/cases/promql/expected/service-metric-labeled-compare-matrix.yml
+++ b/test/e2e-v2/cases/promql/expected/service-metric-labeled-compare-matrix.yml
@@ -20,7 +20,7 @@ data:
     {{- contains .data.result }}
     - metric:
         __name__: service_percentile
-        label: p_value
+        p: 99
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
diff --git a/test/e2e-v2/cases/promql/expected/service-metric-labeled-matrix.yml b/test/e2e-v2/cases/promql/expected/service-metric-labeled-matrix.yml
index 2ec90f0b8950..d87c2d24b9db 100644
--- a/test/e2e-v2/cases/promql/expected/service-metric-labeled-matrix.yml
+++ b/test/e2e-v2/cases/promql/expected/service-metric-labeled-matrix.yml
@@ -20,7 +20,7 @@ data:
     {{- contains .data.result }}
     - metric:
         __name__: service_percentile
-        label: P50
+        p: 50
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
@@ -31,7 +31,7 @@ data:
         {{- end}}
     - metric:
         __name__: service_percentile
-        label: P75
+        p: 75
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
@@ -42,7 +42,7 @@ data:
         {{- end}}
     - metric:
         __name__: service_percentile
-        label: P90
+        p: 90
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
diff --git a/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector-old.yml b/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector-old.yml
new file mode 100644
index 000000000000..ccb0068a46b7
--- /dev/null
+++ b/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector-old.yml
@@ -0,0 +1,49 @@
+# 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.
+
+status: success
+data:
+  resultType: vector
+  result:
+    {{- contains .data.result }}
+    - metric:
+        __name__: service_percentile_old
+        labels: P50
+        layer: GENERAL
+        scope: Service
+        service: e2e-service-consumer
+      value:
+        - "{{ index .value 0 }}"
+        - "{{ index .value 1 }}"
+    - metric:
+        __name__: service_percentile_old
+        labels: P75
+        layer: GENERAL
+        scope: Service
+        service: e2e-service-consumer
+      value:
+        - "{{ index .value 0 }}"
+        - "{{ index .value 1 }}"
+    - metric:
+        __name__: service_percentile_old
+        labels: P90
+        layer: GENERAL
+        scope: Service
+        service: e2e-service-consumer
+      value:
+        - "{{ index .value 0 }}"
+        - "{{ index .value 1 }}"
+    {{- end}}
+
diff --git a/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector.yml b/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector.yml
index bc90ffb827be..cbfd5050d356 100644
--- a/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector.yml
+++ b/test/e2e-v2/cases/promql/expected/service-metric-labeled-vector.yml
@@ -20,7 +20,7 @@ data:
     {{- contains .data.result }}
     - metric:
         __name__: service_percentile
-        label: P50
+        p: 50
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
@@ -29,7 +29,7 @@ data:
         - "{{ index .value 1 }}"
     - metric:
         __name__: service_percentile
-        label: P75
+        p: 75
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
@@ -38,7 +38,7 @@ data:
         - "{{ index .value 1 }}"
     - metric:
         __name__: service_percentile
-        label: P90
+        p: 90
         layer: GENERAL
         scope: Service
         service: e2e-service-consumer
diff --git a/test/e2e-v2/cases/promql/oal/core.oal b/test/e2e-v2/cases/promql/oal/core.oal
new file mode 100755
index 000000000000..c40593d9bfae
--- /dev/null
+++ b/test/e2e-v2/cases/promql/oal/core.oal
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ */
+
+// Service scope metrics
+service_resp_time = from(Service.latency).longAvg();
+service_sla = from(Service.*).percent(status == true);
+service_cpm = from(Service.*).cpm();
+service_percentile = from(Service.latency).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
+service_percentile_old = from(Service.latency).percentile(10); // old version, use percentile func, need compatible with old version
+service_apdex = from(Service.latency).apdex(name, status);
+service_mq_consume_count = from(Service.*).filter(type == RequestType.MQ).count();
+service_mq_consume_latency = from((str->long)Service.tag["transmission.latency"]).filter(type == RequestType.MQ).filter(tag["transmission.latency"] != null).longAvg();
+
+// Service relation scope metrics for topology
+service_relation_client_cpm = from(ServiceRelation.*).filter(detectPoint == DetectPoint.CLIENT).cpm();
+service_relation_server_cpm = from(ServiceRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
+service_relation_client_call_sla = from(ServiceRelation.*).filter(detectPoint == DetectPoint.CLIENT).percent(status == true);
+service_relation_server_call_sla = from(ServiceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
+service_relation_client_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
+service_relation_server_resp_time = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
+service_relation_client_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_relation_server_percentile = from(ServiceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+
+// Service Instance relation scope metrics for topology
+service_instance_relation_client_cpm = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.CLIENT).cpm();
+service_instance_relation_server_cpm = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
+service_instance_relation_client_call_sla = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.CLIENT).percent(status == true);
+service_instance_relation_server_call_sla = from(ServiceInstanceRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
+service_instance_relation_client_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).longAvg();
+service_instance_relation_server_resp_time = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).longAvg();
+service_instance_relation_client_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.CLIENT).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+service_instance_relation_server_percentile = from(ServiceInstanceRelation.latency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+
+// Service Instance Scope metrics
+service_instance_sla = from(ServiceInstance.*).percent(status == true);
+service_instance_resp_time = from(ServiceInstance.latency).longAvg();
+service_instance_cpm = from(ServiceInstance.*).cpm();
+
+// Endpoint scope metrics
+endpoint_cpm = from(Endpoint.*).cpm();
+endpoint_resp_time = from(Endpoint.latency).longAvg();
+endpoint_sla = from(Endpoint.*).percent(status == true);
+endpoint_percentile = from(Endpoint.latency).percentile2(10); // Multiple values including p50, p75, p90, p95, p99
+endpoint_mq_consume_latency = from((str->long)Endpoint.tag["transmission.latency"]).filter(type == RequestType.MQ).filter(tag["transmission.latency"] != null).longAvg();
+
+// Endpoint relation scope metrics
+endpoint_relation_cpm = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).cpm();
+endpoint_relation_resp_time = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).longAvg();
+endpoint_relation_sla = from(EndpointRelation.*).filter(detectPoint == DetectPoint.SERVER).percent(status == true);
+endpoint_relation_percentile = from(EndpointRelation.rpcLatency).filter(detectPoint == DetectPoint.SERVER).percentile(10); // Multiple values including p50, p75, p90, p95, p99
+
+database_access_resp_time = from(DatabaseAccess.latency).longAvg();
+database_access_sla = from(DatabaseAccess.*).percent(status == true);
+database_access_cpm = from(DatabaseAccess.*).cpm();
+database_access_percentile = from(DatabaseAccess.latency).percentile(10);
+
+cache_read_resp_time = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).longAvg();
+cache_read_sla = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Read).percent(status == true);
+cache_read_cpm = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Read).cpm();
+cache_read_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Read).percentile(10);
+
+cache_write_resp_time = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).longAvg();
+cache_write_sla = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Write).percent(status == true);
+cache_write_cpm = from(CacheAccess.*).filter(operation == VirtualCacheOperation.Write).cpm();
+cache_write_percentile = from(CacheAccess.latency).filter(operation == VirtualCacheOperation.Write).percentile(10);
+
+cache_access_resp_time = from(CacheAccess.latency).longAvg();
+cache_access_sla = from(CacheAccess.*).percent(status == true);
+cache_access_cpm = from(CacheAccess.*).cpm();
+cache_access_percentile = from(CacheAccess.latency).percentile(10);
+
+mq_service_consume_cpm = from(MQAccess.*).filter(operation == MQOperation.Consume).cpm();
+mq_service_consume_sla = from(MQAccess.*).filter(operation == MQOperation.Consume).percent(status == true);
+mq_service_consume_latency = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).longAvg();
+mq_service_consume_percentile = from(MQAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile(10);
+mq_service_produce_cpm = from(MQAccess.*).filter(operation == MQOperation.Produce).cpm();
+mq_service_produce_sla = from(MQAccess.*).filter(operation == MQOperation.Produce).percent(status == true);
+
+mq_endpoint_consume_cpm = from(MQEndpointAccess.*).filter(operation == MQOperation.Consume).cpm();
+mq_endpoint_consume_latency = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).longAvg();
+mq_endpoint_consume_percentile = from(MQEndpointAccess.transmissionLatency).filter(operation == MQOperation.Consume).percentile(10);
+mq_endpoint_consume_sla = from(MQEndpointAccess.*).filter(operation == MQOperation.Consume).percent(status == true);
+mq_endpoint_produce_cpm = from(MQEndpointAccess.*).filter(operation == MQOperation.Produce).cpm();
+mq_endpoint_produce_sla = from(MQEndpointAccess.*).filter(operation == MQOperation.Produce).percent(status == true);
diff --git a/test/e2e-v2/cases/promql/promql-cases.yaml b/test/e2e-v2/cases/promql/promql-cases.yaml
index caa6d570832e..efb618fd7f89 100644
--- a/test/e2e-v2/cases/promql/promql-cases.yaml
+++ b/test/e2e-v2/cases/promql/promql-cases.yaml
@@ -34,8 +34,12 @@ cases:
   # labels query
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/labels -d 'match[]=service_cpm'
     expected: expected/service-metric-label.yml
-  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/labels -d 'match[]=service_percentile'
-    expected: expected/service-labeled-metric-label.yml
+  - query: |
+      sleep 30;
+      curl -X GET http://${oap_host}:${oap_9090}/api/v1/labels -d 'match[]=service_percentile'
+    expected: expected/service-labeled-metric-label-p.yml
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/labels -d 'match[]=service_percentile_old'
+    expected: expected/service-labeled-metric-label-old.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/labels -d 'match[]=service_instance_cpm'
     expected: expected/instance-metric-label.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/labels -d 'match[]=endpoint_cpm'
@@ -50,9 +54,11 @@ cases:
     expected: expected/service-metric-vector.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_sla{service="e2e-service-consumer", layer="GENERAL"}[30m]'
     expected: expected/service-metric-matrix.yml
-  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", labels="0,1,2", relabels="P50,P75,P90"}'
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", p="50,75,90"}'
     expected: expected/service-metric-labeled-vector.yml
-  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", labels="0,1,2", relabels="P50,P75,P90"}[30m]'
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile_old{service="e2e-service-consumer", layer="GENERAL", labels="0,1,2", relabels="P50,P75,P90"}'
+    expected: expected/service-metric-labeled-vector-old.yml
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", p="50,75,90"}[30m]'
     expected: expected/service-metric-labeled-matrix.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_cpm{layer="GENERAL",top_n="10", order="DES"}'
     expected: expected/service-metric-sort-vector.yml
@@ -61,12 +67,12 @@ cases:
   ## multiple metrics operation query
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_sla{service="e2e-service-consumer", layer="GENERAL"} + service_cpm{service="e2e-service-consumer", layer="GENERAL"}'
     expected: expected/service-metric-vector.yml
-  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", labels="4", relabels="p_value"} - service_percentile{service="e2e-service-consumer", layer="GENERAL", labels="3", relabels="p_value"}'
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", p="99"} - service_percentile{service="e2e-service-consumer", layer="GENERAL", p="99"}'
     expected: expected/service-metric-labeled-compare-matrix.yml
   ## query_range
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=service_sla{service="e2e-service-consumer", layer="GENERAL"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
     expected: expected/service-metric-matrix.yml
-  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", labels="0,1,2", relabels="P50,P75,P90"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=service_percentile{service="e2e-service-consumer", layer="GENERAL", p="50,75,90"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
     expected: expected/service-metric-labeled-matrix.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=service_cpm{layer="GENERAL",top_n="10", order="DES"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
     expected: expected/service-metric-sort-matrix.yml
@@ -82,7 +88,7 @@ cases:
     expected: expected/endpoint-metric-vector.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=endpoint_sla{service="e2e-service-consumer", layer="GENERAL", endpoint="POST:/users"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
     expected: expected/endpoint-metric-matrix.yml
-  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=endpoint_percentile{service="e2e-service-consumer", layer="GENERAL", labels="0,1,2", relabels="P50,P75,P90", endpoint="POST:/users"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
+  - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=endpoint_percentile{service="e2e-service-consumer", layer="GENERAL", p="50,75,90", endpoint="POST:/users"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
     expected: expected/endpoint-metric-labeled-matrix.yml
   - query: curl -X GET http://${oap_host}:${oap_9090}/api/v1/query_range -d 'query=endpoint_cpm{parent_service="e2e-service-consumer", layer="GENERAL",top_n="10", order="DES"}&start='$(($(date +%s)-1800))'&end='$(date +%s)
     expected: expected/endpoint-metric-sort-matrix.yml
diff --git a/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-bookie-label.yml b/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-bookie-label.yml
index 07d707edd9c2..c73366ef39c9 100644
--- a/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-bookie-label.yml
+++ b/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-bookie-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: node
           value: bookie:8000
     values:
       {{- contains .values }}
@@ -30,4 +30,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-broker-label.yml b/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-broker-label.yml
index f93f3cbdd2e1..a787b1b9ee3c 100644
--- a/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-broker-label.yml
+++ b/test/e2e-v2/cases/pulsar/expected/metrics-has-value-instance-broker-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: node
           value: broker:8080
     values:
       {{- contains .values }}
@@ -30,4 +30,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-instance-label.yml b/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-instance-label.yml
index fded7014c66e..13d9af3f54cc 100644
--- a/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-instance-label.yml
+++ b/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-instance-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-      - key: _
+      - key: alloc
         value: std_alloc
     values:
       {{- contains .values }}
@@ -30,4 +30,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-service-label.yml b/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-service-label.yml
index ee4db23d10ca..154ffa47cf0d 100644
--- a/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-service-label.yml
+++ b/test/e2e-v2/cases/rabbitmq/expected/metrics-has-value-service-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-      - key: _
+      - key: node
         value: rmq0:15692
     values:
       {{- contains .values }}
@@ -30,4 +30,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/redis/redis-cases.yaml b/test/e2e-v2/cases/redis/redis-cases.yaml
index da75ac93862f..bb7f8e59fa31 100644
--- a/test/e2e-v2/cases/redis/redis-cases.yaml
+++ b/test/e2e-v2/cases/redis/redis-cases.yaml
@@ -26,22 +26,16 @@ cases:
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_memory_usage --service-name=redis::root[root]
     expected: expected/metrics-has-value.yml
-
-
-
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_hit_rate --service-name=redis::root[root]
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_net_input_bytes_total --service-name=redis::root[root]
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_net_output_bytes_total --service-name=redis::root[root]
     expected: expected/metrics-has-value.yml
-
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_db_keys --service-name=redis::root[root]
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_expired_keys_total --service-name=redis::root[root]
     expected: expected/metrics-has-value.yml
-
-
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_uptime --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_connected_clients --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
@@ -50,19 +44,16 @@ cases:
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_memory_max_bytes --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
-
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_hit_rate --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_net_input_bytes_total --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_net_output_bytes_total --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
-
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_db_keys --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_redis_instance_expired_keys_total --service-name=redis::root[root] --instance-name=redis_exporter_1:9121
     expected: expected/metrics-has-value.yml
-
     # slow sql
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql records list --name=top_n_database_statement --service-name=redis::root[root] |yq e 'to_entries | with(.[] ; .value=(.value | to_entries))' -
     expected:  expected/db-has-value.yml
diff --git a/test/e2e-v2/cases/rocketmq/e2e.yaml b/test/e2e-v2/cases/rocketmq/e2e.yaml
index 0b7d36be3334..ce8c1389ec1f 100644
--- a/test/e2e-v2/cases/rocketmq/e2e.yaml
+++ b/test/e2e-v2/cases/rocketmq/e2e.yaml
@@ -34,4 +34,4 @@ verify:
     interval: 3s
   cases:
     - includes:
-        - ./rocketmq-cases.yaml
\ No newline at end of file
+        - ./rocketmq-cases.yaml
diff --git a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-empty-label.yml b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-empty-label.yml
index 64d711a38e3c..2ac37bfcaad3 100644
--- a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-empty-label.yml
+++ b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-empty-label.yml
@@ -17,19 +17,15 @@ type: TIME_SERIES_VALUES
 results:
   {{- contains .results }}
   - metric:
-      labels:
-        {{- contains .metric.labels }}
-        - key: _
-          value: ""
-        {{- end}}
-      values:
-        { { - contains .values } }
-        - id: { { notEmpty .id } }
-          value: null
-          traceid: null
-        - id: { { notEmpty .id } }
-          value: { { .value } }
-          traceid: null
-        { { - end } }
+      labels: []
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      {{- end }}
   {{- end}}
 error: null
diff --git a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-group-label.yml b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-group-label.yml
index 1b49846d570e..72b4ab5d500a 100644
--- a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-group-label.yml
+++ b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-group-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: group
           value: please_rename_unique_group_name_4
     values:
       {{- contains .values }}
diff --git a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label-brokerIP.yml b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label-brokerIP.yml
new file mode 100644
index 000000000000..a3bd6e5973e2
--- /dev/null
+++ b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label-brokerIP.yml
@@ -0,0 +1,35 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        {{- contains .metric.labels }}
+        - key: brokerIP
+          value: {{ .value }}
+        {{- end}}
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label.yml
index a94c3c4ba00c..020530652cb9 100644
--- a/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/rocketmq/expected/metrics-has-value-label.yml
@@ -19,8 +19,12 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
-          value: {{ .value }}
+        - key: topic
+          value: TopicTest
+        - key: broker
+          value: rocketmq-broker-1
+        - key: group
+          value: please_rename_unique_group_name_4
         {{- end}}
     values:
       {{- contains .values }}
diff --git a/test/e2e-v2/cases/rocketmq/rocketmq-cases.yaml b/test/e2e-v2/cases/rocketmq/rocketmq-cases.yaml
index 47a51bf1952b..5f367bacf1d2 100644
--- a/test/e2e-v2/cases/rocketmq/rocketmq-cases.yaml
+++ b/test/e2e-v2/cases/rocketmq/rocketmq-cases.yaml
@@ -38,13 +38,13 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_max_consumer_latency --service-name=rocketmq::rocketmq-cluster
     expected: expected/metrics-has-value-label.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_max_commitLog_disk_ratio --service-name=rocketmq::rocketmq-cluster
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-brokerIP.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_commitLog_disk_ratio --service-name=rocketmq::rocketmq-cluster
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-brokerIP.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_pull_threadPool_queue_head_wait_time --service-name=rocketmq::rocketmq-cluster
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-brokerIP.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_send_threadPool_queue_head_wait_time --service-name=rocketmq::rocketmq-cluster
-    expected: expected/metrics-has-value-label.yml
+    expected: expected/metrics-has-value-label-brokerIP.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_topic_count --service-name=rocketmq::rocketmq-cluster
     expected: expected/metrics-has-value-empty-label.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_cluster_broker_count --service-name=rocketmq::rocketmq-cluster
@@ -86,4 +86,4 @@ cases:
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_topic_consumer_group_count --service-name=rocketmq::rocketmq-cluster --endpoint-name=TopicTest
     expected: expected/metrics-has-value-empty-label.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_rocketmq_topic_broker_count --service-name=rocketmq::rocketmq-cluster --endpoint-name=TopicTest
-    expected: expected/metrics-has-value-empty-label.yml
\ No newline at end of file
+    expected: expected/metrics-has-value-empty-label.yml
diff --git a/test/e2e-v2/cases/simple/expected/metrics-has-value-percentile.yml b/test/e2e-v2/cases/simple/expected/metrics-has-value-percentile.yml
index a94c3c4ba00c..0e662e432fd5 100644
--- a/test/e2e-v2/cases/simple/expected/metrics-has-value-percentile.yml
+++ b/test/e2e-v2/cases/simple/expected/metrics-has-value-percentile.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: p
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/so11y/expected/metrics-has-value-label.yml b/test/e2e-v2/cases/so11y/expected/metrics-has-value-label.yml
index 36b22485e970..4eee5f0c242f 100644
--- a/test/e2e-v2/cases/so11y/expected/metrics-has-value-label.yml
+++ b/test/e2e-v2/cases/so11y/expected/metrics-has-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: level
           value: L1 aggregation
     values:
       {{- contains .values }}
diff --git a/test/e2e-v2/cases/so11y/so11y-cases.yaml b/test/e2e-v2/cases/so11y/so11y-cases.yaml
index abc96c50d1e9..f0fda21fc3ff 100644
--- a/test/e2e-v2/cases/so11y/so11y-cases.yaml
+++ b/test/e2e-v2/cases/so11y/so11y-cases.yaml
@@ -30,7 +30,7 @@
       expected: expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_oap_instance_trace_count --instance-name=http://localhost:1234 --service-name=oap-server
       expected: expected/metrics-has-value.yml
-    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="meter_oap_instance_metrics_aggregation{_='L1 aggregation'}" --instance-name=http://localhost:1234 --service-name=oap-server
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression="meter_oap_instance_metrics_aggregation{level='L1 aggregation'}" --instance-name=http://localhost:1234 --service-name=oap-server
       expected: expected/metrics-has-value-label.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_oap_instance_persistence_prepare_count --instance-name=http://localhost:1234 --service-name=oap-server
       expected: expected/metrics-has-value.yml
diff --git a/test/e2e-v2/cases/storage/expected/metrics-has-value-percentile.yml b/test/e2e-v2/cases/storage/expected/metrics-has-value-percentile.yml
index a94c3c4ba00c..0e662e432fd5 100644
--- a/test/e2e-v2/cases/storage/expected/metrics-has-value-percentile.yml
+++ b/test/e2e-v2/cases/storage/expected/metrics-has-value-percentile.yml
@@ -19,7 +19,7 @@ results:
   - metric:
       labels:
         {{- contains .metric.labels }}
-        - key: _
+        - key: p
           value: {{ .value }}
         {{- end}}
     values:
diff --git a/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label-zabbix.yml b/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label-zabbix.yml
new file mode 100644
index 000000000000..54d9a478fa2d
--- /dev/null
+++ b/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label-zabbix.yml
@@ -0,0 +1,46 @@
+# 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.
+
+type: TIME_SERIES_VALUES
+results:
+  {{- contains .results }}
+  - metric:
+      labels:
+        - key: 2
+          value: "idle"
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  - metric:
+      labels:
+        - key: 2
+          value: "user"
+    values:
+      {{- contains .values }}
+      - id: {{ notEmpty .id }}
+        value: {{ .value }}
+        traceid: null
+      - id: {{ notEmpty .id }}
+        value: null
+        traceid: null
+      {{- end}}
+  {{- end}}
+error: null
diff --git a/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label.yml b/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label.yml
index df8a11782134..02f6394a0dfd 100644
--- a/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label.yml
+++ b/test/e2e-v2/cases/vm/expected/metrics-has-average-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: mode
           value: "idle"
     values:
       {{- contains .values }}
@@ -31,7 +31,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: mode
           value: "user"
     values:
       {{- contains .values }}
@@ -43,4 +43,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/vm/expected/metrics-has-mountpoint-value-label.yml b/test/e2e-v2/cases/vm/expected/metrics-has-mountpoint-value-label.yml
index 52f90c0a68f5..d3bf3e318afd 100644
--- a/test/e2e-v2/cases/vm/expected/metrics-has-mountpoint-value-label.yml
+++ b/test/e2e-v2/cases/vm/expected/metrics-has-mountpoint-value-label.yml
@@ -18,7 +18,7 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
+        - key: mountpoint
           value: "/etc/hosts"
     values:
       {{- contains .values }}
@@ -31,7 +31,7 @@ results:
       {{- end}}
   - metric:
       labels:
-        - key: _
+        - key: mountpoint
           value: "/etc/hostname"
     values:
       {{- contains .values }}
@@ -43,4 +43,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/vm/expected/metrics-has-vfs-value-label.yml b/test/e2e-v2/cases/vm/expected/metrics-has-vfs-value-label.yml
index f94f2417f9c5..bbb1c678e884 100644
--- a/test/e2e-v2/cases/vm/expected/metrics-has-vfs-value-label.yml
+++ b/test/e2e-v2/cases/vm/expected/metrics-has-vfs-value-label.yml
@@ -18,8 +18,10 @@ results:
   {{- contains .results }}
   - metric:
       labels:
-        - key: _
-          value: "/-total"
+        - key: 1
+          value: "/"
+        - key: 2
+          value: "total"
     values:
       {{- contains .values }}
       - id: {{ notEmpty .id }}
@@ -30,4 +32,4 @@ results:
         traceid: null
       {{- end}}
   {{- end}}
-error: null
\ No newline at end of file
+error: null
diff --git a/test/e2e-v2/cases/vm/prometheus-node-exporter/e2e.yaml b/test/e2e-v2/cases/vm/prometheus-node-exporter/e2e.yaml
index bc74e963bc90..fddad37cc198 100644
--- a/test/e2e-v2/cases/vm/prometheus-node-exporter/e2e.yaml
+++ b/test/e2e-v2/cases/vm/prometheus-node-exporter/e2e.yaml
@@ -48,4 +48,7 @@ verify:
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_filefd_allocated --service-name=vm-service
       expected:  ../expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_filesystem_percentage --service-name=vm-service
-      expected:  ../expected/metrics-has-mountpoint-value-label.yml
\ No newline at end of file
+      expected:  ../expected/metrics-has-mountpoint-value-label.yml
+    # multiple-linear metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_cpu_average_used --service-name=vm-service
+      expected: ../expected/metrics-has-average-value-label.yml
diff --git a/test/e2e-v2/cases/vm/vm-cases.yaml b/test/e2e-v2/cases/vm/vm-cases.yaml
index faeb35778ff0..8ede019edf10 100644
--- a/test/e2e-v2/cases/vm/vm-cases.yaml
+++ b/test/e2e-v2/cases/vm/vm-cases.yaml
@@ -26,6 +26,3 @@
       expected:  expected/metrics-has-value.yml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_memory_available --service-name=vm-service
       expected:  expected/metrics-has-value.yml
-    # multiple-linear metrics
-    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_cpu_average_used --service-name=vm-service
-      expected:  expected/metrics-has-average-value-label.yml
diff --git a/test/e2e-v2/cases/vm/zabbix/e2e.yaml b/test/e2e-v2/cases/vm/zabbix/e2e.yaml
index e5a3785fff63..7a8e22430417 100644
--- a/test/e2e-v2/cases/vm/zabbix/e2e.yaml
+++ b/test/e2e-v2/cases/vm/zabbix/e2e.yaml
@@ -37,3 +37,6 @@ verify:
         - ../vm-cases.yaml
     - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_vfs_fs_size --service-name=vm-service
       expected:  ../expected/metrics-has-vfs-value-label.yml
+    # multiple-linear metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics exec --expression=meter_vm_cpu_average_used --service-name=vm-service
+      expected:  ../expected/metrics-has-average-value-label-zabbix.yml