You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/03/22 15:50:43 UTC

[skywalking] branch master updated: [Breaking Change] Support cross-thread trace profiling. (#10575)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 0de087a100 [Breaking Change] Support cross-thread trace profiling. (#10575)
0de087a100 is described below

commit 0de087a100c89d299f3f6536e191314c21330761
Author: mrproliu <74...@qq.com>
AuthorDate: Wed Mar 22 23:50:26 2023 +0800

    [Breaking Change] Support cross-thread trace profiling. (#10575)
    
    The data structure and query APIs are changed.
---
 docs/en/changes/changes.md                         |   1 +
 .../profiling/trace/ProfileTaskQueryService.java   | 172 ++++++++++++++++++---
 .../profiling/trace/analyze/ProfileAnalyzer.java   |  28 ++--
 .../SegmentProfileAnalyzeQuery.java}               |  31 ++--
 .../oap/server/core/query/type/KVInt.java          |   1 +
 .../{ProfiledSegment.java => NullableValue.java}   |  20 +--
 .../oap/server/core/query/type/ProfiledSpan.java   |   3 +
 ...iledSegment.java => ProfiledTraceSegments.java} |  27 +++-
 .../trace/IProfileThreadSnapshotQueryDAO.java      |  10 +-
 .../server/core/storage/query/ITraceQueryDAO.java  |   4 +
 .../trace/ProfileTaskQueryServiceTest.java         | 139 +++++++++++++++++
 .../trace/analyze/ProfileStackAnalyze.java         |  15 +-
 .../profiling/trace/analyze/ProfileStackData.java  |   9 +-
 .../core/storage/query/MetricsQueryUtilTest.java   |  24 +--
 .../oap/query/graphql/resolver/MetricQuery.java    |   9 ++
 .../oap/query/graphql/resolver/ProfileQuery.java   |  17 +-
 .../src/main/resources/query-protocol              |   2 +-
 .../BanyanDBProfileThreadSnapshotQueryDAO.java     |  63 +-------
 .../banyandb/stream/BanyanDBTraceQueryDAO.java     |  41 ++++-
 .../query/ProfileThreadSnapshotQueryEsDAO.java     |  97 ++----------
 .../elasticsearch/query/TraceQueryEsDAO.java       |  46 +++++-
 .../dao/JDBCProfileThreadSnapshotQueryDAO.java     | 112 +-------------
 .../plugin/jdbc/common/dao/JDBCTraceQueryDAO.java  | 112 +++++++++++---
 .../profile/exporter/ProfileSnapshotDumper.java    |  13 +-
 .../exporter/ProfileSnapshotExporterBootstrap.java |   6 +-
 .../tool/profile/exporter/ProfiledBasicInfo.java   |  94 ++++++-----
 .../exporter/ProfileAnalyzeSnapshotDAO.java        |   9 +-
 .../profile/exporter/ProfileExportedAnalyze.java   |  14 +-
 .../exporter/test/ProfileExportSnapshotDAO.java    |  16 +-
 .../exporter/test/ProfileSnapshotExporterTest.java |   4 +-
 .../profile/exporter/test/ProfileTraceDAO.java     |  29 ++++
 .../trace/expected/profile-segment-detail.yml      |  40 -----
 .../trace/expected/profile-segment-list.yml        |  37 ++++-
 .../cases/profiling/trace/profiling-cases.yaml     |  24 +--
 .../cases/satellite/native-protocols/e2e.yaml      |  23 +--
 .../expected/profile-segment-detail.yml            |  38 -----
 .../expected/profile-segment-list.yml              |  37 ++++-
 test/e2e-v2/script/env                             |   2 +-
 38 files changed, 770 insertions(+), 599 deletions(-)

diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index d1ca54287a..3d34aab7cb 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -17,6 +17,7 @@
 * Support continuous profiling feature.
 * Support collect process level related metrics.
 * Fix K8sRetag reads the wrong k8s service from the cache due to a possible namespace mismatch.
+* [Breaking Change] Support cross-thread trace profiling. The data structure and query APIs are changed.
 
 #### UI
 * Revert: cpm5d function. This feature is cancelled from backend.
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryService.java
index 4e88a82e22..efa9487ecb 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryService.java
@@ -22,8 +22,16 @@ import com.google.common.base.Objects;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import io.vavr.Tuple;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.network.language.agent.v3.SegmentObject;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
@@ -32,19 +40,21 @@ import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentReco
 import org.apache.skywalking.oap.server.core.cache.NetworkAddressAliasCache;
 import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
 import org.apache.skywalking.oap.server.core.profiling.trace.analyze.ProfileAnalyzer;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.KeyValue;
 import org.apache.skywalking.oap.server.core.query.type.LogEntity;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzation;
-import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTask;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTaskLog;
-import org.apache.skywalking.oap.server.core.query.type.ProfiledSegment;
+import org.apache.skywalking.oap.server.core.query.type.ProfiledTraceSegments;
 import org.apache.skywalking.oap.server.core.query.type.ProfiledSpan;
+import org.apache.skywalking.oap.server.core.query.type.Ref;
+import org.apache.skywalking.oap.server.core.query.type.RefType;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileTaskLogQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileTaskQueryDAO;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.ITraceQueryDAO;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.module.Service;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
@@ -54,6 +64,7 @@ import static java.util.Objects.isNull;
 /**
  * handle profile task queries
  */
+@Slf4j
 public class ProfileTaskQueryService implements Service {
     private final ModuleManager moduleManager;
     private IProfileTaskQueryDAO profileTaskQueryDAO;
@@ -61,6 +72,7 @@ public class ProfileTaskQueryService implements Service {
     private IProfileThreadSnapshotQueryDAO profileThreadSnapshotQueryDAO;
     private NetworkAddressAliasCache networkAddressAliasCache;
     private IComponentLibraryCatalogService componentLibraryCatalogService;
+    private ITraceQueryDAO traceQueryDAO;
 
     private final ProfileAnalyzer profileAnalyzer;
 
@@ -117,6 +129,15 @@ public class ProfileTaskQueryService implements Service {
         return componentLibraryCatalogService;
     }
 
+    private ITraceQueryDAO getTraceQueryDAO() {
+        if (traceQueryDAO == null) {
+            this.traceQueryDAO = moduleManager.find(StorageModule.NAME)
+                                              .provider()
+                                              .getService(ITraceQueryDAO.class);
+        }
+        return traceQueryDAO;
+    }
+
     /**
      * search profile task list
      *
@@ -161,38 +182,131 @@ public class ProfileTaskQueryService implements Service {
         return findMatchedLogs(taskID, taskLogList);
     }
 
-    /**
-     * search profiled traces
-     */
-    public List<BasicTrace> getTaskTraces(String taskId) throws IOException {
-        return getProfileThreadSnapshotQueryDAO().queryProfiledSegments(taskId);
+    public ProfileAnalyzation getProfileAnalyze(final List<SegmentProfileAnalyzeQuery> queries) throws IOException {
+        return profileAnalyzer.analyze(queries);
+    }
+
+    public List<SegmentRecord> getTaskSegments(String taskId) throws IOException {
+        final List<String> profiledSegmentIdList = getProfileThreadSnapshotQueryDAO().queryProfiledSegmentIdList(taskId);
+        return getTraceQueryDAO().queryBySegmentIdList(profiledSegmentIdList);
     }
 
-    public ProfileAnalyzation getProfileAnalyze(final String segmentId,
-                                                final List<ProfileAnalyzeTimeRange> timeRanges) throws IOException {
-        return profileAnalyzer.analyze(segmentId, timeRanges);
+    public List<ProfiledTraceSegments> getProfileTaskSegments(String taskId) throws IOException {
+        // query all profiled segments
+        final List<String> profiledSegmentIdList = getProfileThreadSnapshotQueryDAO().queryProfiledSegmentIdList(taskId);
+        final List<SegmentRecord> segmentRecords = getTraceQueryDAO().queryBySegmentIdList(profiledSegmentIdList);
+        if (CollectionUtils.isEmpty(segmentRecords)) {
+            return Collections.emptyList();
+        }
+        final Map<String, List<String>> traceWithInstances = segmentRecords.stream().collect(Collectors.toMap(
+            SegmentRecord::getTraceId,
+            s -> new ArrayList(List.of(s.getServiceInstanceId())),
+            (s1, s2) -> {
+                s1.addAll(s2);
+                return s1;
+            }));
+
+        // query all profiled segments related segments(same traceId and instanceId)
+        final Set<String> traceIdList = new HashSet<>(segmentRecords.size());
+        final Set<String> instanceIdList = new HashSet<>(segmentRecords.size());
+        for (SegmentRecord segment : segmentRecords) {
+            traceIdList.add(segment.getTraceId());
+            instanceIdList.add(segment.getServiceInstanceId());
+        }
+        final List<SegmentRecord> traceRelatedSegments = getTraceQueryDAO().queryByTraceIdWithInstanceId(
+            new ArrayList<>(traceIdList),
+            new ArrayList<>(instanceIdList));
+
+        // group by the traceId + service instanceId
+        final Map<String, List<SegmentRecord>> instanceTraceWithSegments = traceRelatedSegments.stream().filter(s -> {
+            final List<String> includingInstances = traceWithInstances.get(s.getTraceId());
+            return includingInstances.contains(s.getServiceInstanceId());
+        }).collect(Collectors.toMap(
+            s -> s.getTraceId() + s.getServiceInstanceId(),
+            s -> new ArrayList<>(List.of(s)),
+            (s1, s2) -> {
+                s1.addAll(s2);
+                return s1;
+            }));
+
+        // build result
+        return instanceTraceWithSegments.values().stream()
+            .flatMap(s -> buildProfiledSegmentsList(s, profiledSegmentIdList).stream())
+            .collect(Collectors.toList());
     }
 
-    public ProfiledSegment getProfiledSegment(String segmentId) throws IOException {
-        SegmentRecord segmentRecord = getProfileThreadSnapshotQueryDAO().getProfiledSegment(segmentId);
-        if (segmentRecord == null) {
-            return null;
+    protected List<ProfiledTraceSegments> buildProfiledSegmentsList(List<SegmentRecord> segmentRecords, List<String> profiledSegmentIdList) {
+        final Map<String, ProfiledTraceSegments> segments = segmentRecords.stream().map(s -> {
+            try {
+                return Tuple.of(s, SegmentObject.parseFrom(s.getDataBinary()));
+            } catch (InvalidProtocolBufferException e) {
+                log.warn("parsing segment data error", e);
+                return null;
+            }
+        }).filter(java.util.Objects::nonNull).filter(s -> CollectionUtils.isNotEmpty(s._2.getSpansList())).collect(Collectors.toMap(
+            tuple -> tuple._1.getSegmentId(),
+            tuple -> {
+                final IDManager.ServiceInstanceID.InstanceIDDefinition serviceInstance = IDManager.ServiceInstanceID.analysisId(tuple._1.getServiceInstanceId());
+                final ProfiledTraceSegments seg = new ProfiledTraceSegments();
+                final boolean profiled = profiledSegmentIdList.contains(tuple._1.getSegmentId());
+                seg.setTraceId(tuple._1.getTraceId());
+                seg.setInstanceId(tuple._1.getServiceInstanceId());
+                seg.setInstanceName(serviceInstance.getName());
+                seg.getEndpointNames().add(IDManager.EndpointID.analysisId(tuple._1.getEndpointId()).getEndpointName());
+                seg.setDuration(tuple._1.getLatency());
+                seg.setStart(String.valueOf(tuple._1.getStartTime()));
+                seg.getSpans().addAll(buildProfiledSpanList(tuple._2, profiled));
+                seg.setContainsProfiled(profiled);
+                return seg;
+            }
+        ));
+
+        // trying to find parent
+        final ArrayList<ProfiledTraceSegments> results = new ArrayList<>();
+        final Iterator<Map.Entry<String, ProfiledTraceSegments>> entryIterator = segments.entrySet().iterator();
+        while (entryIterator.hasNext()) {
+            // keep segment if no ref
+            final Map.Entry<String, ProfiledTraceSegments> current = entryIterator.next();
+            if (CollectionUtils.isEmpty(current.getValue().getSpans().get(0).getRefs())) {
+                results.add(current.getValue());
+                continue;
+            }
+            // keep segment if ref type is not same process(analyze only match with the same process)
+            final Ref ref = current.getValue().getSpans().get(0).getRefs().get(0);
+            if (RefType.CROSS_PROCESS.equals(ref.getType())) {
+                results.add(current.getValue());
+                continue;
+            }
+
+            // find parent segment if exist
+            final ProfiledTraceSegments parentSegments = segments.get(ref.getParentSegmentId());
+            if (parentSegments == null) {
+                results.add(current.getValue());
+                continue;
+            }
+
+            // add current segments into parent
+            parentSegments.merge(current.getValue());
+            // set parent segments(combined) as current segment
+            current.setValue(parentSegments);
         }
 
-        ProfiledSegment profiledSegment = new ProfiledSegment();
-        SegmentObject segmentObject = SegmentObject.parseFrom(segmentRecord.getDataBinary());
-        profiledSegment.getSpans().addAll(buildProfiledSpanList(segmentObject));
+        return results.stream().filter(ProfiledTraceSegments::isContainsProfiled).peek(this::removeAllCrossProcessRef).collect(Collectors.toList());
+    }
 
-        return profiledSegment;
+    private void removeAllCrossProcessRef(ProfiledTraceSegments segments) {
+        segments.getSpans().stream().filter(s -> CollectionUtils.isNotEmpty(s.getRefs()))
+            .forEach(s -> s.getRefs().removeIf(ref -> RefType.CROSS_PROCESS.equals(ref.getType())));
     }
 
-    private List<ProfiledSpan> buildProfiledSpanList(SegmentObject segmentObject) {
+    private List<ProfiledSpan> buildProfiledSpanList(SegmentObject segmentObject, boolean profiled) {
         List<ProfiledSpan> spans = new ArrayList<>();
 
         segmentObject.getSpansList().forEach(spanObject -> {
             ProfiledSpan span = new ProfiledSpan();
             span.setSpanId(spanObject.getSpanId());
             span.setParentSpanId(spanObject.getParentSpanId());
+            span.setSegmentId(segmentObject.getTraceSegmentId());
             span.setStartTime(spanObject.getStartTime());
             span.setEndTime(spanObject.getEndTime());
             span.setError(spanObject.getIsError());
@@ -230,6 +344,24 @@ public class ProfileTaskQueryService implements Service {
                 span.getLogs().add(logEntity);
             });
 
+            final List<Ref> refs = spanObject.getRefsList().stream().map(r -> {
+                final Ref ref = new Ref();
+                ref.setTraceId(r.getTraceId());
+                ref.setParentSegmentId(r.getParentTraceSegmentId());
+                ref.setParentSpanId(r.getParentSpanId());
+                switch (r.getRefType()) {
+                    case CrossThread:
+                        ref.setType(org.apache.skywalking.oap.server.core.query.type.RefType.CROSS_THREAD);
+                        break;
+                    case CrossProcess:
+                        ref.setType(org.apache.skywalking.oap.server.core.query.type.RefType.CROSS_PROCESS);
+                        break;
+                }
+                return ref;
+            }).collect(Collectors.toList());
+            span.setRefs(refs);
+            span.setProfiled(profiled);
+
             spans.add(span);
         });
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
index 91be9a8654..65d67cd454 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileAnalyzer.java
@@ -28,8 +28,8 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzation;
-import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 import org.apache.skywalking.oap.server.core.query.type.ProfileStackTree;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
@@ -64,11 +64,11 @@ public class ProfileAnalyzer {
     /**
      * search snapshots and analyze
      */
-    public ProfileAnalyzation analyze(String segmentId, List<ProfileAnalyzeTimeRange> timeRanges) throws IOException {
+    public ProfileAnalyzation analyze(final List<SegmentProfileAnalyzeQuery> queries) throws IOException {
         ProfileAnalyzation analyzation = new ProfileAnalyzation();
 
         // query sequence range list
-        SequenceSearch sequenceSearch = getAllSequenceRange(segmentId, timeRanges);
+        SequenceSearch sequenceSearch = getAllSequenceRange(queries);
         if (sequenceSearch == null) {
             analyzation.setTip("Data not found");
             return analyzation;
@@ -80,7 +80,7 @@ public class ProfileAnalyzer {
         // query snapshots
         List<ProfileStack> stacks = sequenceSearch.getRanges().parallelStream().map(r -> {
             try {
-                return getProfileThreadSnapshotQueryDAO().queryRecords(segmentId, r.getMinSequence(), r.getMaxSequence());
+                return getProfileThreadSnapshotQueryDAO().queryRecords(r.getSegmentId(), r.getMinSequence(), r.getMaxSequence());
             } catch (IOException e) {
                 LOGGER.warn(e.getMessage(), e);
                 return Collections.<ProfileThreadSnapshotRecord>emptyList();
@@ -88,7 +88,7 @@ public class ProfileAnalyzer {
         }).flatMap(Collection::stream).map(ProfileStack::deserialize).distinct().collect(Collectors.toList());
 
         // analyze
-        final List<ProfileStackTree> trees = analyze(stacks);
+        final List<ProfileStackTree> trees = analyzeByStack(stacks);
         if (trees != null) {
             analyzation.getTrees().addAll(trees);
         }
@@ -96,10 +96,10 @@ public class ProfileAnalyzer {
         return analyzation;
     }
 
-    protected SequenceSearch getAllSequenceRange(String segmentId, List<ProfileAnalyzeTimeRange> timeRanges) {
-        final List<SequenceSearch> searches = timeRanges.parallelStream().map(r -> {
+    protected SequenceSearch getAllSequenceRange(final List<SegmentProfileAnalyzeQuery> queries) {
+        final List<SequenceSearch> searches = queries.parallelStream().map(r -> {
             try {
-                return getAllSequenceRange(segmentId, r.getStart(), r.getEnd());
+                return getAllSequenceRange(r.getSegmentId(), r.getTimeRange().getStart(), r.getTimeRange().getEnd());
             } catch (IOException e) {
                 LOGGER.warn(e.getMessage(), e);
                 return null;
@@ -125,7 +125,7 @@ public class ProfileAnalyzer {
 
         do {
             int batchMax = Math.min(minSequence + threadSnapshotAnalyzeBatchSize, maxSequence);
-            sequenceSearch.getRanges().add(new SequenceRange(minSequence, batchMax));
+            sequenceSearch.getRanges().add(new SequenceRange(segmentId, minSequence, batchMax));
             minSequence = batchMax;
         }
         while (minSequence < maxSequence);
@@ -136,7 +136,7 @@ public class ProfileAnalyzer {
     /**
      * Analyze records
      */
-    protected List<ProfileStackTree> analyze(List<ProfileStack> stacks) {
+    protected List<ProfileStackTree> analyzeByStack(List<ProfileStack> stacks) {
         if (CollectionUtils.isEmpty(stacks)) {
             return null;
         }
@@ -184,14 +184,20 @@ public class ProfileAnalyzer {
     }
 
     private static class SequenceRange {
+        private String segmentId;
         private int minSequence;
         private int maxSequence;
 
-        public SequenceRange(int minSequence, int maxSequence) {
+        public SequenceRange(String segmentId, int minSequence, int maxSequence) {
+            this.segmentId = segmentId;
             this.minSequence = minSequence;
             this.maxSequence = maxSequence;
         }
 
+        public String getSegmentId() {
+            return segmentId;
+        }
+
         public int getMinSequence() {
             return minSequence;
         }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/SegmentProfileAnalyzeQuery.java
similarity index 65%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/SegmentProfileAnalyzeQuery.java
index 08acc5a155..5d0b3c8d4a 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/SegmentProfileAnalyzeQuery.java
@@ -16,22 +16,19 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core.query.type;
+package org.apache.skywalking.oap.server.core.query.input;
 
-import lombok.Getter;
-import lombok.Setter;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 
-import java.util.ArrayList;
-import java.util.List;
-
-@Getter
-@Setter
-public class ProfiledSegment {
-
-    private final List<ProfiledSpan> spans;
-
-    public ProfiledSegment() {
-        this.spans = new ArrayList<>();
-    }
-
-}
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class SegmentProfileAnalyzeQuery {
+    private String segmentId;
+    private ProfileAnalyzeTimeRange timeRange;
+}
\ No newline at end of file
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/KVInt.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/KVInt.java
index 6cbe687259..cbe6b2c5e1 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/KVInt.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/KVInt.java
@@ -26,4 +26,5 @@ import lombok.Setter;
 public class KVInt {
     private String id;
     private long value;
+    private boolean isEmptyValue;
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/NullableValue.java
similarity index 76%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/NullableValue.java
index 08acc5a155..8462ea693c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/NullableValue.java
@@ -18,20 +18,10 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Getter
-@Setter
-public class ProfiledSegment {
-
-    private final List<ProfiledSpan> spans;
-
-    public ProfiledSegment() {
-        this.spans = new ArrayList<>();
-    }
+import lombok.Data;
 
+@Data
+public class NullableValue {
+    private long value;
+    private boolean isEmptyValue;
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSpan.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSpan.java
index 0bce4e93c6..6930f7b6f8 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSpan.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSpan.java
@@ -29,6 +29,8 @@ public class ProfiledSpan {
 
     private int spanId;
     private int parentSpanId;
+    private String segmentId;
+    private List<Ref> refs;
     private String serviceCode;
     private String serviceInstanceName;
     private long startTime;
@@ -41,6 +43,7 @@ public class ProfiledSpan {
     private String layer;
     private final List<KeyValue> tags;
     private final List<LogEntity> logs;
+    private boolean profiled;
 
     public ProfiledSpan() {
         this.tags = new ArrayList<>();
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledTraceSegments.java
similarity index 61%
rename from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java
rename to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledTraceSegments.java
index 08acc5a155..04996a38ae 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledSegment.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProfiledTraceSegments.java
@@ -18,20 +18,31 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
-import lombok.Getter;
-import lombok.Setter;
+import lombok.Data;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@Getter
-@Setter
-public class ProfiledSegment {
+@Data
+public class ProfiledTraceSegments {
+    private String traceId;
+    private String instanceId;
+    private String instanceName;
+    private List<String> endpointNames;
+    private int duration;
+    private String start;
+    private List<ProfiledSpan> spans;
+    private boolean containsProfiled;
 
-    private final List<ProfiledSpan> spans;
-
-    public ProfiledSegment() {
+    public ProfiledTraceSegments() {
+        this.endpointNames = new ArrayList<>();
         this.spans = new ArrayList<>();
     }
 
+    public void merge(ProfiledTraceSegments other) {
+        this.spans.addAll(other.spans);
+        if (!this.containsProfiled) {
+            this.containsProfiled = other.containsProfiled;
+        }
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profiling/trace/IProfileThreadSnapshotQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profiling/trace/IProfileThreadSnapshotQueryDAO.java
index c063fa50f9..d5894b0746 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profiling/trace/IProfileThreadSnapshotQueryDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/profiling/trace/IProfileThreadSnapshotQueryDAO.java
@@ -21,9 +21,7 @@ package org.apache.skywalking.oap.server.core.storage.profiling.trace;
 import java.io.IOException;
 import java.util.List;
 
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.DAO;
 
 /**
@@ -32,11 +30,11 @@ import org.apache.skywalking.oap.server.core.storage.DAO;
 public interface IProfileThreadSnapshotQueryDAO extends DAO {
 
     /**
-     * search all profiled segments, need appoint taskId and snapshot sequence equals 0 sort by segment start time
+     * search all profiled segment id list, need appoint taskId and snapshot sequence equals 0 sort by segment start time
      *
      * @return it represents the segments having profile snapshot data.
      */
-    List<BasicTrace> queryProfiledSegments(String taskId) throws IOException;
+    List<String> queryProfiledSegmentIdList(String taskId) throws IOException;
 
     /**
      * search snapshots min sequence
@@ -58,8 +56,4 @@ public interface IProfileThreadSnapshotQueryDAO extends DAO {
      */
     List<ProfileThreadSnapshotRecord> queryRecords(String segmentId, int minSequence, int maxSequence) throws IOException;
 
-    /**
-     * search segment data
-     */
-    SegmentRecord getProfiledSegment(String segmentId) throws IOException;
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITraceQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITraceQueryDAO.java
index d5fc9e923c..2bf1ae7f87 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITraceQueryDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITraceQueryDAO.java
@@ -46,6 +46,10 @@ public interface ITraceQueryDAO extends Service {
 
     List<SegmentRecord> queryByTraceId(String traceId) throws IOException;
 
+    List<SegmentRecord> queryBySegmentIdList(List<String> segmentIdList) throws IOException;
+
+    List<SegmentRecord> queryByTraceIdWithInstanceId(List<String> traceIdList, List<String> instanceIdList) throws IOException;
+
     /**
      * This method gives more flexible for 3rd trace without segment concept, which can't search data through {@link #queryByTraceId(String)}
      */
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryServiceTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryServiceTest.java
new file mode 100644
index 0000000000..11550f7f07
--- /dev/null
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/ProfileTaskQueryServiceTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.profiling.trace;
+
+import org.apache.skywalking.apm.network.language.agent.v3.RefType;
+import org.apache.skywalking.apm.network.language.agent.v3.SegmentObject;
+import org.apache.skywalking.apm.network.language.agent.v3.SegmentReference;
+import org.apache.skywalking.apm.network.language.agent.v3.SpanObject;
+import org.apache.skywalking.oap.server.core.CoreModuleConfig;
+import org.apache.skywalking.oap.server.core.CoreModuleProvider;
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
+import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
+import org.apache.skywalking.oap.server.core.query.type.ProfiledTraceSegments;
+import org.apache.skywalking.oap.server.core.query.type.ProfiledSpan;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.module.ModuleProviderHolder;
+import org.apache.skywalking.oap.server.library.util.StringUtil;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opentest4j.AssertionFailedError;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ProfileTaskQueryServiceTest {
+
+    @Mock
+    private ModuleManager moduleManager;
+    @Mock
+    private CoreModuleConfig moduleConfig;
+    @Mock
+    private ModuleProviderHolder providerHolder;
+    @Mock
+    private CoreModuleProvider coreModuleProvider;
+    @Mock
+    private IComponentLibraryCatalogService catalogService;
+
+    @BeforeEach
+    public void setup() {
+        when(moduleManager.find(anyString())).thenReturn(providerHolder);
+        when(providerHolder.provider()).thenReturn(coreModuleProvider);
+        when(coreModuleProvider.getService(IComponentLibraryCatalogService.class)).thenReturn(catalogService);
+        when(catalogService.getComponentName(anyInt())).thenReturn("");
+        when(moduleConfig.getMaxPageSizeOfQueryProfileSnapshot()).thenReturn(1);
+        when(moduleConfig.getMaxSizeOfAnalyzeProfileSnapshot()).thenReturn(1);
+    }
+
+    @Test
+    public void testBuildProfiledSegmentsList() {
+        // all segment in same process
+        validate(Arrays.asList(
+            buildRecord("1B", "2A", RefType.CrossThread),
+            buildRecord("2A", "", null),
+            buildRecord("3C", "1B", RefType.CrossThread)
+        ), Arrays.asList(
+            Arrays.asList("2A", "1B", "3C")
+        ));
+
+        // segment with different process
+        validate(Arrays.asList(
+            buildRecord("A", "", null),
+            buildRecord("B", "A", RefType.CrossThread),
+
+            buildRecord("C", "B", RefType.CrossProcess),
+
+            buildRecord("D", "Z", RefType.CrossThread)
+        ), Arrays.asList(
+            Arrays.asList("A", "B"),
+            Arrays.asList("C"),
+            Arrays.asList("D")
+        ));
+    }
+
+    private void validate(List<SegmentRecord> records, List<List<String>> excepted) {
+        final ProfileTaskQueryService profileTaskQueryService = new ProfileTaskQueryService(moduleManager, moduleConfig);
+        final List<ProfiledTraceSegments> result = profileTaskQueryService.buildProfiledSegmentsList(records, records.stream().map(SegmentRecord::getSegmentId).collect(Collectors.toList()));
+        assertEquals(result.size(), excepted.size(), "result size not same");
+        for (List<String> exceptedSegments : excepted) {
+            boolean found = false;
+            for (ProfiledTraceSegments segments : result) {
+                if (segments.getSpans().stream().map(ProfiledSpan::getSegmentId).collect(Collectors.toList()).equals(exceptedSegments)) {
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found) {
+                throw new AssertionFailedError("cannot find any matches result of {}, all actual data: {}",
+                    exceptedSegments, result.stream().map(segments -> segments.getSpans().stream().map(ProfiledSpan::getSegmentId).collect(Collectors.toList())).collect(Collectors.toList()));
+            }
+        }
+    }
+
+    private SegmentRecord buildRecord(String segmentId, String parentSegmentId, RefType refType) {
+        final SegmentRecord record = new SegmentRecord();
+        record.setSegmentId(segmentId);
+        final String testServiceId = IDManager.ServiceID.buildId("test", true);
+        record.setServiceInstanceId(IDManager.ServiceInstanceID.buildId(testServiceId, "test"));
+        record.setEndpointId(IDManager.EndpointID.buildId(testServiceId, "test"));
+        final SegmentObject.Builder builder = SegmentObject.newBuilder();
+        builder.setTraceSegmentId(segmentId);
+        final SpanObject.Builder firstSpan = SpanObject.newBuilder();
+        if (StringUtil.isNotEmpty(parentSegmentId)) {
+            firstSpan.addRefs(SegmentReference.newBuilder()
+                .setParentTraceSegmentId(parentSegmentId)
+                .setRefType(refType).build());
+        }
+        builder.addSpans(firstSpan.build());
+        record.setDataBinary(builder.build().toByteArray());
+        return record;
+    }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackAnalyze.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackAnalyze.java
index 6844cee254..fa0272da7a 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackAnalyze.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackAnalyze.java
@@ -23,10 +23,8 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import lombok.Data;
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
-import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileStackTree;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
 
@@ -41,9 +39,9 @@ public class ProfileStackAnalyze {
 
     public void analyzeAndAssert(int maxAnalyzeCount) throws IOException {
         List<ProfileThreadSnapshotRecord> stacks = data.transformSnapshots();
-        final List<ProfileAnalyzeTimeRange> ranges = data.transformTimeRanges();
+        final List<SegmentProfileAnalyzeQuery> queries = data.transformQueries();
 
-        List<ProfileStackTree> trees = buildAnalyzer(stacks, maxAnalyzeCount).analyze(null, ranges).getTrees();
+        List<ProfileStackTree> trees = buildAnalyzer(stacks, maxAnalyzeCount).analyze(queries).getTrees();
 
         assertNotNull(trees);
         assertEquals(trees.size(), expected.size());
@@ -67,7 +65,7 @@ public class ProfileStackAnalyze {
         }
 
         @Override
-        public List<BasicTrace> queryProfiledSegments(String taskId) throws IOException {
+        public List<String> queryProfiledSegmentIdList(String taskId) throws IOException {
             return null;
         }
 
@@ -99,11 +97,6 @@ public class ProfileStackAnalyze {
                     .collect(Collectors.toList());
         }
 
-        @Override
-        public SegmentRecord getProfiledSegment(String segmentId) throws IOException {
-            return null;
-        }
-
     }
 
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackData.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackData.java
index 7948518da2..aee8ae0dbd 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackData.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/profiling/trace/analyze/ProfileStackData.java
@@ -22,6 +22,7 @@ import com.google.common.base.Splitter;
 import lombok.Data;
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadStack;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 
 import java.util.ArrayList;
@@ -49,19 +50,19 @@ public class ProfileStackData {
         return result;
     }
 
-    public List<ProfileAnalyzeTimeRange> transformTimeRanges() {
+    public List<SegmentProfileAnalyzeQuery> transformQueries() {
         final String[] timeRangeString = this.timeRanges.split(",");
-        final ArrayList<ProfileAnalyzeTimeRange> ranges = new ArrayList<>();
+        final ArrayList<SegmentProfileAnalyzeQuery> result = new ArrayList<>();
         for (String timeRange : timeRangeString) {
             final ProfileAnalyzeTimeRange range = new ProfileAnalyzeTimeRange();
             final String[] startEndTimes = timeRange.split("-");
 
             range.setStart(Integer.parseInt(startEndTimes[0]) * limit);
             range.setEnd(Integer.parseInt(startEndTimes[1]) * limit);
-            ranges.add(range);
+            result.add(SegmentProfileAnalyzeQuery.builder().timeRange(range).build());
         }
 
-        return ranges;
+        return result;
     }
 
 }
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 4cb19b1803..00ea8c0979 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
@@ -52,43 +52,43 @@ public class MetricsQueryUtilTest {
                 asList("200", "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},{\"id\":\"202007291426\",\"value\":3}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2},{\"id\":\"202007291426\",\"value\":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}]}}]"
             },
             {
                 asList("400", "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},{\"id\":\"202007291426\",\"value\":3}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2},{\"id\":\"202007291426\",\"value\":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}]}}]"
             },
             {
                 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},{\"id\":\"202007291426\",\"value\":3}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2},{\"id\":\"202007291426\",\"value\":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}]}}]"
             },
             {
                 Collections.singletonList("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},{\"id\":\"202007291426\",\"value\":3}]}}]"
+                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":3,\"isEmptyValue\":false}]}}]"
             },
             {
                 asList("200", "400", "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},{\"id\":\"202007291426\",\"value\":3}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2},{\"id\":\"202007291426\",\"value\":8}]}}," +
-                    "{\"label\":\"500\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":" + DEFAULT_VALUE + "},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + "}]}}]"
+                "[{\"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\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":false}]}}]"
             },
             {
                 asList("200", "400"),
                 asList("202007291425", "202007291426"),
                 of("202007291425", new DataTable("200,1|400,2")),
-                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + "}]}}," +
-                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + "}]}}]"
+                "[{\"label\":\"200\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":1,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":false}]}}," +
+                    "{\"label\":\"400\",\"values\":{\"values\":[{\"id\":\"202007291425\",\"value\":2,\"isEmptyValue\":false},{\"id\":\"202007291426\",\"value\":" + DEFAULT_VALUE + ",\"isEmptyValue\":false}]}}]"
             },
         });
     }
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricQuery.java
index d4b6f9cc34..06977eed16 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricQuery.java
@@ -35,6 +35,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.MetricsValues;
+import org.apache.skywalking.oap.server.core.query.type.NullableValue;
 import org.apache.skywalking.oap.server.core.query.type.Thermodynamic;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
@@ -92,6 +93,14 @@ public class MetricQuery implements GraphQLQueryResolver {
         return metricsValues.getValues();
     }
 
+    public NullableValue readNullableMetricsValue(MetricsCondition condition, Duration duration) {
+        // TODO default implantation
+        final NullableValue nullableValue = new NullableValue();
+        nullableValue.setValue(0);
+        nullableValue.setEmptyValue(true);
+        return nullableValue;
+    }
+
     public List<IntValues> getMultipleLinearIntValues(final MetricCondition metrics, final int numOfLinear,
                                                       final Duration duration) throws IOException {
         MetricsCondition condition = new MetricsCondition();
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
index 6ac4f93752..3811cfd1e6 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/ProfileQuery.java
@@ -21,12 +21,11 @@ package org.apache.skywalking.oap.query.graphql.resolver;
 import graphql.kickstart.tools.GraphQLQueryResolver;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskQueryService;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzation;
-import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTask;
 import org.apache.skywalking.oap.server.core.query.type.ProfileTaskLog;
-import org.apache.skywalking.oap.server.core.query.type.ProfiledSegment;
+import org.apache.skywalking.oap.server.core.query.type.ProfiledTraceSegments;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
 import java.io.IOException;
@@ -61,16 +60,12 @@ public class ProfileQuery implements GraphQLQueryResolver {
         return getProfileTaskQueryService().getProfileTaskLogs(taskID);
     }
 
-    public List<BasicTrace> getProfileTaskSegmentList(final String taskID) throws IOException {
-        return getProfileTaskQueryService().getTaskTraces(taskID);
+    public List<ProfiledTraceSegments> getProfileTaskSegments(String taskId) throws IOException {
+        return getProfileTaskQueryService().getProfileTaskSegments(taskId);
     }
 
-    public ProfiledSegment getProfiledSegment(final String segmentId) throws IOException {
-        return getProfileTaskQueryService().getProfiledSegment(segmentId);
-    }
-
-    public ProfileAnalyzation getProfileAnalyze(final String segmentId, final List<ProfileAnalyzeTimeRange> timeRanges) throws IOException {
-        return getProfileTaskQueryService().getProfileAnalyze(segmentId, timeRanges);
+    public ProfileAnalyzation getSegmentsProfileAnalyze(final List<SegmentProfileAnalyzeQuery> queries) throws IOException {
+        return getProfileTaskQueryService().getProfileAnalyze(queries);
     }
 
 }
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index 4749946962..06789e114b 160000
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit 4749946962b9c685111876d1abe8c745d3cf3253
+Subproject commit 06789e114b321b19cd23802ea7cb210732b3dbf3
diff --git a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBProfileThreadSnapshotQueryDAO.java b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBProfileThreadSnapshotQueryDAO.java
index 3072d6337f..d688a84686 100644
--- a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBProfileThreadSnapshotQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBProfileThreadSnapshotQueryDAO.java
@@ -19,16 +19,12 @@
 package org.apache.skywalking.oap.server.storage.plugin.banyandb.stream;
 
 import com.google.common.collect.ImmutableSet;
-import org.apache.skywalking.banyandb.v1.client.Element;
 import org.apache.skywalking.banyandb.v1.client.RowEntity;
 import org.apache.skywalking.banyandb.v1.client.StreamQuery;
 import org.apache.skywalking.banyandb.v1.client.StreamQueryResponse;
-import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
-import org.apache.skywalking.oap.server.library.util.BooleanUtils;
 import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBConverter;
 import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageClient;
 
@@ -80,7 +76,7 @@ public class BanyanDBProfileThreadSnapshotQueryDAO extends AbstractBanyanDBDAO i
     }
 
     @Override
-    public List<BasicTrace> queryProfiledSegments(String taskId) throws IOException {
+    public List<String> queryProfiledSegmentIdList(String taskId) throws IOException {
         StreamQueryResponse resp = query(ProfileThreadSnapshotRecord.INDEX_NAME,
                 TAGS_BASIC,
                 new QueryBuilder<StreamQuery>() {
@@ -102,42 +98,7 @@ public class BanyanDBProfileThreadSnapshotQueryDAO extends AbstractBanyanDBDAO i
             segmentIds.add(rowEntity.getTagValue(ProfileThreadSnapshotRecord.SEGMENT_ID));
         }
 
-        if (segmentIds.isEmpty()) {
-            return Collections.emptyList();
-        }
-
-        final StreamQueryResponse segmentRecordResp = query(SegmentRecord.INDEX_NAME,
-                TAGS_TRACE,
-                new QueryBuilder<StreamQuery>() {
-                    @Override
-                    public void apply(StreamQuery traceQuery) {
-                        // TODO: use "in" operator
-                        for (final String segmentID : segmentIds) {
-                            traceQuery.or(eq(SegmentRecord.SEGMENT_ID, segmentID));
-                        }
-                        traceQuery.setLimit(segmentIds.size());
-                        traceQuery.setOrderBy(desc(SegmentRecord.START_TIME));
-                    }
-                });
-
-        List<BasicTrace> basicTraces = new ArrayList<>();
-        for (final Element row : segmentRecordResp.getElements()) {
-            BasicTrace basicTrace = new BasicTrace();
-
-            basicTrace.setSegmentId(row.getId());
-            basicTrace.setStart(String.valueOf((Number) row.getTagValue(SegmentRecord.START_TIME)));
-            basicTrace.getEndpointNames().add(IDManager.EndpointID.analysisId(
-                    row.getTagValue(SegmentRecord.ENDPOINT_ID)
-            ).getEndpointName());
-            basicTrace.setDuration(((Number) row.getTagValue(SegmentRecord.LATENCY)).intValue());
-            basicTrace.setError(BooleanUtils.valueToBoolean(
-                    ((Number) row.getTagValue(SegmentRecord.IS_ERROR)).intValue()
-            ));
-            basicTrace.getTraceIds().add(row.getTagValue(SegmentRecord.TRACE_ID));
-
-            basicTraces.add(basicTrace);
-        }
-        return basicTraces;
+        return segmentIds;
     }
 
     @Override
@@ -172,26 +133,6 @@ public class BanyanDBProfileThreadSnapshotQueryDAO extends AbstractBanyanDBDAO i
         return result;
     }
 
-    @Override
-    public SegmentRecord getProfiledSegment(String segmentId) throws IOException {
-        StreamQueryResponse resp = query(SegmentRecord.INDEX_NAME,
-                TAGS_TRACE_ALL,
-                new QueryBuilder<StreamQuery>() {
-                    @Override
-                    public void apply(StreamQuery query) {
-                        query.and(eq(SegmentRecord.SEGMENT_ID, segmentId));
-                    }
-                });
-
-        if (resp.size() == 0) {
-            return null;
-        }
-
-        final RowEntity rowEntity = resp.getElements().iterator().next();
-        return new SegmentRecord.Builder().storage2Entity(
-                new BanyanDBConverter.StorageToStream(SegmentRecord.INDEX_NAME, rowEntity));
-    }
-
     private int querySequenceWithAgg(AggType aggType, String segmentId, long start, long end) throws IOException {
         StreamQueryResponse resp = query(ProfileThreadSnapshotRecord.INDEX_NAME,
                 TAGS_ALL,
diff --git a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBTraceQueryDAO.java b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBTraceQueryDAO.java
index 641204bc3d..69113c005c 100644
--- a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBTraceQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/stream/BanyanDBTraceQueryDAO.java
@@ -68,6 +68,7 @@ public class BanyanDBTraceQueryDAO extends AbstractBanyanDBDAO implements ITrace
             SegmentRecord.ENDPOINT_ID,
             SegmentRecord.LATENCY,
             SegmentRecord.START_TIME,
+            SegmentRecord.SEGMENT_ID,
             SegmentRecord.DATA_BINARY);
 
     public BanyanDBTraceQueryDAO(BanyanDBStorageClient client) {
@@ -182,20 +183,48 @@ public class BanyanDBTraceQueryDAO extends AbstractBanyanDBDAO implements ITrace
                         query.and(eq(SegmentRecord.TRACE_ID, traceId));
                     }
                 });
+        return buildRecords(resp);
+    }
+
+    @Override
+    public List<SegmentRecord> queryBySegmentIdList(List<String> segmentIdList) throws IOException {
+        StreamQueryResponse resp = query(SegmentRecord.INDEX_NAME, TAGS,
+            new QueryBuilder<StreamQuery>() {
+                @Override
+                public void apply(StreamQuery query) {
+                    query.and(in(SegmentRecord.SEGMENT_ID, segmentIdList));
+                }
+            });
+        return buildRecords(resp);
+    }
+
+    @Override
+    public List<SegmentRecord> queryByTraceIdWithInstanceId(List<String> traceIdList, List<String> instanceIdList) throws IOException {
+        StreamQueryResponse resp = query(SegmentRecord.INDEX_NAME, TAGS,
+            new QueryBuilder<StreamQuery>() {
+                @Override
+                public void apply(StreamQuery query) {
+                    query.and(in(SegmentRecord.TRACE_ID, traceIdList));
+                    query.and(in(SegmentRecord.SERVICE_INSTANCE_ID, instanceIdList));
+                }
+            });
+        return buildRecords(resp);
+    }
 
+    @Override
+    public List<Span> doFlexibleTraceQuery(String traceId) throws IOException {
+        return Collections.emptyList();
+    }
+
+    private List<SegmentRecord> buildRecords(StreamQueryResponse resp) {
         List<SegmentRecord> segmentRecords = new ArrayList<>(resp.getElements().size());
 
         for (final RowEntity rowEntity : resp.getElements()) {
             SegmentRecord segmentRecord = new SegmentRecord.Builder().storage2Entity(
-                    new BanyanDBConverter.StorageToStream(SegmentRecord.INDEX_NAME, rowEntity));
+                new BanyanDBConverter.StorageToStream(SegmentRecord.INDEX_NAME, rowEntity));
             segmentRecords.add(segmentRecord);
         }
 
         return segmentRecords;
     }
-
-    @Override
-    public List<Span> doFlexibleTraceQuery(String traceId) throws IOException {
-        return Collections.emptyList();
-    }
 }
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
index 97f2ee26c5..5669ead679 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/ProfileThreadSnapshotQueryEsDAO.java
@@ -18,13 +18,12 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
-import com.google.common.base.Strings;
+import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Base64;
-import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+
 import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder;
 import org.apache.skywalking.library.elasticsearch.requests.search.Query;
 import org.apache.skywalking.library.elasticsearch.requests.search.Search;
@@ -34,14 +33,9 @@ import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.A
 import org.apache.skywalking.library.elasticsearch.requests.search.aggregation.AggregationBuilder;
 import org.apache.skywalking.library.elasticsearch.response.search.SearchHit;
 import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse;
-import org.apache.skywalking.oap.server.core.analysis.IDManager;
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
-import org.apache.skywalking.oap.server.library.util.BooleanUtils;
-import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.ElasticSearchConverter;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController;
@@ -61,22 +55,22 @@ public class ProfileThreadSnapshotQueryEsDAO extends EsDAO
     }
 
     @Override
-    public List<BasicTrace> queryProfiledSegments(String taskId) {
+    public List<String> queryProfiledSegmentIdList(String taskId) throws IOException {
         final BoolQueryBuilder segmentIdQuery =
             Query.bool()
-                 .must(Query.term(ProfileThreadSnapshotRecord.TASK_ID, taskId))
-                 .must(Query.term(ProfileThreadSnapshotRecord.SEQUENCE, 0));
+                .must(Query.term(ProfileThreadSnapshotRecord.TASK_ID, taskId))
+                .must(Query.term(ProfileThreadSnapshotRecord.SEQUENCE, 0));
         if (IndexController.LogicIndicesRegister.isMergedTable(ProfileThreadSnapshotRecord.INDEX_NAME)) {
             segmentIdQuery.must(Query.term(IndexController.LogicIndicesRegister.RECORD_TABLE_NAME, ProfileThreadSnapshotRecord.INDEX_NAME));
         }
 
         final SearchBuilder search =
             Search.builder().query(segmentIdQuery)
-                  .size(querySegmentMaxSize)
-                  .sort(
-                      ProfileThreadSnapshotRecord.DUMP_TIME,
-                      Sort.Order.DESC
-                  );
+                .size(querySegmentMaxSize)
+                .sort(
+                    ProfileThreadSnapshotRecord.DUMP_TIME,
+                    Sort.Order.DESC
+                );
 
         SearchResponse response =
             getClient().search(
@@ -90,44 +84,7 @@ public class ProfileThreadSnapshotQueryEsDAO extends EsDAO
             segmentIds.add(
                 (String) searchHit.getSource().get(ProfileThreadSnapshotRecord.SEGMENT_ID));
         }
-
-        if (CollectionUtils.isEmpty(segmentIds)) {
-            return Collections.emptyList();
-        }
-
-        final BoolQueryBuilder traceQuery = Query.bool();
-        for (String segmentId : segmentIds) {
-            traceQuery.should(Query.term(SegmentRecord.SEGMENT_ID, segmentId));
-        }
-        final SearchBuilder traceSearch =
-            Search.builder().query(traceQuery)
-                  .size(segmentIds.size())
-                  .sort(SegmentRecord.START_TIME, Sort.Order.DESC);
-
-        response = getClient().search(SegmentRecord.INDEX_NAME, traceSearch.build());
-
-        List<BasicTrace> result = new ArrayList<>();
-        for (SearchHit searchHit : response.getHits().getHits()) {
-            BasicTrace basicTrace = new BasicTrace();
-
-            basicTrace.setSegmentId((String) searchHit.getSource().get(SegmentRecord.SEGMENT_ID));
-            basicTrace.setStart(
-                String.valueOf(searchHit.getSource().get(SegmentRecord.START_TIME)));
-            basicTrace.getEndpointNames().add(
-                IDManager.EndpointID.analysisId(
-                    (String) searchHit.getSource().get(SegmentRecord.ENDPOINT_ID)
-                ).getEndpointName());
-            basicTrace.setDuration(
-                ((Number) searchHit.getSource().get(SegmentRecord.LATENCY)).intValue());
-            basicTrace.setError(BooleanUtils.valueToBoolean(
-                ((Number) searchHit.getSource().get(SegmentRecord.IS_ERROR)).intValue()));
-            basicTrace.getTraceIds()
-                      .add((String) searchHit.getSource().get(SegmentRecord.TRACE_ID));
-
-            result.add(basicTrace);
-        }
-
-        return result;
+        return segmentIds;
     }
 
     @Override
@@ -177,38 +134,6 @@ public class ProfileThreadSnapshotQueryEsDAO extends EsDAO
         return result;
     }
 
-    @Override
-    public SegmentRecord getProfiledSegment(String segmentId) {
-        final String index =
-            IndexController.LogicIndicesRegister.getPhysicalTableName(SegmentRecord.INDEX_NAME);
-        final SearchBuilder search =
-            Search.builder()
-                  .query(Query.term(SegmentRecord.SEGMENT_ID, segmentId))
-                  .size(1);
-
-        final SearchResponse response = getClient().search(index, search.build());
-
-        if (response.getHits().getHits().isEmpty()) {
-            return null;
-        }
-        final SearchHit searchHit = response.getHits().iterator().next();
-        final SegmentRecord segmentRecord = new SegmentRecord();
-        segmentRecord.setSegmentId((String) searchHit.getSource().get(SegmentRecord.SEGMENT_ID));
-        segmentRecord.setTraceId((String) searchHit.getSource().get(SegmentRecord.TRACE_ID));
-        segmentRecord.setServiceId((String) searchHit.getSource().get(SegmentRecord.SERVICE_ID));
-        segmentRecord.setStartTime(
-            ((Number) searchHit.getSource().get(SegmentRecord.START_TIME)).longValue());
-        segmentRecord.setLatency(
-            ((Number) searchHit.getSource().get(SegmentRecord.LATENCY)).intValue());
-        segmentRecord.setIsError(
-            ((Number) searchHit.getSource().get(SegmentRecord.IS_ERROR)).intValue());
-        String dataBinaryBase64 = (String) searchHit.getSource().get(SegmentRecord.DATA_BINARY);
-        if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
-            segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
-        }
-        return segmentRecord;
-    }
-
     protected int querySequenceWithAgg(AggregationBuilder aggregationBuilder,
                                        String segmentId, long start, long end) {
         final BoolQueryBuilder query =
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TraceQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TraceQueryEsDAO.java
index 7e98512f18..c8fdb2eef6 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TraceQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TraceQueryEsDAO.java
@@ -184,6 +184,47 @@ public class TraceQueryEsDAO extends EsDAO implements ITraceQueryDAO {
 
         final SearchResponse response = getClient().search(index, search.build(), searchParams);
 
+        return buildRecords(response);
+    }
+
+    @Override
+    public List<SegmentRecord> queryBySegmentIdList(List<String> segmentIdList) throws IOException {
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(SegmentRecord.INDEX_NAME);
+
+        final SearchBuilder search =
+            Search.builder()
+                .query(Query.terms(SegmentRecord.SEGMENT_ID, segmentIdList))
+                .size(segmentQueryMaxSize);
+
+        SearchParams searchParams = new SearchParams();
+        final SearchResponse response = getClient().search(index, search.build(), searchParams);
+
+        return buildRecords(response);
+    }
+
+    @Override
+    public List<SegmentRecord> queryByTraceIdWithInstanceId(List<String> traceIdList, List<String> instanceIdList) throws IOException {
+        final String index =
+            IndexController.LogicIndicesRegister.getPhysicalTableName(SegmentRecord.INDEX_NAME);
+
+        final SearchBuilder search =
+            Search.builder()
+                .query(Query.bool().must(Query.terms(SegmentRecord.TRACE_ID, traceIdList)).must(Query.terms(SegmentRecord.SERVICE_INSTANCE_ID, instanceIdList)))
+                .size(segmentQueryMaxSize);
+
+        SearchParams searchParams = new SearchParams();
+        final SearchResponse response = getClient().search(index, search.build(), searchParams);
+
+        return buildRecords(response);
+    }
+
+    @Override
+    public List<Span> doFlexibleTraceQuery(String traceId) throws IOException {
+        return Collections.emptyList();
+    }
+
+    private List<SegmentRecord> buildRecords(SearchResponse response) {
         List<SegmentRecord> segmentRecords = new ArrayList<>();
         for (SearchHit searchHit : response.getHits().getHits()) {
             SegmentRecord segmentRecord = new SegmentRecord.Builder().storage2Entity(
@@ -192,9 +233,4 @@ public class TraceQueryEsDAO extends EsDAO implements ITraceQueryDAO {
         }
         return segmentRecords;
     }
-
-    @Override
-    public List<Span> doFlexibleTraceQuery(String traceId) throws IOException {
-        return Collections.emptyList();
-    }
 }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java
index 5370a5b43b..2da30dd129 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCProfileThreadSnapshotQueryDAO.java
@@ -18,100 +18,36 @@
 
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.common.dao;
 
-import com.google.common.base.Strings;
 import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
-import org.apache.skywalking.oap.server.core.analysis.IDManager;
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
 import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient;
-import org.apache.skywalking.oap.server.library.util.BooleanUtils;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInstaller;
-import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.SQLAndParameters;
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
 import java.io.IOException;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Base64;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.stream.IntStream;
 
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
-
 @RequiredArgsConstructor
 public class JDBCProfileThreadSnapshotQueryDAO implements IProfileThreadSnapshotQueryDAO {
     private final JDBCClient jdbcClient;
     private final TableHelper tableHelper;
 
-    @Override
     @SneakyThrows
-    public List<BasicTrace> queryProfiledSegments(String taskId) {
-        final var tables = tableHelper.getTablesWithinTTL(ProfileThreadSnapshotRecord.INDEX_NAME);
-        final var results = new ArrayList<BasicTrace>();
-        final var segments = new ArrayList<>();
-
-        for (String table : tables) {
+    @Override
+    public List<String> queryProfiledSegmentIdList(String taskId) throws IOException {
+        final var snapshotTables = tableHelper.getTablesWithinTTL(ProfileThreadSnapshotRecord.INDEX_NAME);
+        final var segments = new ArrayList<String>();
+        for (String table : snapshotTables) {
             segments.addAll(querySegments(taskId, table));
         }
-
-        if (segments.isEmpty()) {
-            return Collections.emptyList();
-        }
-
-        final var segmentTables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
-        for (String table : segmentTables) {
-            final var sql = new StringBuilder();
-            final var parameters = new ArrayList<>();
-
-            sql.append("select * from ").append(table).append(" where ")
-                .append(JDBCTableInstaller.TABLE_COLUMN).append(" = ? and ");
-            parameters.add(SegmentRecord.INDEX_NAME);
-
-            final var segmentQuery =
-                segments
-                    .stream()
-                    .map(it -> SegmentRecord.SEGMENT_ID + " = ? ")
-                    .collect(joining(" or ", "(", ")"));
-            sql.append(segmentQuery);
-            parameters.addAll(segments);
-            sql.append(" order by ").append(SegmentRecord.START_TIME).append(" ").append("desc");
-
-            final var sqlAndParameters = new SQLAndParameters(sql.toString(), parameters);
-
-            jdbcClient.executeQuery(
-                sqlAndParameters.sql(),
-                resultSet -> {
-                    while (resultSet.next()) {
-                        BasicTrace basicTrace = new BasicTrace();
-
-                        basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                        basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));
-                        basicTrace.getEndpointNames().add(
-                            IDManager.EndpointID.analysisId(
-                                resultSet.getString(SegmentRecord.ENDPOINT_ID)).getEndpointName()
-                        );
-                        basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));
-                        basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));
-                        String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);
-                        basicTrace.getTraceIds().add(traceIds);
-
-                        results.add(basicTrace);
-                    }
-                    return null;
-                },
-                sqlAndParameters.parameters());
-        }
-        return results
-            .stream()
-            .sorted(Comparator.<BasicTrace, Long>comparing(it -> Long.parseLong(it.getStart())).reversed())
-            .collect(toList());
+        return segments;
     }
 
     protected ArrayList<String> querySegments(String taskId, String table) throws SQLException {
@@ -193,42 +129,6 @@ public class JDBCProfileThreadSnapshotQueryDAO implements IProfileThreadSnapshot
         return results;
     }
 
-    @Override
-    @SneakyThrows
-    public SegmentRecord getProfiledSegment(String segmentId) throws IOException {
-        final var tables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
-        for (final var table : tables) {
-            final var r = jdbcClient.executeQuery(
-                "select * from " + table +
-                    " where " + JDBCTableInstaller.TABLE_COLUMN + " = ?" +
-                    " and " + SegmentRecord.SEGMENT_ID + " = ?",
-                resultSet -> {
-                    if (resultSet.next()) {
-                        SegmentRecord segmentRecord = new SegmentRecord();
-                        segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                        segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
-                        segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
-                        segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
-                        segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
-                        segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
-                        segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
-                        String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
-                        if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
-                            segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
-                        }
-                        return segmentRecord;
-                    }
-                    return null;
-                },
-                SegmentRecord.INDEX_NAME, segmentId
-            );
-            if (r != null) {
-                return r;
-            }
-        }
-        return null;
-    }
-
     @SneakyThrows
     private int querySequenceWithAgg(String aggType, String segmentId, long start, long end) throws IOException {
         final var tables = tableHelper.getTablesWithinTTL(ProfileThreadSnapshotRecord.INDEX_NAME);
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java
index ad5fc9a811..b01af83985 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/common/dao/JDBCTraceQueryDAO.java
@@ -44,6 +44,8 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCTableInst
 import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper;
 
 import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Base64;
@@ -51,6 +53,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static java.util.Objects.nonNull;
 import static java.util.function.Predicate.not;
@@ -65,6 +68,16 @@ public class JDBCTraceQueryDAO implements ITraceQueryDAO {
 
     private Set<String> searchableTagKeys;
 
+    private static String DETAIL_SELECT_QUERY = "select " + SegmentRecord.SEGMENT_ID + ", " +
+        SegmentRecord.TRACE_ID + ", " +
+        SegmentRecord.ENDPOINT_ID + ", " +
+        SegmentRecord.SERVICE_ID + ", " +
+        SegmentRecord.SERVICE_INSTANCE_ID + ", " +
+        SegmentRecord.START_TIME + ", " +
+        SegmentRecord.LATENCY + ", " +
+        SegmentRecord.IS_ERROR + ", " +
+        SegmentRecord.DATA_BINARY;
+
     @Override
     @SneakyThrows
     public TraceBrief queryBasicTraces(Duration duration,
@@ -228,32 +241,11 @@ public class JDBCTraceQueryDAO implements ITraceQueryDAO {
 
         for (String table : tables) {
             jdbcClient.executeQuery(
-                "select " + SegmentRecord.SEGMENT_ID + ", " +
-                    SegmentRecord.TRACE_ID + ", " +
-                    SegmentRecord.SERVICE_ID + ", " +
-                    SegmentRecord.SERVICE_INSTANCE_ID + ", " +
-                    SegmentRecord.START_TIME + ", " +
-                    SegmentRecord.LATENCY + ", " +
-                    SegmentRecord.IS_ERROR + ", " +
-                    SegmentRecord.DATA_BINARY + " from " + table + " where " +
+                DETAIL_SELECT_QUERY + " from " + table + " where " +
                     JDBCTableInstaller.TABLE_COLUMN + " = ? and " +
                     SegmentRecord.TRACE_ID + " = ?",
                 resultSet -> {
-                    while (resultSet.next()) {
-                        SegmentRecord segmentRecord = new SegmentRecord();
-                        segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
-                        segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
-                        segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
-                        segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
-                        segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
-                        segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
-                        segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
-                        String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
-                        if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
-                            segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
-                        }
-                        segmentRecords.add(segmentRecord);
-                    }
+                    segmentRecords.addAll(buildRecords(resultSet));
                     return null;
                 },
                 SegmentRecord.INDEX_NAME, traceId
@@ -262,8 +254,82 @@ public class JDBCTraceQueryDAO implements ITraceQueryDAO {
         return segmentRecords;
     }
 
+    @SneakyThrows
+    @Override
+    public List<SegmentRecord> queryBySegmentIdList(List<String> segmentIdList) throws IOException {
+        final var tables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
+        final var segmentRecords = new ArrayList<SegmentRecord>();
+        final ArrayList<String> conditions = new ArrayList<>();
+        conditions.add(SegmentRecord.INDEX_NAME);
+        conditions.addAll(segmentIdList);
+
+        for (String table : tables) {
+            jdbcClient.executeQuery(
+                DETAIL_SELECT_QUERY + " from " + table + " where " +
+                    JDBCTableInstaller.TABLE_COLUMN + " = ? and " +
+                    SegmentRecord.SEGMENT_ID + " in " +
+                    segmentIdList.stream().map(it -> "?").collect(Collectors.joining(",", "(", ")")),
+                resultSet -> {
+                    segmentRecords.addAll(buildRecords(resultSet));
+                    return null;
+                },
+                conditions.toArray()
+            );
+        }
+        return segmentRecords;
+    }
+
+    @SneakyThrows
+    @Override
+    public List<SegmentRecord> queryByTraceIdWithInstanceId(List<String> traceIdList, List<String> instanceIdList) throws IOException {
+        final var tables = tableHelper.getTablesWithinTTL(SegmentRecord.INDEX_NAME);
+        final var segmentRecords = new ArrayList<SegmentRecord>();
+        final ArrayList<String> conditions = new ArrayList<>();
+        conditions.add(SegmentRecord.INDEX_NAME);
+        conditions.addAll(traceIdList);
+        conditions.addAll(instanceIdList);
+
+        for (String table : tables) {
+            jdbcClient.executeQuery(
+                DETAIL_SELECT_QUERY + " from " + table + " where " +
+                    JDBCTableInstaller.TABLE_COLUMN + " = ? and " +
+                    SegmentRecord.TRACE_ID + " in " +
+                    traceIdList.stream().map(it -> "?").collect(Collectors.joining(",", "(", ") and ")) +
+                    SegmentRecord.SERVICE_INSTANCE_ID + " in " +
+                    instanceIdList.stream().map(it -> "?").collect(Collectors.joining(",", "(", ")")),
+                resultSet -> {
+                    segmentRecords.addAll(buildRecords(resultSet));
+                    return null;
+                },
+                conditions.toArray()
+            );
+        }
+        return segmentRecords;
+    }
+
     @Override
     public List<Span> doFlexibleTraceQuery(String traceId) {
         return Collections.emptyList();
     }
+
+    private List<SegmentRecord> buildRecords(ResultSet resultSet) throws SQLException {
+        final List<SegmentRecord> records = new ArrayList<>();
+        while (resultSet.next()) {
+            SegmentRecord segmentRecord = new SegmentRecord();
+            segmentRecord.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));
+            segmentRecord.setTraceId(resultSet.getString(SegmentRecord.TRACE_ID));
+            segmentRecord.setEndpointId(resultSet.getString(SegmentRecord.ENDPOINT_ID));
+            segmentRecord.setServiceId(resultSet.getString(SegmentRecord.SERVICE_ID));
+            segmentRecord.setServiceInstanceId(resultSet.getString(SegmentRecord.SERVICE_INSTANCE_ID));
+            segmentRecord.setStartTime(resultSet.getLong(SegmentRecord.START_TIME));
+            segmentRecord.setLatency(resultSet.getInt(SegmentRecord.LATENCY));
+            segmentRecord.setIsError(resultSet.getInt(SegmentRecord.IS_ERROR));
+            String dataBinaryBase64 = resultSet.getString(SegmentRecord.DATA_BINARY);
+            if (!Strings.isNullOrEmpty(dataBinaryBase64)) {
+                segmentRecord.setDataBinary(Base64.getDecoder().decode(dataBinaryBase64));
+            }
+            records.add(segmentRecord);
+        }
+        return records;
+    }
 }
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotDumper.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotDumper.java
index deb2924450..8c490833ba 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotDumper.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotDumper.java
@@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadSnapshot;
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadStack;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
@@ -50,13 +50,12 @@ public class ProfileSnapshotDumper {
         List<ProfiledBasicInfo.SequenceRange> sequenceRanges = basicInfo.buildSequenceRanges();
         int rangeCount = sequenceRanges.size();
 
-        String segmentId = basicInfo.getSegmentId();
         File snapshotFile = new File(basicInfo.getConfig().getAnalyzeResultDist() + File.separator + "snapshot.data");
 
         // reading data and write to file
         try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(snapshotFile))) {
             for (int i = 0; i < rangeCount; i++) {
-                List<ProfileThreadSnapshotRecord> records = querySnapshot(segmentId, snapshotQueryDAO, sequenceRanges.get(i));
+                List<ProfileThreadSnapshotRecord> records = querySnapshot(snapshotQueryDAO, sequenceRanges.get(i));
                 for (ProfileThreadSnapshotRecord record : records) {
                     // transform to proto data and save it
                     ThreadSnapshot.newBuilder()
@@ -80,10 +79,10 @@ public class ProfileSnapshotDumper {
     /**
      * query snapshots with retry mechanism
      */
-    private static List<ProfileThreadSnapshotRecord> querySnapshot(String segmentId, IProfileThreadSnapshotQueryDAO threadSnapshotQueryDAO, ProfiledBasicInfo.SequenceRange sequenceRange) throws IOException {
+    private static List<ProfileThreadSnapshotRecord> querySnapshot(IProfileThreadSnapshotQueryDAO threadSnapshotQueryDAO, ProfiledBasicInfo.SequenceRange sequenceRange) throws IOException {
         for (int i = 1; i <= QUERY_PROFILE_SNAPSHOT_RETRY_COUNT; i++) {
             try {
-                return threadSnapshotQueryDAO.queryRecords(segmentId, sequenceRange.getMin(), sequenceRange.getMax());
+                return threadSnapshotQueryDAO.queryRecords(sequenceRange.getSegmentId(), sequenceRange.getMin(), sequenceRange.getMax());
             } catch (IOException e) {
                 if (i == QUERY_PROFILE_SNAPSHOT_RETRY_COUNT) {
                     throw e;
@@ -96,13 +95,13 @@ public class ProfileSnapshotDumper {
     /**
      * load thread snapshots in appointing time range
      */
-    public static List<ThreadSnapshot> parseFromFileWithTimeRange(File file, List<ProfileAnalyzeTimeRange> timeRanges) throws IOException {
+    public static List<ThreadSnapshot> parseFromFileWithTimeRange(File file, final List<SegmentProfileAnalyzeQuery> queries) throws IOException {
         try (final FileInputStream fileInputStream = new FileInputStream(file)) {
             ThreadSnapshot snapshot;
             final ArrayList<ThreadSnapshot> data = new ArrayList<>();
             while ((snapshot = ThreadSnapshot.parseDelimitedFrom(fileInputStream)) != null) {
                 ThreadSnapshot finalSnapshot = snapshot;
-                if (timeRanges.stream().filter(t -> finalSnapshot.getTime() >= t.getStart() && finalSnapshot.getTime() <= t.getEnd()).findFirst().isPresent()) {
+                if (queries.stream().anyMatch(t -> finalSnapshot.getTime() >= t.getTimeRange().getStart() && finalSnapshot.getTime() <= t.getTimeRange().getEnd())) {
                     data.add(snapshot);
                 }
             }
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotExporterBootstrap.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotExporterBootstrap.java
index 8afb452d43..9ff9e5ffa0 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotExporterBootstrap.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileSnapshotExporterBootstrap.java
@@ -41,9 +41,9 @@ public class ProfileSnapshotExporterBootstrap {
 
             // prepare basic info
             ProfiledBasicInfo profiledBaseInfo = ProfiledBasicInfo.build(exporterConfig, manager);
-            log.info("Queried profiled basic info, profiled segment start time:{}, duration:{}, total span count:{}, snapshot count:{}",
-                    profiledBaseInfo.getSegmentStartTime(), profiledBaseInfo.getDuration(), profiledBaseInfo.getProfiledSegmentSpans().size(),
-                    profiledBaseInfo.getMaxSequence() - profiledBaseInfo.getMinSequence());
+            log.info("Queried profiled basic info, segment count: {}, total span count:{}",
+                    profiledBaseInfo.getSegments().size(),
+                    profiledBaseInfo.getProfiledSegmentSpans().size());
 
             // write basic info to file
             File basicInfoFile = profiledBaseInfo.writeFile();
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfiledBasicInfo.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfiledBasicInfo.java
index 923640f552..c9a824443d 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfiledBasicInfo.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/main/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfiledBasicInfo.java
@@ -22,9 +22,9 @@ import lombok.Data;
 import lombok.Getter;
 import org.apache.commons.io.FileUtils;
 import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskQueryService;
 import org.apache.skywalking.oap.server.core.query.TraceQueryService;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.query.type.Span;
 import org.apache.skywalking.oap.server.core.query.type.Trace;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
@@ -49,18 +49,11 @@ public class ProfiledBasicInfo {
     private ExporterConfig config;
 
     // profiled segment
-    private String segmentId;
-    private long segmentStartTime;
-    private long segmentEndTime;
-    private int duration;
+    private List<ProfiledSegment> segments;
 
     // spans
     private List<Span> profiledSegmentSpans;
 
-    // snapshot sequence
-    private int minSequence;
-    private int maxSequence;
-
     /**
      * reading data from storage and build data
      */
@@ -73,35 +66,43 @@ public class ProfiledBasicInfo {
         IProfileThreadSnapshotQueryDAO threadSnapshotQueryDAO = manager.find(StorageModule.NAME).provider().getService(IProfileThreadSnapshotQueryDAO.class);
 
         // query and found profiled segment
-        List<BasicTrace> taskTraces = taskQueryService.getTaskTraces(config.getTaskId());
-        BasicTrace profiledTrace = taskTraces.stream().filter(t -> t.getTraceIds().contains(config.getTraceId())).findFirst().orElse(null);
-        if (profiledTrace == null) {
+        List<SegmentRecord> taskTraces = taskQueryService.getTaskSegments(config.getTaskId());
+        List<SegmentRecord> segments = taskTraces.stream().filter(t -> Objects.equals(t.getTraceId(), config.getTraceId())).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(segments)) {
             throw new IllegalArgumentException("Cannot fount profiled segment in current task: " + config.getTaskId()
                     + ", segment id: " + config.getTraceId() + ", current task total profiled trace count is " + taskTraces.size());
         }
 
         // setting segment basic info
-        String segmentId = profiledTrace.getSegmentId();
-        long startTime = Long.parseLong(profiledTrace.getStart());
-        long endTime = startTime + profiledTrace.getDuration();
-        data.setSegmentId(segmentId);
-        data.setSegmentStartTime(startTime);
-        data.setSegmentEndTime(endTime);
-        data.setDuration(profiledTrace.getDuration());
-
-        // query spans
-        Trace trace = traceQueryService.queryTrace(config.getTraceId());
-        List<Span> profiledSegmentSpans = trace.getSpans().stream().filter(s -> Objects.equals(s.getSegmentId(), segmentId)).collect(Collectors.toList());
-        if (CollectionUtils.isEmpty(profiledSegmentSpans)) {
-            throw new IllegalArgumentException("Current segment cannot found any span");
+        data.setSegments(new ArrayList<>());
+        data.setProfiledSegmentSpans(new ArrayList<>());
+        for (SegmentRecord segment : segments) {
+            final ProfiledSegment profiledSegment = new ProfiledSegment();
+
+            String segmentId = segment.getSegmentId();
+            long startTime = segment.getStartTime();
+            long endTime = startTime + segment.getLatency();
+            profiledSegment.setSegmentId(segmentId);
+            profiledSegment.setSegmentStartTime(startTime);
+            profiledSegment.setSegmentEndTime(endTime);
+            profiledSegment.setDuration(segment.getLatency());
+
+            // query spans
+            Trace trace = traceQueryService.queryTrace(config.getTraceId());
+            List<Span> profiledSegmentSpans = trace.getSpans().stream().filter(s -> Objects.equals(s.getSegmentId(), segmentId)).collect(Collectors.toList());
+            if (CollectionUtils.isEmpty(profiledSegmentSpans)) {
+                throw new IllegalArgumentException("Current segment cannot found any span");
+            }
+            data.getProfiledSegmentSpans().addAll(profiledSegmentSpans);
+
+            // query snapshots sequences
+            int minSequence = threadSnapshotQueryDAO.queryMinSequence(segmentId, startTime, endTime);
+            int maxSequence = threadSnapshotQueryDAO.queryMaxSequence(segmentId, startTime, endTime);
+            profiledSegment.setMinSequence(minSequence);
+            profiledSegment.setMaxSequence(maxSequence);
+
+            data.getSegments().add(profiledSegment);
         }
-        data.setProfiledSegmentSpans(profiledSegmentSpans);
-
-        // query snapshots sequences
-        int minSequence = threadSnapshotQueryDAO.queryMinSequence(segmentId, startTime, endTime);
-        int maxSequence = threadSnapshotQueryDAO.queryMaxSequence(segmentId, startTime, endTime);
-        data.setMinSequence(minSequence);
-        data.setMaxSequence(maxSequence);
 
         return data;
     }
@@ -130,25 +131,42 @@ public class ProfiledBasicInfo {
      */
     public List<SequenceRange> buildSequenceRanges() {
         ArrayList<SequenceRange> ranges = new ArrayList<>();
-        do {
-            int batchMax = Math.min(minSequence + SEQUENCE_RANGE_BATCH_SIZE, maxSequence);
-            ranges.add(new SequenceRange(minSequence, batchMax));
-            minSequence = batchMax;
+        for (ProfiledSegment segment : this.segments) {
+            int minSequence = segment.minSequence;
+            do {
+                int batchMax = Math.min(minSequence + SEQUENCE_RANGE_BATCH_SIZE, segment.maxSequence);
+                ranges.add(new SequenceRange(segment.getSegmentId(), minSequence, batchMax));
+                minSequence = batchMax;
+            }
+            while (minSequence < segment.maxSequence);
         }
-        while (minSequence < maxSequence);
 
         return ranges;
     }
 
     @Getter
     public static class SequenceRange {
+        private String segmentId;
         private int min;
         private int max;
 
-        public SequenceRange(int min, int max) {
+        public SequenceRange(String segmentId, int min, int max) {
+            this.segmentId = segmentId;
             this.min = min;
             this.max = max;
         }
     }
 
+    @Data
+    public static class ProfiledSegment {
+        private String segmentId;
+        private long segmentStartTime;
+        private long segmentEndTime;
+        private int duration;
+
+        // snapshot sequence
+        private int minSequence;
+        private int maxSequence;
+    }
+
 }
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileAnalyzeSnapshotDAO.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileAnalyzeSnapshotDAO.java
index 5c00eacb5d..4822589710 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileAnalyzeSnapshotDAO.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileAnalyzeSnapshotDAO.java
@@ -20,9 +20,7 @@ package org.apache.skywalking.oap.server.tool.profile.exporter;
 
 import com.google.common.primitives.Ints;
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadSnapshot;
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
 
 import java.io.IOException;
@@ -39,7 +37,7 @@ public class ProfileAnalyzeSnapshotDAO implements IProfileThreadSnapshotQueryDAO
     }
 
     @Override
-    public List<BasicTrace> queryProfiledSegments(String taskId) throws IOException {
+    public List<String> queryProfiledSegmentIdList(String taskId) throws IOException {
         return null;
     }
 
@@ -61,11 +59,6 @@ public class ProfileAnalyzeSnapshotDAO implements IProfileThreadSnapshotQueryDAO
                 .collect(Collectors.toList());
     }
 
-    @Override
-    public SegmentRecord getProfiledSegment(String segmentId) throws IOException {
-        return null;
-    }
-
     private ProfileThreadSnapshotRecord buildFromSnapshot(ThreadSnapshot snapshot) {
         final ProfileThreadSnapshotRecord record = new ProfileThreadSnapshotRecord();
         record.setStackBinary(snapshot.getStack().toByteArray());
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileExportedAnalyze.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileExportedAnalyze.java
index 0c3688d8e7..fc5763095a 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileExportedAnalyze.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/ProfileExportedAnalyze.java
@@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadSnapshot;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
 import org.apache.skywalking.oap.server.core.profiling.trace.analyze.ProfileAnalyzer;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzation;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 import org.apache.skywalking.oap.server.core.query.type.ProfileStackElement;
@@ -33,7 +34,6 @@ import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
@@ -59,13 +59,13 @@ public class ProfileExportedAnalyze {
         final Span span = sameNameSpans.get(0);
 
         // build time ranges
-        final List<ProfileAnalyzeTimeRange> timeRanges = buildTimeRanges(basicInfo, span, includeChildren);
-        final List<ThreadSnapshot> snapshots = ProfileSnapshotDumper.parseFromFileWithTimeRange(snapshotFile, timeRanges);
+        final List<SegmentProfileAnalyzeQuery> queries = buildAnalyzeQueries(basicInfo, span, includeChildren);
+        final List<ThreadSnapshot> snapshots = ProfileSnapshotDumper.parseFromFileWithTimeRange(snapshotFile, queries);
         log.info("Total found snapshot count: {}", snapshots.size());
 
         // analyze and print
         final ProfileAnalyzer profileAnalyzer = new Analyzer(snapshots);
-        final ProfileAnalyzation analyzation = profileAnalyzer.analyze(null, timeRanges);
+        final ProfileAnalyzation analyzation = profileAnalyzer.analyze(queries);
         printAnalyzation(analyzation);
 
     }
@@ -100,12 +100,12 @@ public class ProfileExportedAnalyze {
         }
     }
 
-    private static List<ProfileAnalyzeTimeRange> buildTimeRanges(ProfiledBasicInfo basicInfo, Span currentSpan, boolean includeChildren) {
+    private static final List<SegmentProfileAnalyzeQuery> buildAnalyzeQueries(ProfiledBasicInfo basicInfo, Span currentSpan, boolean includeChildren) {
         if (includeChildren) {
             final ProfileAnalyzeTimeRange range = new ProfileAnalyzeTimeRange();
             range.setStart(currentSpan.getStartTime());
             range.setEnd(currentSpan.getEndTime());
-            return Collections.singletonList(range);
+            return List.of(SegmentProfileAnalyzeQuery.builder().timeRange(range).build());
         }
 
         // find children spans
@@ -137,7 +137,7 @@ public class ProfileExportedAnalyze {
             ranges.add(range);
         }
 
-        return ranges;
+        return ranges.stream().map(r -> SegmentProfileAnalyzeQuery.builder().timeRange(r).build()).collect(Collectors.toList());
     }
 
     private static class Analyzer extends ProfileAnalyzer {
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileExportSnapshotDAO.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileExportSnapshotDAO.java
index 343f7a7046..880bbca7a1 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileExportSnapshotDAO.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileExportSnapshotDAO.java
@@ -19,15 +19,12 @@
 package org.apache.skywalking.oap.server.tool.profile.exporter.test;
 
 import org.apache.skywalking.apm.network.language.profile.v3.ThreadStack;
-import org.apache.skywalking.oap.server.core.analysis.manual.segment.SegmentRecord;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileThreadSnapshotRecord;
-import org.apache.skywalking.oap.server.core.query.type.BasicTrace;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 public class ProfileExportSnapshotDAO implements IProfileThreadSnapshotQueryDAO {
@@ -39,13 +36,8 @@ public class ProfileExportSnapshotDAO implements IProfileThreadSnapshotQueryDAO
     }
 
     @Override
-    public List<BasicTrace> queryProfiledSegments(String taskId) throws IOException {
-        final BasicTrace basicTrace = new BasicTrace();
-        basicTrace.setSegmentId(exportedData.getSegmentId());
-        basicTrace.getTraceIds().add(exportedData.getTraceId());
-        basicTrace.setStart(exportedData.getSpans().get(0).getStart() + "");
-        basicTrace.setDuration(exportedData.getSpans().get(0).getEnd());
-        return Collections.singletonList(basicTrace);
+    public List<String> queryProfiledSegmentIdList(String taskId) throws IOException {
+        return Arrays.asList(exportedData.getSegmentId());
     }
 
     @Override
@@ -85,8 +77,4 @@ public class ProfileExportSnapshotDAO implements IProfileThreadSnapshotQueryDAO
         return records;
     }
 
-    @Override
-    public SegmentRecord getProfiledSegment(String segmentId) throws IOException {
-        return null;
-    }
 }
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileSnapshotExporterTest.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileSnapshotExporterTest.java
index ebf39d1b37..221062944e 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileSnapshotExporterTest.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileSnapshotExporterTest.java
@@ -26,6 +26,7 @@ import org.apache.skywalking.oap.server.core.config.ComponentLibraryCatalogServi
 import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService;
 import org.apache.skywalking.oap.server.core.profiling.trace.ProfileTaskQueryService;
 import org.apache.skywalking.oap.server.core.query.TraceQueryService;
+import org.apache.skywalking.oap.server.core.query.input.SegmentProfileAnalyzeQuery;
 import org.apache.skywalking.oap.server.core.query.type.ProfileAnalyzeTimeRange;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
 import org.apache.skywalking.oap.server.core.storage.profiling.trace.IProfileThreadSnapshotQueryDAO;
@@ -49,7 +50,6 @@ import org.yaml.snakeyaml.Yaml;
 import java.io.File;
 import java.io.IOException;
 import java.io.Reader;
-import java.util.Collections;
 import java.util.List;
 
 @ExtendWith(MockitoExtension.class)
@@ -107,7 +107,7 @@ public class ProfileSnapshotExporterTest {
         timeRange.setStart(exportedData.getSpans().get(0).getStart());
         timeRange.setEnd(exportedData.getSpans().get(0).getEnd());
         final List<ThreadSnapshot> threadSnapshots = ProfileSnapshotDumper.parseFromFileWithTimeRange(
-            writeFile, Collections.singletonList(timeRange));
+            writeFile, List.of(SegmentProfileAnalyzeQuery.builder().timeRange(timeRange).build()));
 
         Assertions.assertEquals(threadSnapshots.size(), exportedData.getSnapshots().size());
         for (int i = 0; i < threadSnapshots.size(); i++) {
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileTraceDAO.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileTraceDAO.java
index 62d19cead9..2c5639c2a5 100644
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileTraceDAO.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-bootstrap/src/test/java/org/apache/skywalking/oap/server/tool/profile/exporter/test/ProfileTraceDAO.java
@@ -79,6 +79,35 @@ public class ProfileTraceDAO implements ITraceQueryDAO {
         return segments;
     }
 
+    @Override
+    public List<SegmentRecord> queryBySegmentIdList(List<String> segmentIdList) throws IOException {
+        final ArrayList<SegmentRecord> segments = new ArrayList<>();
+        final SegmentRecord segment = new SegmentRecord();
+        segments.add(segment);
+
+        final SegmentObject.Builder segmentBuilder = SegmentObject.newBuilder();
+        segmentBuilder.setTraceSegmentId(exportData.getSegmentId());
+        for (ExportedData.Span span : exportData.getSpans()) {
+            segmentBuilder.addSpans(SpanObject.newBuilder()
+                .setOperationName(span.getOperation())
+                .setStartTime(span.getStart())
+                .setEndTime(span.getEnd())
+                .setSpanId(span.getId())
+                .setParentSpanId(span.getParentId()));
+        }
+        segment.setDataBinary(segmentBuilder.build().toByteArray());
+        segment.setTraceId(exportData.getTraceId());
+        segment.setServiceId("service");
+        segment.setSegmentId(exportData.getSegmentId());
+        segment.setLatency(exportData.getLimit() * 10);
+        return segments;
+    }
+
+    @Override
+    public List<SegmentRecord> queryByTraceIdWithInstanceId(List<String> traceIdList, List<String> instanceIdList) throws IOException {
+        return null;
+    }
+
     @Override
     public List<Span> doFlexibleTraceQuery(String traceId) throws IOException {
         return null;
diff --git a/test/e2e-v2/cases/profiling/trace/expected/profile-segment-detail.yml b/test/e2e-v2/cases/profiling/trace/expected/profile-segment-detail.yml
deleted file mode 100644
index 7b2236357c..0000000000
--- a/test/e2e-v2/cases/profiling/trace/expected/profile-segment-detail.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-spans:
-{{- contains .spans }}
-- spanid: 0
-  parentspanid: -1
-  servicecode: e2e-service-provider
-  serviceinstancename: ""
-  starttime: {{ gt .starttime 0 }}
-  endtime: {{ gt .endtime 0 }}
-  endpointname: POST:/profile/{name}
-  type: Entry
-  peer: ""
-  component: SpringMVC
-  iserror: false
-  layer: Http
-  tags:
-    {{- contains .tags }}
-    - key: url
-      value: {{ notEmpty .value }}
-    - key: http.method
-      value: POST
-    - key: http.params
-      value: "e2e=[true]"
-    {{- end }}
-  logs: []
-{{- end }}
diff --git a/test/e2e-v2/cases/profiling/trace/expected/profile-segment-list.yml b/test/e2e-v2/cases/profiling/trace/expected/profile-segment-list.yml
index a92304683f..5c45b8e704 100644
--- a/test/e2e-v2/cases/profiling/trace/expected/profile-segment-list.yml
+++ b/test/e2e-v2/cases/profiling/trace/expected/profile-segment-list.yml
@@ -14,14 +14,39 @@
 # limitations under the License.
 
 {{- contains . }}
-- segmentid: {{ notEmpty .segmentid }}
+- traceid: {{ notEmpty .traceid }}
+  instanceid: {{ notEmpty .instanceid }}
+  instancename: provider1
   endpointnames:
     - POST:/profile/{name}
   duration: {{ gt .duration 0 }}
   start: "{{ notEmpty .start }}"
-  iserror: false
-  traceids:
-  {{- contains .traceids }}
-    - {{ notEmpty . }}
-  {{- end }}
+  spans:
+  {{- contains .spans}}
+  - spanid: {{ ge .spanid 0 }}
+    parentspanid: {{ .parentspanid }}
+    segmentid: {{ notEmpty .segmentid }}
+    refs: []
+    servicecode: e2e-service-provider
+    serviceinstancename: provider1
+    starttime: {{ gt .starttime 0 }}
+    endtime: {{ gt .endtime 0 }}
+    endpointname: POST:/profile/{name}
+    type: Entry
+    peer: ""
+    component: SpringMVC
+    iserror: false
+    layer: Http
+    tags:
+      {{- contains .tags }}
+      - key: url
+        value: {{ notEmpty .value }}
+      - key: http.method
+        value: POST
+      - key: http.params
+        value: "e2e=[true]"
+      {{- end }}
+    logs: []
+    profiled: true
+  {{- end}}
 {{- end }}
diff --git a/test/e2e-v2/cases/profiling/trace/profiling-cases.yaml b/test/e2e-v2/cases/profiling/trace/profiling-cases.yaml
index 7a395c2a01..69fc65576b 100644
--- a/test/e2e-v2/cases/profiling/trace/profiling-cases.yaml
+++ b/test/e2e-v2/cases/profiling/trace/profiling-cases.yaml
@@ -55,22 +55,22 @@
           swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/profile/{name} | yq e '.[0].id' - \
         )
       expected: expected/profile-segment-list.yml
-    # profiled segment detail
-    - query: |
-        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace profiled-segment --segment-id=$( \
-          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
-            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/profile/{name} | yq e '.[0].id' - \
-          ) | yq e '.[0].segmentid' - \
-        )
-      expected: expected/profile-segment-detail.yml
     # query profiled segment analyze
     - query: |
         segmentid=$( \
           swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
             swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/profile/{name} | yq e '.[0].id' - \
-          ) | yq e '.[0].segmentid' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .segmentid' - \
+        );
+        start=$(
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
+            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/profile/{name} | yq e '.[0].id' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .starttime' - \
+        );
+        end=$(
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
+            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/profile/{name} | yq e '.[0].id' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .endtime' - \
         );
-        start=$(swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace profiled-segment --segment-id=$segmentid | yq e '.spans[] | select(.spanid == 0).starttime' -);
-        end=$(swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace profiled-segment --segment-id=$segmentid | yq e '.spans[] | select(.spanid == 0).endtime' -);
-        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace analysis --segment-id=$segmentid --time-ranges=$(echo $start"-"$end)
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace analysis --segment-ids=$segmentid --time-ranges=$(echo $start"-"$end)
       expected: expected/profile-segment-analyze.yml
diff --git a/test/e2e-v2/cases/satellite/native-protocols/e2e.yaml b/test/e2e-v2/cases/satellite/native-protocols/e2e.yaml
index f11afee4e1..9d99188180 100644
--- a/test/e2e-v2/cases/satellite/native-protocols/e2e.yaml
+++ b/test/e2e-v2/cases/satellite/native-protocols/e2e.yaml
@@ -115,24 +115,25 @@ verify:
       expected: expected/profile-segment-list.yml
     # native profile: query profiled segment
     - query: |
-        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace profiled-segment --segment-id=$( \
+        segmentid=$( \
           swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
             swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/info | yq e '.[0].id' - \
-          ) | yq e '.[0].segmentid' - \
-        )
-      expected: expected/profile-segment-detail.yml
-    # native profile: query profiled segment
-    - query: |
-        segmentid=$( \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .segmentid' - \
+        );
+        start=$(
           swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
             swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/info | yq e '.[0].id' - \
-          ) | yq e '.[0].segmentid' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .starttime' - \
         );
-        start=$(swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace profiled-segment --segment-id=$segmentid|yq e '.spans.[0].starttime' -);
-        end=$(swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace profiled-segment --segment-id=$segmentid|yq e '.spans.[0].endtime' -);
-        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace analysis --segment-id=$segmentid --time-ranges=$(echo $start"-"$end)
+        end=$(
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace segment-list --task-id=$( \
+            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace list --service-name=e2e-service-provider --endpoint-name=POST:/info | yq e '.[0].id' - \
+          ) | yq e '.[0].spans.[] | select(.spanid == 0) | .endtime' - \
+        );
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql profiling trace analysis --segment-ids=$segmentid --time-ranges=$(echo $start"-"$end)
       expected: expected/profile-segment-analyze.yml
 
+
     # native CDS: using etcdctl to update trace span limit, "/users" should have more than one span because it need DB save
     - query: |
         etcdctl --endpoints http://${etcd_host}:${etcd_2379}/ put /skywalking/configuration-discovery.default.agentConfigurations 'configurations:
diff --git a/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-detail.yml b/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-detail.yml
deleted file mode 100644
index 43f5b6b539..0000000000
--- a/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-detail.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-spans:
-{{- contains .spans }}
-- spanid: 0
-  parentspanid: -1
-  servicecode: e2e-service-provider
-  serviceinstancename: ""
-  starttime: {{ gt .starttime 0 }}
-  endtime: {{ gt .endtime 0 }}
-  endpointname: POST:/info
-  type: Entry
-  peer: ""
-  component: Tomcat
-  iserror: false
-  layer: Http
-  tags:
-    {{- contains .tags }}
-    - key: url
-      value: {{ notEmpty .value }}
-    - key: http.method
-      value: POST
-    {{- end }}
-  logs: []
-{{- end }}
diff --git a/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-list.yml b/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-list.yml
index b65f72a46d..9dfacc3d74 100644
--- a/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-list.yml
+++ b/test/e2e-v2/cases/satellite/native-protocols/expected/profile-segment-list.yml
@@ -13,15 +13,38 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-{{- contains . }}
-- segmentid: {{ notEmpty .segmentid }}
+  {{- contains . }}
+- traceid: {{ notEmpty .traceid }}
+  instanceid: {{ notEmpty .instanceid }}
+  instancename: provider1
   endpointnames:
     - POST:/info
   duration: {{ gt .duration 0 }}
   start: "{{ notEmpty .start }}"
-  iserror: false
-  traceids:
-  {{- contains .traceids }}
-    - {{ notEmpty . }}
+  spans:
+  {{- contains .spans}}
+  - spanid: {{ ge .spanid 0 }}
+    parentspanid: {{ .parentspanid }}
+    segmentid: {{ notEmpty .segmentid }}
+    refs: []
+    servicecode: e2e-service-provider
+    serviceinstancename: provider1
+    starttime: {{ gt .starttime 0 }}
+    endtime: {{ gt .endtime 0 }}
+    endpointname: POST:/info
+    type: Entry
+    peer: ""
+    component: Tomcat
+    iserror: false
+    layer: Http
+    tags:
+      {{- contains .tags }}
+      - key: url
+        value: {{ notEmpty .value }}
+      - key: http.method
+        value: POST
+      {{- end }}
+    logs: []
+    profiled: true
+  {{- end}}
   {{- end }}
-{{- end }}
diff --git a/test/e2e-v2/script/env b/test/e2e-v2/script/env
index 506a9a6d7d..074f84a380 100644
--- a/test/e2e-v2/script/env
+++ b/test/e2e-v2/script/env
@@ -25,4 +25,4 @@ SW_KUBERNETES_COMMIT_SHA=b670c41d94a82ddefcf466d54bab5c492d88d772
 SW_ROVER_COMMIT=fc8d074c6d34ecfee585a7097cbd5aef1ca680a5
 SW_BANYANDB_COMMIT=adbd3e87df7f84e5d1904fcf40476d2e81842058
 
-SW_CTL_COMMIT=9aa1e75af41407a8b85106cc6bc711ab937f6fb5
\ No newline at end of file
+SW_CTL_COMMIT=f3eed66ee2ff330e3218fdc995b6f9952901e37c
\ No newline at end of file