文档

查询Profile

更新时间:

本文介绍云数据库 SelectDB 版的Profile功能和使用方式,为查询性能分析提供参考和依据。

打开查询Profile

通过如下命令打开会话变量is_report_success

SET enable_profile=true;

打开查询Profile后,执行查询时,SelectDB会产生该查询的一个Profile。Profile包含了一个查询在各个节点上的具体执行情况,有助于分析查询瓶颈。

查看查询Profile

查询执行完成后,通过如下命令获取Profile列表。这个命令会列出当前保存的所有Profile,每行对应一个查询。您可以选择需要查看的Profile对应的QueryId,查看Profile具体情况。

SHOW QUERY PROFILE "/"\G
*************************** 1. row ***************************
   QueryId: c257c52f93e149ee-ace8ac14e8c9fef9
      User: root
 DefaultDb: default_cluster:db1
       SQL: select tbl1.k1, sum(tbl1.k2) from tbl1 join tbl2 on tbl1.k1 = tbl2.k1 group by tbl1.k1 order by tbl1.k1
 QueryType: Query
 StartTime: 2021-04-08 11:30:50
   EndTime: 2021-04-08 11:30:50
 TotalTime: 9ms
QueryState: EOF

可以通过以下3个步骤,逐步排查一个SQL的性能瓶颈。

  1. 查看整体执行计划树。

    这一步主要用于从整体分析执行计划,并查看每个Fragment的执行耗时。例如查询Profile对应的QueryId。查询结果中每个节点都标注了自己所属的Fragment,并且在每个Fragment的Sender节点标注了该Fragment的执行耗时。这个耗时是Fragment下所有执行单元的执行耗时中最长的一个。该统计报告有助于从整体角度发现最耗时的Fragment,查询示例如下。

    SHOW QUERY PROFILE "/c257c52f93e149ee-ace8ac14e8c9fef9"\G
    *************************** 1. row ***************************
    Fragments:
                 ┌──────────────────────┐
                 │[-1: DataBufferSender]│
                 │Fragment: 0           │
                 │MaxActiveTime: 6.626ms│
                 └──────────────────────┘
                             │
                   ┌──────────────────┐
                   │[9: EXCHANGE_NODE]│
                   │Fragment: 0       │
                   └──────────────────┘
                             │
                 ┌──────────────────────┐
                 │[9: DataStreamSender] │
                 │Fragment: 1           │
                 │MaxActiveTime: 5.449ms│
                 └──────────────────────┘
                             │
                     ┌──────────────┐
                     │[4: SORT_NODE]│
                     │Fragment: 1   │
                     └──────────────┘
                            ┌┘
                 ┌─────────────────────┐
                 │[8: AGGREGATION_NODE]│
                 │Fragment: 1          │
                 └─────────────────────┘
                            └┐
                   ┌──────────────────┐
                   │[7: EXCHANGE_NODE]│
                   │Fragment: 1       │
                   └──────────────────┘
                             │
                 ┌──────────────────────┐
                 │[7: DataStreamSender] │
                 │Fragment: 2           │
                 │MaxActiveTime: 3.505ms│
                 └──────────────────────┘
                            ┌┘
                 ┌─────────────────────┐
                 │[3: AGGREGATION_NODE]│
                 │Fragment: 2          │
                 └─────────────────────┘
                            │
                  ┌───────────────────┐
                  │[2: HASH_JOIN_NODE]│
                  │Fragment: 2        │
                  └───────────────────┘
               ┌────────────┴────────────┐
     ┌──────────────────┐      ┌──────────────────┐
     │[5: EXCHANGE_NODE]│      │[6: EXCHANGE_NODE]│
     │Fragment: 2       │      │Fragment: 2       │
     └──────────────────┘      └──────────────────┘
               │                         │
    ┌─────────────────────┐ ┌────────────────────────┐
    │[5: DataStreamSender]│ │[6: DataStreamSender]   │
    │Fragment: 4          │ │Fragment: 3             │
    │MaxActiveTime: 1.87ms│ │MaxActiveTime: 636.767us│
    └─────────────────────┘ └────────────────────────┘
               │                        ┌┘
     ┌───────────────────┐    ┌───────────────────┐
     │[0: OLAP_SCAN_NODE]│    │[1: OLAP_SCAN_NODE]│
     │Fragment: 4        │    │Fragment: 3        │
     └───────────────────┘    └───────────────────┘
               │                        │
        ┌─────────────┐          ┌─────────────┐
        │[OlapScanner]│          │[OlapScanner]│
        │Fragment: 4  │          │Fragment: 3  │
        └─────────────┘          └─────────────┘
               │                        │
      ┌─────────────────┐      ┌─────────────────┐
      │[SegmentIterator]│      │[SegmentIterator]│
      │Fragment: 4      │      │Fragment: 3      │
      └─────────────────┘      └─────────────────┘
     
    1 row in set (0.02 sec)
  2. 查看具体Fragment下的执行单元列表。

    例如上述示例中Fragment1耗时最长,您可以继续查看Fragment1的执行单元列表。查询中Fragment 1上所有的3个执行单元所在的执行节点和耗时,查询示例如下。

    SHOW QUERY PROFILE "/c257c52f93e149ee-ace8ac14e8c9fef9/1";
    +-----------------------------------+-------------------+------------+
    | Instances                         | Host              | ActiveTime |
    +-----------------------------------+-------------------+------------+
    | c257c52f93e149ee-ace8ac14e8c9ff03 | 10.200.00.01:9060 | 5.449ms    |
    | c257c52f93e149ee-ace8ac14e8c9ff05 | 10.200.00.02:9060 | 5.367ms    |
    | c257c52f93e149ee-ace8ac14e8c9ff04 | 10.200.00.03:9060 | 5.358ms    |
    +-----------------------------------+-------------------+------------+ 
  3. 查看具体执行单元。

    您可以继续查看某一个具体的执行单元上各个算子的详细Profile。例如查询Fragment1中,执行单元c257c52f93e149ee-ace8ac14e8c9ff03的各个算子的具体Profile,查询示例如下。

    SHOW QUERY PROFILE "/c257c52f93e149ee-ace8ac14e8c9fef9/1/c257c52f93e149ee-ace8ac14e8c9ff03"\G
    *************************** 1. row ***************************
    Instance:
     ┌───────────────────────────────────────┐
     │[9: DataStreamSender]                  │
     │(Active: 37.222us, non-child: 0.40)    │
     │  - Counters:                          │
     │      - BytesSent: 0.00                │
     │      - IgnoreRows: 0                  │
     │      - OverallThroughput: 0.0 /sec    │
     │      - PeakMemoryUsage: 8.00 KB       │
     │      - SerializeBatchTime: 0ns        │
     │      - UncompressedRowBatchSize: 0.00 │
     └───────────────────────────────────────┘
                         └┐
                          │
        ┌──────────────────────────────────┐
        │[4: SORT_NODE]                    │
        │(Active: 5.421ms, non-child: 0.71)│
        │  - Counters:                     │
        │      - PeakMemoryUsage: 12.00 KB │
        │      - RowsReturned: 0           │
        │      - RowsReturnedRate: 0       │
        └──────────────────────────────────┘
                         ┌┘
                         │
       ┌───────────────────────────────────┐
       │[8: AGGREGATION_NODE]              │
       │(Active: 5.355ms, non-child: 10.68)│
       │  - Counters:                      │
       │      - BuildTime: 3.701us         │
       │      - GetResultsTime: 0ns        │
       │      - HTResize: 0                │
       │      - HTResizeTime: 1.211us      │
       │      - HashBuckets: 0             │
       │      - HashCollisions: 0          │
       │      - HashFailedProbe: 0         │
       │      - HashFilledBuckets: 0       │
       │      - HashProbe: 0               │
       │      - HashTravelLength: 0        │
       │      - LargestPartitionPercent: 0 │
       │      - MaxPartitionLevel: 0       │
       │      - NumRepartitions: 0         │
       │      - PartitionsCreated: 16      │
       │      - PeakMemoryUsage: 34.02 MB  │
       │      - RowsProcessed: 0           │
       │      - RowsRepartitioned: 0       │
       │      - RowsReturned: 0            │
       │      - RowsReturnedRate: 0        │
       │      - SpilledPartitions: 0       │
       └───────────────────────────────────┘
                         └┐
                          │
    ┌──────────────────────────────────────────┐
    │[7: EXCHANGE_NODE]                        │
    │(Active: 4.360ms, non-child: 46.84)       │
    │  - Counters:                             │
    │      - BytesReceived: 0.00               │
    │      - ConvertRowBatchTime: 387ns        │
    │      - DataArrivalWaitTime: 4.357ms      │
    │      - DeserializeRowBatchTimer: 0ns     │
    │      - FirstBatchArrivalWaitTime: 4.356ms│
    │      - PeakMemoryUsage: 0.00             │
    │      - RowsReturned: 0                   │
    │      - RowsReturnedRate: 0               │
    │      - SendersBlockedTotalTimer(*): 0ns  │
    └──────────────────────────────────────────┘

导出查询Profile

在SelectDB 3.0.4版本后,您可以导出查询Profile供进一步分析,操作如下。

  1. 打开查询 Profile。

    SET enable_profile=true;
  2. 执行查询。

    -- 发送SQL请求,此时查询的Profile信息会被记录
    SELECT ... FROM ...
  3. 查看查询的query_id

    SHOW QUERY PROFILE "/";
    +-----------------------------------+-----------+---------------------+---------------------+-------+------------+-------+------------------------------------+-------------------------------+
    | Profile ID                        | Task Type | Start Time          | End Time            | Total | Task State | User  | Default Db                         | Sql Statement                 |
    +-----------------------------------+-----------+---------------------+---------------------+-------+------------+-------+------------------------------------+-------------------------------+
    | b9c9ba063d9d4365-97878361371e757a | QUERY     | 2024-02-07 17:40:04 | 2024-02-07 17:40:04 | 32ms  | EOF        | admin | default_cluster:information_schema | select * from user_privileges |
    | 8800c306137e4072-9bb1ed419f4ac9f2 | QUERY     | 2024-02-07 17:40:00 | 2024-02-07 17:40:00 | 3ms   | ERR        | admin | default_cluster:information_schema | select * from user_priveleges |
    | e2efdd1a996c4de2-ab939ad49b409990 | QUERY     | 2024-02-07 17:39:51 | 2024-02-07 17:39:51 | 13ms  | EOF        | admin |                                    | SELECT DATABASE()             |
    +-----------------------------------+-----------+---------------------+---------------------+-------+------------+-------+------------------------------------+-------------------------------+
  4. 根据query_id通过curl使用重定向符号将信息输出到文件。

    curl -u'<userName>:<userPassword>' "http://<selectdbAddress>:<httpPort>/api/profile?query_id=<query_id>" 
    
    # 可使用重定向符号输出到文件
    curl -u'<userName>:<userPassword>' "http://<selectdbAddress>:{httpPort>/api/profile?query_id=<query_id>" > test.txt
    参数说明

    参数名称

    参数说明

    userName

    SelectDB用户名。

    userPassword

    SelectDB密码。

    selectdbAddress

    SelectDB连接地址。

    httpPort

    SelectDB的HTTP端口,默认为8080。

    query_id

    查询语句的Profile ID。

  5. (可选)若使用重定向符号保存为文件,推荐进行格式化转换,以方便查看。

    sudo sed -r 's/\\n/\n/g' res.txt | sed -r 's/\\t/\t/g' > new.tx

Profile参数解析

以下对BE端收集的统计信息参数进行说明。

Fragment

参数名称

参数说明

AverageThreadTokens

执行Fragment使用线程数目,不包含线程池的使用情况。

Buffer Pool PeakReservation

Buffer Pool使用的内存的峰值。

MemoryLimit

查询时的内存限制。

PeakMemoryUsage

整个执行单元在查询时内存使用的峰值。

RowsProduced

处理列的行数。

BlockMgr

参数名称

参数说明

BlocksCreated

BlockMgr创建的Blocks数目。

BlocksRecycled

重用的Blocks数目。

BytesWritten

总的落盘写数据量。

MaxBlockSize

单个Block的大小。

TotalReadBlockTime

读Block的总耗时。

DataStreamSender

参数名称

参数说明

BytesSent

发送的总数据量 = 接受者×发送数据量。

IgnoreRows

过滤的行数。

LocalBytesSent

记录数据在Exchange过程中,本机节点的自发自收数据量。

OverallThroughput

总的吞吐量 = BytesSent/时间。

SerializeBatchTime

发送数据序列化消耗的时间。

UncompressedRowBatchSize

发送数据压缩前的RowBatch的大小。

ODBC_TABLE_SINK

参数名称

参数说明

NumSentRows

写入外表的总行数。

TupleConvertTime

发送数据序列化为Insert语句的耗时。

ResultSendTime

通过ODBC Driver写入的耗时。

EXCHANGE_NODE

参数名称

参数说明

BytesReceived

通过网络接收的数据量大小。

MergeGetNext

当下层节点存在排序时,会在EXCHANGE NODE进行统一的归并排序,输出有序结果。该指标记录了Merge排序的总耗时,包含了MergeGetNextBatch耗时。

MergeGetNextBatch

Merge节点取数据的耗时。如果为单层Merge排序,则取数据的对象为网络队列;若为多层Merge排序,则取数据对象为Child Merger。

ChildMergeGetNext

当下层的发送数据的Sender过多时,单线程的Merge会成为性能瓶颈,SelectDB会启动多个Child Merge线程并行归并排序。该数值记录了Child Merge的排序耗时,是多个线程的累加值。

ChildMergeGetNextBatch

Child Merge节点从取数据的耗时,如果耗时过大,说明下层的数据发送节点可能存在瓶颈。

DataArrivalWaitTime

等待Sender发送数据的总时间。

FirstBatchArrivalWaitTime

等待第一个Batch从Sender获取的时间。

DeserializeRowBatchTimer

反序列化网络数据的耗时。

SendersBlockedTotalTimer(*)

DataStreamRecv的队列的内存被打满,Sender端等待的耗时。

ConvertRowBatchTime

接收数据转为RowBatch的耗时。

RowsReturned

接收行的数目。

RowsReturnedRate

接收行的速率。

SORT_NODE

参数名称

参数说明

InMemorySortTime

内存中排序的耗时。

InitialRunsCreated

初始化排序的趟数(若为内存内排序,则该数为1)。

SortDataSize

总的排序数据量。

MergeGetNext

MergeSort从多个sort_run获取下一个Batch的耗时(仅在落盘时计时)。

MergeGetNextBatch

MergeSort提取下一个sort_run的Batch的耗时(仅在落盘时计时)。

TotalMergesPerformed

进行外排Merge的次数。

AGGREGATION_NODE

参数名称

参数说明

PartitionsCreated

聚合查询拆分成Partition的个数。

GetResultsTime

从各个partition之中获取聚合结果的时间。

HTResizeTime

HashTable进行resize消耗的时间。

HTResize

HashTable进行resize的次数。

HashBuckets

HashTable中Buckets的个数。

HashBucketsWithDuplicate

HashTable有DuplicateNode的Buckets的个数。

HashCollisions

HashTable产生哈希冲突的次数。

HashDuplicateNodes

HashTable出现Buckets相同DuplicateNode的个数。

HashFailedProbe

HashTable Probe操作失败的次数。

HashFilledBuckets

HashTable填入数据的Buckets数目。

HashProbe

HashTable查询的次数。

HashTravelLength

HashTable查询时移动的步数。

HASH_JOIN_NODE

参数名称

参数说明

ExecOption

对右子节点构造HashTable的方式(同步or异步),Join中右子节点可能是表或子查询,左子节点同理。

BuildBuckets

HashTable中Buckets的个数。

BuildRows

HashTable的行数。

BuildTime

构造HashTable的耗时。

LoadFactor

HashTable的负载因子(即非空Buckets的数量)。

ProbeRows

遍历左子节点进行Hash Probe的行数。

ProbeTime

遍历左子节点进行Hash Probe的耗时,不包括对左子节点RowBatch调用GetNext的耗时。

PushDownComputeTime

谓词下推条件计算耗时。

PushDownTime

谓词下推的总耗时,Join时对满足要求的右子节点,转为左子节点的in查询。

CROSS_JOIN_NODE

参数名称

参数说明

ExecOption

对右子节点构造RowBatchList的方式(同步or异步)。

BuildRows

RowBatchList的行数(即右子节点的行数)。

BuildTime

构造RowBatchList的耗时。

LeftChildRows

左子节点的行数。

LeftChildTime

遍历左子节点和右子节点求笛卡尔积的耗时,不包括对左子节点RowBatch调用GetNext的耗时。

UNION_NODE

参数名称

参数说明

MaterializeExprsEvaluateTime

Union两端字段类型不一致时,类型转换表达式计算及物化结果的耗时。

ANALYTIC_EVAL_NODE

参数名称

参数说明

EvaluationTime

分析函数(窗口函数)计算总耗时。

GetNewBlockTime

初始化时申请一个新的Block的耗时,Block用来缓存Rows窗口或整个分区,用于分析函数计算。

PinTime

后续申请新的Block或将写入磁盘的Block重新读取回内存的耗时。

UnpinTime

对暂不需要使用的Block或当前操作符内存压力大时,将Block的数据刷入磁盘的耗时。

OLAP_SCAN_NODE

OLAP_SCAN_NODE节点负责具体的数据扫描任务。一个OLAP_SCAN_NODE会生成一个或多个OlapScanner。每个Scanner线程负责扫描部分数据。

查询中的部分或全部谓词条件会推送给OLAP_SCAN_NODE。这些谓词条件中一部分会继续下推给存储引擎,以便利用存储引擎的索引进行数据过滤。另一部分会保留在OLAP_SCAN_NODE中,用于过滤从存储引擎中返回的数据。

OLAP_SCAN_NODE节点的Profile通常用于分析数据扫描的效率,依据调用关系分为OLAP_SCAN_NODEOlapScannerSegmentIterator三层。

一个典型的OLAP_SCAN_NODE节点的Profile如下。部分指标会因存储格式的不同(V1或V2)而有不同含义。

OLAP_SCAN_NODE (id=0):(Active: 1.2ms, % non-child: 0.00%)
  - BytesRead: 265.00 B                 # 从数据文件中读取到的数据量。假设读取到了是10个32位整型,则数据量为 10 * 4B = 40 Bytes。这个数据仅表示数据在内存中全展开的大小,并不代表实际的 IO 大小。 
  - NumDiskAccess: 1                    # 该 ScanNode 节点涉及到的磁盘数量。
  - NumScanners: 20                     # 该 ScanNode 生成的 Scanner 数量。
  - PeakMemoryUsage: 0.00               # 查询时内存使用的峰值,暂未使用
  - RowsRead: 7                         # 从存储引擎返回到 Scanner 的行数,不包括经 Scanner 过滤的行数。
  - RowsReturned: 7                     # 从 ScanNode 返回给上层节点的行数。
  - RowsReturnedRate: 6.979K /sec       # RowsReturned/ActiveTime
  - TabletCount : 20                    # 该 ScanNode 涉及的 Tablet 数量。
  - TotalReadThroughput: 74.70 KB/sec   # BytesRead除以该节点运行的总时间(从Open到Close),对于IO受限的查询,接近磁盘的总吞吐量。
  - ScannerBatchWaitTime: 426.886us     # 用于统计transfer 线程等待scaner 线程返回rowbatch的时间。
  - ScannerWorkerWaitTime: 17.745us     # 用于统计scanner thread 等待线程池中可用工作线程的时间。
  OlapScanner:
    - BlockConvertTime: 8.941us         # 将向量化Block转换为行结构的 RowBlock 的耗时。向量化 Block 在 V1 中为 VectorizedRowBatch,V2中为 RowBlockV2。
    - BlockFetchTime: 468.974us         # Rowset Reader 获取 Block 的时间。
    - ReaderInitTime: 5.475ms           # OlapScanner 初始化 Reader 的时间。V1 中包括组建 MergeHeap 的时间。V2 中包括生成各级 Iterator 并读取第一组Block的时间。
    - RowsDelFiltered: 0                # 包括根据 Tablet 中存在的 Delete 信息过滤掉的行数,以及 unique key 模型下对被标记的删除行过滤的行数。
    - RowsPushedCondFiltered: 0         # 根据传递下推的谓词过滤掉的条件,比如 Join 计算中从 BuildTable 传递给 ProbeTable 的条件。该数值不准确,因为如果过滤效果差,就不再过滤了。
    - ScanTime: 39.24us                 # 从 ScanNode 返回给上层节点的时间。
    - ShowHintsTime_V1: 0ns             # V2 中无意义。V1 中读取部分数据来进行 ScanRange 的切分。
    SegmentIterator:
      - BitmapIndexFilterTimer: 779ns   # 利用 bitmap 索引过滤数据的耗时。
      - BlockLoadTime: 415.925us        # SegmentReader(V1) 或 SegmentIterator(V2) 获取 block 的时间。
      - BlockSeekCount: 12              # 读取 Segment 时进行 block seek 的次数。
      - BlockSeekTime: 222.556us        # 读取 Segment 时进行 block seek 的耗时。
      - BlocksLoad: 6                   # 读取 Block 的数量
      - CachedPagesNum: 30              # 仅 V2 中,当开启 PageCache 后,命中 Cache 的 Page 数量。
      - CompressedBytesRead: 0.00       # V1 中,从文件中读取的解压前的数据大小。V2 中,读取到的没有命中 PageCache 的 Page 的压缩前的大小。
      - DecompressorTimer: 0ns          # 数据解压耗时。
      - IOTimer: 0ns                    # 实际从操作系统读取数据的 IO 时间。
      - IndexLoadTime_V1: 0ns           # 仅 V1 中,读取 Index Stream 的耗时。
      - NumSegmentFiltered: 0           # 在生成 Segment Iterator 时,通过列统计信息和查询条件,完全过滤掉的 Segment 数量。
      - NumSegmentTotal: 6              # 查询涉及的所有 Segment 数量。
      - RawRowsRead: 7                  # 存储引擎中读取的原始行数。详情见下文。
      - RowsBitmapIndexFiltered: 0      # 仅 V2 中,通过 Bitmap 索引过滤掉的行数。
      - RowsBloomFilterFiltered: 0      # 仅 V2 中,通过 BloomFilter 索引过滤掉的行数。
      - RowsKeyRangeFiltered: 0         # 仅 V2 中,通过 SortkeyIndex 索引过滤掉的行数。
      - RowsStatsFiltered: 0            # V2 中,通过 ZoneMap 索引过滤掉的行数,包含删除条件。V1 中还包含通过 BloomFilter 过滤掉的行数。
      - RowsConditionsFiltered: 0       # 仅 V2 中,通过各种列索引过滤掉的行数。
      - RowsVectorPredFiltered: 0       # 通过向量化条件过滤操作过滤掉的行数。
      - TotalPagesNum: 30               # 仅 V2 中,读取的总 Page 数量。
      - UncompressedBytesRead: 0.00     # V1 中为读取的数据文件解压后的大小(如果文件无需解压,则直接统计文件大小)。V2 中,仅统计未命中 PageCache 的 Page 解压后的大小(如果Page无需解压,直接统计Page大小)
      - VectorPredEvalTime: 0ns         # 向量化条件过滤操作的耗时。
      - ShortPredEvalTime: 0ns          # 短路谓词过滤操作的耗时。
      - PredColumnReadTime: 0ns         # 谓词列读取的耗时。
      - LazyReadTime: 0ns               # 非谓词列读取的耗时。
      - OutputColumnTime: 0ns           # 物化列的耗时。

通过Profile中数据行数相关指标可以推断谓词条件下推和索引使用情况。如下对Segment V2格式数据读取流程中的Profile进行说明。Segment V1格式中,这些指标的含义略有不同。

Init阶段

  1. 当读取一个V2格式的Segment时,若查询存在key_ranges(前缀key组成的查询范围),首先通过SortkeyIndex索引过滤数据,过滤的行数记录在RowsKeyRangeFiltered

  2. 对查询条件中含有Bitmap索引的列,使用Bitmap索引进行精确过滤,过滤的行数记录在RowsBitmapIndexFiltered

  3. 按查询条件中的等值(eq,in,is)条件,使用BloomFilter索引过滤数据,记录在RowsBloomFilterFilteredRowsBloomFilterFiltered的值是Segment的总行数(而不是Bitmap索引过滤后的行数)和经过BloomFilter过滤后剩余行数的差值,因此BloomFilter过滤的数据可能会和Bitmap过滤的数据有重叠。

  4. 按查询条件和删除条件,使用ZoneMap索引过滤数据,记录在RowsStatsFiltered

  5. RowsConditionsFiltered是各种索引过滤的行数,包含了RowsBloomFilterFilteredRowsStatsFiltered的值。

Next阶段

  • Next阶段删除条件过滤的行数,记录在RowsDelFiltered。因该删除条件实际过滤的行数,分别记录在RowsStatsFilteredRowsDelFiltered中。

  • RawRowsRead是经过上述过滤后,最终需要读取的行数。

  • RowsRead是最终返回给Scanner的行数。RowsRead通常小于RawRowsRead,这是因为从存储引擎返回到Scanner可能会经过一次数据聚合。如果RawRowsReadRowsRead差距较大,则说明大量的行被聚合,而聚合可能比较耗时。

  • RowsReturned是ScanNode最终返回给上层节点的行数。RowsReturned通常也会小于RowsRead。因为在Scanner上会有一些没有下推给存储引擎的谓词条件,这通常意味着一次过滤。如果RowsReadRowsReturned差距较大,则意味着Scanner中进行了大批量的行过滤。这说明很多选择度高的谓词条件并没有推送给存储引擎,而在Scanner中的过滤效率会比在存储引擎中过滤效率差。

通过以上指标,可以大致分析出存储引擎处理的行数以及最终过滤后的结果行数大小。通过Rows***Filtered这组指标,也可以分析查询条件是否下推到了存储引擎,以及不同索引的过滤效果。

其他指标

还可以通过如下几个指标进行分析。

  • OlapScanner下的很多指标,如IOTimerBlockFetchTime等是所有Scanner线程指标的累加,因此数值可能会比较大。并且因为Scanner线程异步读取数据,所以这些累加指标只能反映Scanner累加的工作时间,并不直接代表ScanNode的耗时。ScanNode在整个查询计划中的耗时占比为Active字段记录的值。有时会出现例如IOTimer有几十秒,而Active实际只有几秒钟。这种情况可能有以下几个原因。

    • IOTimer为多个Scanner的累加时间,而Scanner数量较多。

    • 上层节点比较耗时。例如上层节点耗时100秒,而底层ScanNode只需10秒。则反映在Active的字段可能只有几毫秒。因为在上层处理数据的同时,ScanNode已经异步的进行了数据扫描并准备好了数据。当上层节点从ScanNode获取数据时,可以获取到已经准备好的数据,因此Active时间很短。

  • NumScanners表示Scanner提交到线程池的Task个数,由RuntimeState中的线程池调度。doris_scanner_thread_pool_thread_numdoris_scanner_thread_pool_queue_size两个参数分别控制线程池的大小和队列长度。线程数过多或过少都会影响查询效率。同时可以用一些汇总指标除以线程数来大致的估算每个线程的耗时。

  • TabletCount表示需要扫描的Tablet数量。数量过多可能意味着需要大量的随机读取和数据合并操作。

  • UncompressedBytesRead间接反映了读取的数据量。如果该数值较大,说明可能有大量的IO操作。

  • CachedPagesNumTotalPagesNum可以查看命中PageCache的情况。命中率越高,说明IO和解压操作耗时越少。

Buffer pool

参数名称

参数说明

AllocTime

内存分配耗时。

CumulativeAllocationBytes

累计内存分配的量。

CumulativeAllocations

累计的内存分配次数。

PeakReservation

Reservation的峰值。

PeakUnpinnedBytes

Unpin的内存数据量。

PeakUsedReservation

Reservation的内存使用量。

ReservationLimit

BufferPool的Reservation的限制量。

  • 本页导读 (1)
文档反馈