产品概述
基本概念
集群架构
产品优势
应用场景
mysql> set enable_profile=true;
is_report_success),在 FE 的 Web 页面就可以看到对应 SQL 语句执行的 Report 信息:

Query:Summary:Query ID: 9664061c57e84404-85ae111b8ba7e83aStart Time: 2020-05-02 10:34:57End Time: 2020-05-02 10:35:08Total: 10s323msQuery Type: QueryQuery State: EOFDoris Version: trunkUser: rootDefault Db: default_cluster:testSql Statement: select max(Bid_Price) from quotes group by Symbol
Fragment 0:Instance 9664061c57e84404-85ae111b8ba7e83d (host=TNetworkAddress(hostname:192.168.0.1, port:9060)):(Active: 10s270ms, % non-child: 0.14%)- MemoryLimit: 2.00 GB- BytesReceived: 168.08 KB- PeakUsedReservation: 0.00- SendersBlockedTimer: 0ns- DeserializeRowBatchTimer: 501.975us- PeakMemoryUsage: 577.04 KB- RowsProduced: 8.322K (8322)EXCHANGE_NODE (id=4):(Active: 10s256ms, % non-child: 99.35%)- ConvertRowBatchTime: 180.171us- PeakMemoryUsage: 0.00- RowsReturned: 8.322K (8322)- MemoryUsed: 0.00- RowsReturnedRate: 811
hostname指的是执行 Fragment 的 BE 节点。Active:10s270ms表示该节点的执行总时间。non-child: 0.14%表示执行节点自身的执行时间(不包含子节点的执行时间)占总时间的百分比。PeakMemoryUsage表示EXCHANGE_NODE内存使用的峰值。RowsReturned表示EXCHANGE_NODE结果返回的行数。RowsReturnedRate=RowsReturned/ActiveTime。NODE中的含义相同。
后续依次打印子节点的统计信息,这里可以通过缩进区分节点之间的父子关系。FragmentBlockMgrDataStreamSenderODBC_TABLE_SINKEXCHANGE_NODESORT_NODEAGGREGATION_NODEHASH_JOIN_NODECROSS_JOIN_NODEUNION_NODEANALYTIC_EVAL_NODEOLAP_SCAN_NODEOLAP_SCAN_NODE 节点负责具体的数据扫描任务。一个 OLAP_SCAN_NODE 会生成一个或多个 OlapScanner 。每个 Scanner 线程负责扫描部分数据。OLAP_SCAN_NODE。这些谓词条件中一部分会继续下推给存储引擎,以便利用存储引擎的索引进行数据过滤。另一部分会保留在 OLAP_SCAN_NODE 中,用于过滤从存储引擎中返回的数据。OLAP_SCAN_NODE 节点的 Profile 通常用于分析数据扫描的效率,依据调用关系分为 OLAP_SCAN_NODE、OlapScanner、SegmentIterator 三层。
一个典型的 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 # 向量化条件过滤操作的耗时。
RowsKeyRangeFiltered。RowsBitmapIndexFiltered。RowsBloomFilterFiltered。RowsBloomFilterFiltered 的值是 Segment 的总行数(而不是Bitmap索引过滤后的行数)和经过 BloomFilter 过滤后剩余行数的差值,因此 BloomFilter 过滤的数据可能会和 Bitmap 过滤的数据有重叠。RowsStatsFiltered。RowsConditionsFiltered 是各种索引过滤的行数,包含了 RowsBloomFilterFiltered 和 RowsStatsFiltered 的值。RowsDelFiltered。因此删除条件实际过滤的行数,分别记录在 RowsStatsFiltered 和 RowsDelFiltered 中。RawRowsRead 是经过上述过滤后,最终需要读取的行数。RowsRead 是最终返回给 Scanner 的行数。RowsRead 通常小于 RawRowsRead,是因为从存储引擎返回到 Scanner,可能会经过一次数据聚合。如果 RawRowsRead 和 RowsRead 差距较大,则说明大量的行被聚合,而聚合可能比较耗时。RowsReturned 是 ScanNode 最终返回给上层节点的行数。RowsReturned 通常也会小于RowsRead。因为在 Scanner 上会有一些没有下推给存储引擎的谓词条件,会进行一次过滤。如果 RowsRead 和 RowsReturned 差距较大,则说明很多行在 Scanner 中进行了过滤。这说明很多选择度高的谓词条件并没有推送给存储引擎。而在 Scanner 中的过滤效率会比在存储引擎中过滤效率差。Rows***Filtered 这组指标,也可以分析查询条件是否下推到了存储引擎,以及不同索引的过滤效果。此外还可以通过以下几个方面进行简单的分析。OlapScanner 下的很多指标,如 IOTimer,BlockFetchTime 等都是所有 Scanner 线程指标的累加,因此数值可能会比较大。并且因为 Scanner 线程是异步读取数据的,所以这些累加指标只能反映 Scanner 累加的工作时间,并不直接代表 ScanNode 的耗时。ScanNode 在整个查询计划中的耗时占比为 Active 字段记录的值。有时会出现例如 IOTimer 有几十秒,而 Active 实际只有几秒钟。这种情况通常因为:IOTimer 为多个 Scanner 的累加时间,而 Scanner 数量较多。Active 的字段可能只有几毫秒。因为在上层处理数据的同时,ScanNode 已经异步的进行了数据扫描并准备好了数据。当上层节点从 ScanNode 获取数据时,可以获取到已经准备好的数据,因此 Active 时间很短。NumScanners 表示 Scanner 提交到线程池的Task个数,由 RuntimeState 中的线程池调度,doris_scanner_thread_pool_thread_num 和 doris_scanner_thread_pool_queue_size 两个参数分别控制线程池的大小和队列长度。线程数过多或过少都会影响查询效率。同时可以用一些汇总指标除以线程数来大致的估算每个线程的耗时。TabletCount 表示需要扫描的 tablet 数量。数量过多可能意味着需要大量的随机读取和数据合并操作。UncompressedBytesRead 间接反映了读取的数据量。如果该数值较大,说明可能有大量的 IO 操作。CachedPagesNum 和 TotalPagesNum 可以查看命中 PageCache 的情况。命中率越高,说明 IO 和解压操作耗时越少。Buffer pool文档反馈