diff --git a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts index e0b7acbc2..e65e74620 100644 --- a/src/.vuepress/sidebar/V2.0.x/zh-Table.ts +++ b/src/.vuepress/sidebar/V2.0.x/zh-Table.ts @@ -90,6 +90,14 @@ export const zhSidebar = { // children: 'structure', children: [ { text: '数据同步', link: 'Data-Sync_apache' }, + { + text: '系统运维', + collapsible: true, + children: [ + { text: '查询性能分析', link: 'Query-Performance-Analysis' }, + { text: '运维语句', link: 'Maintenance-statement' }, + ], + }, ], }, { diff --git a/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts b/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts index 9c634ae09..481b969c0 100644 --- a/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts +++ b/src/.vuepress/sidebar_timecho/V2.0.x/zh-Table.ts @@ -93,6 +93,14 @@ export const zhSidebar = { children: [ { text: '数据同步', link: 'Data-Sync_timecho' }, { text: '多级存储', link: 'Tiered-Storage_timecho' }, + { + text: '系统运维', + collapsible: true, + children: [ + { text: '查询性能分析', link: 'Query-Performance-Analysis' }, + { text: '运维语句', link: 'Maintenance-statement' }, + ], + }, ], }, { diff --git a/src/zh/UserGuide/Master/Table/User-Manual/Maintenance-statement.md b/src/zh/UserGuide/Master/Table/User-Manual/Maintenance-statement.md new file mode 100644 index 000000000..5453f2f3f --- /dev/null +++ b/src/zh/UserGuide/Master/Table/User-Manual/Maintenance-statement.md @@ -0,0 +1,631 @@ + +# 运维语句 + +## 1 状态查看 + +### 1.1 查看连接的模型 + +**含义**:返回当前连接的 sql_dialect 是树模型/表模型。 + +#### 语法: + +```SQL +showCurrentSqlDialectStatement + : SHOW CURRENT_SQL_DIALECT + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_SQL_DIALECT +``` + +执行结果如下: + +```SQL ++-----------------+ +|CurrentSqlDialect| ++-----------------+ +| TABLE| ++-----------------+ +``` +### 1.2 查看登录的用户名 + +**含义**:返回当前登录的用户名。 + +#### 语法: + +```SQL +showCurrentUserStatement + : SHOW CURRENT_USER + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_USER +``` + +执行结果如下: + +```SQL ++-----------+ +|CurrentUser| ++-----------+ +| root| ++-----------+ +``` + +### 1.3 查看连接的数据库名 + +**含义**:返回当前连接的数据库名,若没有执行过 use 语句,则为 null。 + +#### 语法: + +```SQL +showCurrentDatabaseStatement + : SHOW CURRENT_DATABASE + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_DATABASE; + +IoTDB> USE test; + +IoTDB> SHOW CURRENT_DATABASE; +``` + +执行结果如下: + +```SQL ++---------------+ +|CurrentDatabase| ++---------------+ +| null| ++---------------+ + ++---------------+ +|CurrentDatabase| ++---------------+ +| test| ++---------------+ +``` + +### 1.4 查看集群版本 + +**含义**:返回当前集群的版本。 + +#### 语法: + +```SQL +showVersionStatement + : SHOW VERSION + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW VERSION +``` + +执行结果如下: + +```SQL ++-------+---------+ +|Version|BuildInfo| ++-------+---------+ +|2.0.1.2| 1ca4008| ++-------+---------+ +``` + +### 1.5 查看集群关键参数 + +**含义**:返回当前集群的关键参数。 + +#### 语法: + +```SQL +showVariablesStatement + : SHOW VARIABLES + ; +``` + +关键参数如下: + +1. **ClusterName**:当前集群的名称。 +2. **DataReplicationFactor**:数据副本的数量,表示每个数据分区(DataRegion)的副本数。 +3. **SchemaReplicationFactor**:元数据副本的数量,表示每个元数据分区(SchemaRegion)的副本数。 +4. **DataRegionConsensusProtocolClass**:数据分区(DataRegion)使用的共识协议类。 +5. **SchemaRegionConsensusProtocolClass**:元数据分区(SchemaRegion)使用的共识协议类。 +6. **ConfigNodeConsensusProtocolClass**:配置节点(ConfigNode)使用的共识协议类。 +7. **TimePartitionOrigin**:数据库时间分区的起始时间戳。 +8. **TimePartitionInterval**:数据库的时间分区间隔(单位:毫秒)。 +9. **ReadConsistencyLevel**:读取操作的一致性级别。 +10. **SchemaRegionPerDataNode**:数据节点(DataNode)上的元数据分区(SchemaRegion)数量。 +11. **DataRegionPerDataNode**:数据节点(DataNode)上的数据分区(DataRegion)数量。 +12. **SeriesSlotNum**:数据分区(DataRegion)的序列槽(SeriesSlot)数量。 +13. **SeriesSlotExecutorClass**:序列槽的实现类。 +14. **DiskSpaceWarningThreshold**:磁盘空间告警阈值(单位:百分比)。 +15. **TimestampPrecision**:时间戳精度。 + +#### 示例: + +```SQL +IoTDB> SHOW VARIABLES +``` + +执行结果如下: + +```SQL ++----------------------------------+-----------------------------------------------------------------+ +| Variable| Value| ++----------------------------------+-----------------------------------------------------------------+ +| ClusterName| defaultCluster| +| DataReplicationFactor| 1| +| SchemaReplicationFactor| 1| +| DataRegionConsensusProtocolClass| org.apache.iotdb.consensus.iot.IoTConsensus| +|SchemaRegionConsensusProtocolClass| org.apache.iotdb.consensus.ratis.RatisConsensus| +| ConfigNodeConsensusProtocolClass| org.apache.iotdb.consensus.ratis.RatisConsensus| +| TimePartitionOrigin| 0| +| TimePartitionInterval| 604800000| +| ReadConsistencyLevel| strong| +| SchemaRegionPerDataNode| 1| +| DataRegionPerDataNode| 0| +| SeriesSlotNum| 1000| +| SeriesSlotExecutorClass|org.apache.iotdb.commons.partition.executor.hash.BKDRHashExecutor| +| DiskSpaceWarningThreshold| 0.05| +| TimestampPrecision| ms| ++----------------------------------+-----------------------------------------------------------------+ +``` + +### 1.6 查看集群ID + +**含义**:返回当前集群的ID。 + +#### 语法: + +```SQL +showClusterIdStatement + : SHOW (CLUSTERID | CLUSTER_ID) + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CLUSTER_ID +``` + +执行结果如下: + +```SQL ++------------------------------------+ +| ClusterId| ++------------------------------------+ +|40163007-9ec1-4455-aa36-8055d740fcda| +``` + +### 1.7 查看客户端直连的 DataNode 进程所在服务器的时间 + +#### 语法: + +**含义**:返回当前客户端直连的 DataNode 进程所在服务器的时间。 + +```SQL +showCurrentTimestampStatement + : SHOW CURRENT_TIMESTAMP + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_TIMESTAMP +``` + +执行结果如下: + +```SQL ++-----------------------------+ +| CurrentTimestamp| ++-----------------------------+ +|2025-02-17T11:11:52.987+08:00| ++-----------------------------+ +``` + +### 1.8 查看正在执行的查询信息 + +**含义**:用于显示所有正在执行的查询信息。 + +#### 语法: + +```SQL +showQueriesStatement + : SHOW (QUERIES | QUERY PROCESSLIST) + (WHERE where=booleanExpression)? + (ORDER BY sortItem (',' sortItem)*)? + limitOffsetClause + ; +``` + +**参数解释**: + +1. **WHERE** 子句:需保证过滤的目标列是结果集中存在的列 +2. **ORDER BY** 子句:需保证`sortKey`是结果集中存在的列 +3. **limitOffsetClause**: + - **含义**:用于限制结果集的返回数量。 + - **格式**:`LIMIT , `, `` 是偏移量,`` 是返回的行数。 +4. **QUERIES** 表中的列: + - **query_id**:查询语句的 ID + - **start_time**:查询开始的时间戳,时间戳精度与系统精度一致 + - **datanode_id**:发起查询语句的 DataNode 的ID + - **elapsed_time**:查询的执行耗时,单位是秒 + - **statement**:查询的 SQL 语句 + - **user**:发起查询的用户 + +#### 示例: + +```SQL +IoTDB> SHOW QUERIES WHERE elapsed_time > 30 +``` + +执行结果如下: + +```SQL ++-----------------------+-----------------------------+-----------+------------+------------+----+ +| query_id| start_time|datanode_id|elapsed_time| statement|user| ++-----------------------+-----------------------------+-----------+------------+------------+----+ +|20250108_101015_00000_1|2025-01-08T18:10:15.935+08:00| 1| 32.283|show queries|root| ++-----------------------+-----------------------------+-----------+------------+------------+----+ +``` + +## 2 状态设置 + +### 2.1 设置连接的模型 + +**含义**:将当前连接的 sql_dialect 置为树模型/表模型。 + +#### 语法: + +```SQL +SET SQL_DIALECT EQ (TABLE | TREE) +``` + +#### 示例: + +```SQL +IoTDB> SET SQL_DIALECT=TABLE +IoTDB> SHOW CURRENT_SQL_DIALECT +``` + +执行结果如下: + +```SQL ++-----------------+ +|CurrentSqlDialect| ++-----------------+ +| TABLE| ++-----------------+ +``` + +### 2.2 更新配置项 + +**含义**:用于更新配置项,执行完成后会进行配置项的热加载,对于支持热修改的配置项会立即生效。 + +#### 语法: + +```SQL +setConfigurationStatement + : SET CONFIGURATION propertyAssignments (ON INTEGER_VALUE)? + ; + +propertyAssignments + : property (',' property)* + ; + +property + : identifier EQ propertyValue + ; + +propertyValue + : DEFAULT + | expression + ; +``` + +**参数解释**: + +1. **propertyAssignments** + - **含义**:更新的配置列表,由多个 `property` 组成。 + - 可以更新多个配置列表,用逗号分隔。 + - **取值**: + - `DEFAULT`:将配置项恢复为默认值。 + - `expression`:具体的值,必须是一个字符串。 +2. **ON INTEGER_VALUE** + - **含义**:指定要更新配置的节点 ID。 + - **可选性**:可选。如果不指定或指定的值低于 0,则更新所有 ConfigNode 和 DataNode 的配置。 + +#### 示例: + +```SQL +IoTDB> SET CONFIGURATION "a"='1',b='1' ON 1; +``` + +### 2.3 读取手动修改的配置文件 + +**含义**:用于读取手动修改过的配置文件,并对配置项进行热加载,对于支持热修改的配置项会立即生效。 + +#### 语法: + +```SQL +loadConfigurationStatement + : LOAD CONFIGURATION localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **localOrClusterMode** + - **含义**:指定配置热加载的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:只对客户端直连的 DataNode 进行配置热加载。 + - `ON CLUSTER`:对集群中所有 DataNode 进行配置热加载。 + +#### 示例: + +```SQL +IoTDB> LOAD CONFIGURATION ON LOCAL; +``` + +### 2.4 设置系统的状态 + +**含义**:用于设置系统的状态。 + +#### 语法: + +```SQL +setSystemStatusStatement + : SET SYSTEM TO (READONLY | RUNNING) localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **RUNNING | READONLY** + - **含义**:指定系统的新状态。 + - **取值**: + - `RUNNING`:将系统设置为运行状态,允许读写操作。 + - `READONLY`:将系统设置为只读状态,只允许读取操作,禁止写入操作。 +2. **localOrClusterMode** + - **含义**:指定状态变更的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:仅对客户端直连的 DataNode 生效。 + - `ON CLUSTER`:对集群中所有 DataNode 生效。 + +#### 示例: + +```SQL +IoTDB> SET SYSTEM TO READONLY ON CLUSTER; +``` + + +## 3 数据管理 + +### 3.1 刷写内存表中的数据到磁盘 + +**含义**:将内存表中的数据刷写到磁盘上。 + +#### 语法: + +```SQL +flushStatement + : FLUSH identifier? (',' identifier)* booleanValue? localOrClusterMode? + ; + +booleanValue + : TRUE | FALSE + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **identifier** + - **含义**:指定要刷写的数据库名称。 + - **可选性**:可选。如果不指定,则默认刷写所有数据库。 + - **多个数据库**:可以指定多个数据库名称,用逗号分隔。例如:`FLUSH test_db1, test_db2`。 +2. **booleanValue** + - **含义**:指定刷写的内容。 + - **可选性**:可选。如果不指定,则默认刷写顺序和乱序空间的内存。 + - **取值**: + - `TRUE`:只刷写顺序空间的内存表。 + - `FALSE`:只刷写乱序空间的MemTable。 +3. **localOrClusterMode** + - **含义**:指定刷写的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:只刷写客户端直连的 DataNode 上的内存表。 + - `ON CLUSTER`:刷写集群中所有 DataNode 上的内存表。 + +#### 示例: + +```SQL +IoTDB> FLUSH test_db TRUE ON LOCAL; +``` + +### 3.2 清除 DataNode 上的缓存 + +**含义**:用于清除 DataNode 上的某种类型的缓存。 + +#### 语法: + +```SQL +clearCacheStatement + : CLEAR clearCacheOptions? CACHE localOrClusterMode? + ; + +clearCacheOptions + : ATTRIBUTE + | QUERY + | ALL + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **clearCacheOptions** + - **含义**:指定要清除的缓存类型。 + - **可选性**:可选。如果不指定,默认清除查询缓存(`QUERY`)。 + - **取值**: + - `ATTRIBUTE`:清除设备属性缓存。 + - `QUERY`:清除存储引擎中的查询缓存。 + - `ALL`:清除所有缓存,包括设备属性缓存、查询缓存以及树模型中的模式缓存。 +2. **localOrClusterMode** + - **含义**:指定清除缓存的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:只清除客户端直连的 DataNode 上的缓存。 + - `ON CLUSTER`:清除集群中所有 DataNode 上的缓存。 + +#### 示例: + +```SQL +IoTDB> CLEAR ALL CACHE ON LOCAL; +``` + +## 4 数据修复 + +### 4.1 启动后台扫描并修复 tsfile 任务 + +**含义**:启动一个后台任务,开始扫描并修复 tsfile,能够修复数据文件内的时间戳乱序类异常。 + +#### 语法: + +```SQL +startRepairDataStatement + : START REPAIR DATA localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **localOrClusterMode** + - **含义**:指定数据修复的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:仅对客户端直连的 DataNode 执行。 + - `ON CLUSTER`:对集群中所有 DataNode 执行。 + +#### 示例: + +```SQL +IoTDB> START REPAIR DATA ON CLUSTER; +``` + +### 4.2 暂停后台修复 tsfile 任务 + +**含义**:暂停后台的修复任务,暂停中的任务可通过再次执行 start repair data 命令恢复。 + +#### 语法: + +```SQL +stopRepairDataStatement + : STOP REPAIR DATA localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **localOrClusterMode** + - **含义**:指定数据修复的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:仅对客户端直连的 DataNode 执行。 + - `ON CLUSTER`:对集群中所有 DataNode 执行。 + +#### 示例: + +```SQL +IoTDB> STOP REPAIR DATA ON CLUSTER; +``` + +## 5 终止查询 + +### 5.1 主动终止查询 + +**含义**:使用该命令主动地终止查询。 + +#### 语法: + +```SQL +killQueryStatement + : KILL (QUERY queryId=string | ALL QUERIES) + ; +``` + +**参数解释**: + +1. **QUERY queryId=string** + - **含义**:指定要终止的查询的 ID。 `` 是正在执行的查询的唯一标识符。 + - **获取查询 ID**:可以通过 `SHOW QUERIES` 命令获取所有正在执行的查询及其 ID。 +2. **ALL QUERIES** + - **含义**:终止所有正在执行的查询。 + +#### 示例: + +通过指定 `queryId` 可以中止指定的查询,为了获取正在执行的查询 id,用户可以使用 show queries 命令,该命令将显示所有正在执行的查询列表。 + +```SQL +IoTDB> KILL QUERY 20250108_101015_00000_1; -- 终止指定query +IoTDB> KILL ALL QUERIES; -- 终止所有query +``` \ No newline at end of file diff --git a/src/zh/UserGuide/Master/Table/User-Manual/Query-Performance-Analysis.md b/src/zh/UserGuide/Master/Table/User-Manual/Query-Performance-Analysis.md new file mode 100644 index 000000000..b577983a8 --- /dev/null +++ b/src/zh/UserGuide/Master/Table/User-Manual/Query-Performance-Analysis.md @@ -0,0 +1,335 @@ + +# 系统运维 + +## 查询性能分析 + +查询分析的意义在于帮助用户理解查询的执行机制和性能瓶颈,从而实现查询优化和性能提升。这不仅关乎到查询的执行效率,也直接影响到应用的用户体验和资源的有效利用。为了进行有效的查询分析,IoTDB 提供了查询分析语句:Explain 和 Explain Analyze。 + +- Explain 语句:允许用户预览查询 SQL 的执行计划,包括 IoTDB 如何组织数据检索和处理。 +- Explain Analyze 语句:在 Explain 语句基础上增加了性能分析,完整执行 SQL 并展示查询执行过程中的时间和资源消耗。为 IoTDB 用户深入理解查询详情以及进行查询优化提供了详细的相关信息。与其他常用的 IoTDB 排查手段相比,Explain Analyze 没有部署负担,同时能够针对单条 sql 进行分析,能够更好定位问题。各类方法对比如下:: + +| 方法 | 安装难度 | 业务影响 | 功能范围 | +| ------------------- | ------------------------------------------------------------ | ---------------------------------------------------- | ------------------------------------------------------ | +| Explain Analyze语句 | 低。无需安装额外组件,为IoTDB内置SQL语句 | 低。只会影响当前分析的单条查询,对线上其他负载无影响 | 支持分布式,可支持对单条SQL进行追踪 | +| 监控面板 | 中。需要安装IoTDB监控面板工具(企业版工具),并开启IoTDB监控服务 | 中。IoTDB监控服务记录指标会带来额外耗时 | 支持分布式,仅支持对数据库整体查询负载和耗时进行分析 | +| Arthas抽样 | 中。需要安装Java Arthas工具(部分内网无法直接安装Arthas,且安装后,有时需要重启应用) | 高。CPU 抽样可能会影响线上业务的响应速度 | 不支持分布式,仅支持对数据库整体查询负载和耗时进行分析 | + +### Explain 语句 + +#### 语法 + +Explain命令允许用户查看SQL查询的执行计划。执行计划以算子的形式展示,描述了IoTDB会如何执行查询。其语法如下,其中SELECT_STATEMENT是查询相关的SQL语句: + +```SQL +EXPLAIN +``` +#### 含义 + +```SQL +-- 创建数据库 +create database test; + +-- 创建表 +use test; +create table t1 (device_id STRING ID, type STRING ATTRIBUTE, speed float); + +-- 插入数据 +insert into t1(device_id, type, speed) values('car_1', 'Model Y', 120.0); +insert into t1(device_id, type, speed) values('car_2', 'Model 3', 100.0); + +-- 执行 explain 语句 +explain select * from t1; +``` +执行上方SQL,会得到如下结果。不难看出,IoTDB 分别通过两个 TableScan 节点去不同的数据分区中获取表中的数据,最后通过Collect 算子汇总数据后返回。 + +```SQL ++-----------------------------------------------------------------------------------------------+ +| distribution plan| ++-----------------------------------------------------------------------------------------------+ +| ┌─────────────────────────────────────────────┐ | +| │OutputNode-4 │ | +| │OutputColumns-[time, device_id, type, speed] │ | +| │OutputSymbols: [time, device_id, type, speed]│ | +| └─────────────────────────────────────────────┘ | +| │ | +| │ | +| ┌─────────────────────────────────────────────┐ | +| │Collect-21 │ | +| │OutputSymbols: [time, device_id, type, speed]│ | +| └─────────────────────────────────────────────┘ | +| ┌───────────────────────┴───────────────────────┐ | +| │ │ | +|┌─────────────────────────────────────────────┐ ┌───────────┐ | +|│TableScan-19 │ │Exchange-28│ | +|│QualifiedTableName: test.t1 │ └───────────┘ | +|│OutputSymbols: [time, device_id, type, speed]│ │ | +|│DeviceNumber: 1 │ │ | +|│ScanOrder: ASC │ ┌─────────────────────────────────────────────┐| +|│PushDownOffset: 0 │ │TableScan-20 │| +|│PushDownLimit: 0 │ │QualifiedTableName: test.t1 │| +|│PushDownLimitToEachDevice: false │ │OutputSymbols: [time, device_id, type, speed]│| +|│RegionId: 2 │ │DeviceNumber: 1 │| +|└─────────────────────────────────────────────┘ │ScanOrder: ASC │| +| │PushDownOffset: 0 │| +| │PushDownLimit: 0 │| +| │PushDownLimitToEachDevice: false │| +| │RegionId: 1 │| +| └─────────────────────────────────────────────┘| ++-----------------------------------------------------------------------------------------------+ +``` + + +### Explain Analyze 语句 + +#### 语法 + +```SQL +EXPLAIN ANALYZE [VERBOSE] +``` + +其中 SELECT_STATEMENT 对应需要分析的查询语句;VERBOSE为打印详细分析结果,不填写VERBOSE时EXPLAIN ANALYZE将会省略部分信息。 + +#### 含义 + +Explain Analyze 是 IOTDB 查询引擎自带的性能分析 SQL,与 Explain 不同,它会执行对应的查询计划并统计执行信息,可以用于追踪一条查询的具体性能分布,用于对资源进行观察,进行性能调优与异常分析。 + +在 EXPLAIN ANALYZE 的结果集中,会包含如下信息: + +![explain-analyze-1.png](/img/explain-analyze-1.png) + +其中: + +- QueryStatistics 包含查询层面进的统计信息,主要包含各规划阶段耗时,查询分片数量等信息。 + - Analyze Cost: SQL 分析阶段的耗时(包含 FetchPartitionCost 和 FetchSchemaCost) + - Fetch Partition Cost:拉取分区表的耗时 + - Fetch Schema Cost:拉取元数据以及权限校验的耗时 + - Logical Plan Cost:构建逻辑计划的耗时 + - Logical Optimization Cost: 逻辑计划优化的耗时 + - Distribution Plan Cost:构建分布式计划的耗时 + - Fragment Instance Count:总的查询分片的数量,每个查询分片的信息会挨个输出 +- FragmentInstance 是 IoTDB 一个查询分片的封装,每一个查询分片都会在结果集中输出一份分片的执行信息,主要包含 FragmentStatistics 和算子信息。FragmentStastistics 包含 Fragment 的统计信息,包括总实际耗时(墙上时间),所涉及到的 TsFile,调度信息等情况。在一个 Fragment 的信息输出同时会以节点树层级的方式展示该Fragment 下计划节点的统计信息,主要包括:CPU运行时间、输出的数据行数、指定接口被调用的次数、所占用的内存、节点专属的定制信息。 + - Total Wall Time: 该分片从开始执行到执行结束的物理时间 + - Cost of initDataQuerySource:构建查询文件列表 + - Seq File(unclosed): 未封口(memtable)的顺序文件数量, Seq File(closed): 封口的顺序文件数量 + - UnSeq File(unclosed): 未封口(memtable)的乱序文件数量, UnSeq File(closed): 未封口的乱序文件数量 + - ready queued time: 查询分片的所有task在 ready queue 中的总时长(task 未阻塞,但没有查询执行线程资源时,会被放入ready queue),blocked queued time: 查询分片的所有task在 bloced queue 中的总时长(task 因为某些资源,如内存,或者上游数据未发送过来,则会被放入blocked queue) + - BloomFilter 相关(用于判断某个序列在tsfile中是否存在,存储于tsfile尾部) + - loadBloomFilterFromCacheCount: 命中BloomFilterCache的次数 + - loadBloomFilterFromDiskCount: 从磁盘中读取的次数 + - loadBloomFilterActualIOSize: 从磁盘中读取BloomFilter时耗费的磁盘IO(单位为bytes) + - loadBloomFilterTime: 读取BloomFilter + 计算序列是否存在的总耗时(单位为ms) + - TimeSeriesMetadata 相关(序列在tsfile中的索引信息,一个序列在一个tsfile中只会存储一个) + - loadTimeSeriesMetadataDiskSeqCount: 从封口的顺序文件里加载出的TimeSeriesMetadata数量 + - 大部分情况下等于Seq File(closed),但如果有limit等算子,可能实际加载的数量会小于Seq File(closed) + - loadTimeSeriesMetadataDiskUnSeqCount: 从封口的乱序文件里加载出的TimeSeriesMetadata数量 + - 大部分情况下等于UnSeq File(closed),但如果有limit等算子,可能实际加载的数量会小于UnSeq File(closed) + - loadTimeSeriesMetadataDiskSeqTime: 从封口的顺序文件里加载TimeSeriesMetadata的耗时 + - 并不是所有的 TimeSeriesMetadata 加载都涉及磁盘 IO,有可能会命中TimeSeriesMetadataCache,直接从缓存中读取,但输出信息里并没有分开统计这两者的耗时 + - loadTimeSeriesMetadataDiskUnSeqTime: 从未封口的顺序文件里加载TimeSeriesMetadata的耗时 + - loadTimeSeriesMetadataFromCacheCount: 命中TimeSeriesMetadataCache的次数,注意这里对于对齐设备来讲,每个分量(包括time列,都会去单独请求Cache,所以对于对齐设备来讲,(loadTimeSeriesMetadataFromCacheCount + loadTimeSeriesMetadataFromDiskCount)= tsfile number * subSensor number(包括time列) + - loadTimeSeriesMetadataFromDiskCount: 从磁盘中读取TimeSeriesMetadata的次数,一次读取会把该设备下查询所有涉及到的分量都读出来缓存在TimeSeriesMetadataCache中 + - loadTimeSeriesMetadataActualIOSize: 从磁盘中读取TimeSeriesMetadata时耗费的磁盘IO(单位为bytes) + - Mods 文件相关 + - TimeSeriesMetadataModificationTime: 读取mods文件花费的时间 + - Chunk 相关 + - constructAlignedChunkReadersDiskCount: 读取已封口 tsfile 中总的 Chunk 数量 + - constructAlignedChunkReadersDiskTime: 读取已封口 tsfile 中 Chunk 的总耗时(包含磁盘IO和解压缩) + - pageReadersDecodeAlignedDiskCount: 解编码已封口 tsfile 中总的 page 数量 + - pageReadersDecodeAlignedDiskTime: 解编码已封口 tsfile 中 page 的总耗时 + - loadChunkFromCacheCount: 命中ChunkCache的次数,注意这里对于对齐设备来讲,每个分量(包括time列,都会去单独请求Cache,所以对于对齐设备来讲,(loadChunkFromCacheCount + loadChunkFromDiskCount)= tsfile number * subSensor number(包括time列)* avg chunk number in each tsfile + - loadChunkFromDiskCount: 从磁盘中读取Chunk的次数,一次只会读取一个分量,并缓存在ChunkCache中 + - loadChunkActualIOSize: 从磁盘中读取Chunk时耗费的磁盘IO(单位为bytes) + + +##### 特别说明 + +查询超时场景使用 Explain Analyze 语句: + +Explain Analyze 本身是一种特殊的查询,所以当执行超时的时候,Explain Analyze 语句也无法正常返回结果。为了在查询超时的情况下也可以通过分析结果排查超时原因,Explain Analyze 提供了定时日志机制(无需用户配置),每经过一定的时间间隔会将 Explain Analyze 的当前结果以文本的形式输出到专门的日志中。当查询超时时,用户可以前往logs/log_explain_analyze.log中查看对应的日志进行排查。 +日志的时间间隔基于查询的超时时间进行计算,可以保证在超时的情况下至少会有两次的结果记录。 + +##### 示例 + +下面是Explain Analyze的一个例子: + +```SQL +-- 创建数据库 +create database test; + +-- 创建表 +use test; +create table t1 (device_id STRING ID, type STRING ATTRIBUTE, speed float); + +-- 插入数据 +insert into t1(device_id, type, speed) values('car_1', 'Model Y', 120.0); +insert into t1(device_id, type, speed) values('car_2', 'Model 3', 100.0); + +-- 执行 explain analyze 语句 +explain analyze verbose select * from t1; +``` + +得到输出如下: + +```SQL ++-----------------------------------------------------------------------------------------------+ +| Explain Analyze| ++-----------------------------------------------------------------------------------------------+ +|Analyze Cost: 38.860 ms | +|Fetch Partition Cost: 9.888 ms | +|Fetch Schema Cost: 54.046 ms | +|Logical Plan Cost: 10.102 ms | +|Logical Optimization Cost: 17.396 ms | +|Distribution Plan Cost: 2.508 ms | +|Dispatch Cost: 22.126 ms | +|Fragment Instances Count: 2 | +| | +|FRAGMENT-INSTANCE[Id: 20241127_090849_00009_1.2.0][IP: 0.0.0.0][DataRegion: 2][State: FINISHED]| +| Total Wall Time: 18 ms | +| Cost of initDataQuerySource: 6.153 ms | +| Seq File(unclosed): 1, Seq File(closed): 0 | +| UnSeq File(unclosed): 0, UnSeq File(closed): 0 | +| ready queued time: 0.164 ms, blocked queued time: 0.342 ms | +| Query Statistics: | +| loadBloomFilterFromCacheCount: 0 | +| loadBloomFilterFromDiskCount: 0 | +| loadBloomFilterActualIOSize: 0 | +| loadBloomFilterTime: 0.000 | +| loadTimeSeriesMetadataAlignedMemSeqCount: 1 | +| loadTimeSeriesMetadataAlignedMemSeqTime: 0.246 | +| loadTimeSeriesMetadataFromCacheCount: 0 | +| loadTimeSeriesMetadataFromDiskCount: 0 | +| loadTimeSeriesMetadataActualIOSize: 0 | +| constructAlignedChunkReadersMemCount: 1 | +| constructAlignedChunkReadersMemTime: 0.294 | +| loadChunkFromCacheCount: 0 | +| loadChunkFromDiskCount: 0 | +| loadChunkActualIOSize: 0 | +| pageReadersDecodeAlignedMemCount: 1 | +| pageReadersDecodeAlignedMemTime: 0.047 | +| [PlanNodeId 43]: IdentitySinkNode(IdentitySinkOperator) | +| CPU Time: 5.523 ms | +| output: 2 rows | +| HasNext() Called Count: 6 | +| Next() Called Count: 5 | +| Estimated Memory Size: : 327680 | +| [PlanNodeId 31]: CollectNode(CollectOperator) | +| CPU Time: 5.512 ms | +| output: 2 rows | +| HasNext() Called Count: 6 | +| Next() Called Count: 5 | +| Estimated Memory Size: : 327680 | +| [PlanNodeId 29]: TableScanNode(TableScanOperator) | +| CPU Time: 5.439 ms | +| output: 1 rows | +| HasNext() Called Count: 3 +| Next() Called Count: 2 | +| Estimated Memory Size: : 327680 | +| DeviceNumber: 1 | +| CurrentDeviceIndex: 0 | +| [PlanNodeId 40]: ExchangeNode(ExchangeOperator) | +| CPU Time: 0.053 ms | +| output: 1 rows | +| HasNext() Called Count: 2 | +| Next() Called Count: 1 | +| Estimated Memory Size: : 131072 | +| | +|FRAGMENT-INSTANCE[Id: 20241127_090849_00009_1.3.0][IP: 0.0.0.0][DataRegion: 1][State: FINISHED]| +| Total Wall Time: 13 ms | +| Cost of initDataQuerySource: 5.725 ms | +| Seq File(unclosed): 1, Seq File(closed): 0 | +| UnSeq File(unclosed): 0, UnSeq File(closed): 0 | +| ready queued time: 0.118 ms, blocked queued time: 5.844 ms | +| Query Statistics: | +| loadBloomFilterFromCacheCount: 0 | +| loadBloomFilterFromDiskCount: 0 | +| loadBloomFilterActualIOSize: 0 | +| loadBloomFilterTime: 0.000 | +| loadTimeSeriesMetadataAlignedMemSeqCount: 1 | +| loadTimeSeriesMetadataAlignedMemSeqTime: 0.004 | +| loadTimeSeriesMetadataFromCacheCount: 0 | +| loadTimeSeriesMetadataFromDiskCount: 0 | +| loadTimeSeriesMetadataActualIOSize: 0 | +| constructAlignedChunkReadersMemCount: 1 | +| constructAlignedChunkReadersMemTime: 0.001 | +| loadChunkFromCacheCount: 0 | +| loadChunkFromDiskCount: 0 | +| loadChunkActualIOSize: 0 | +| pageReadersDecodeAlignedMemCount: 1 | +| pageReadersDecodeAlignedMemTime: 0.007 | +| [PlanNodeId 42]: IdentitySinkNode(IdentitySinkOperator) | +| CPU Time: 0.270 ms | +| output: 1 rows | +| HasNext() Called Count: 3 | +| Next() Called Count: 2 | +| Estimated Memory Size: : 327680 | +| [PlanNodeId 30]: TableScanNode(TableScanOperator) | +| CPU Time: 0.250 ms | +| output: 1 rows | +| HasNext() Called Count: 3 | +| Next() Called Count: 2 | +| Estimated Memory Size: : 327680 | +| DeviceNumber: 1 | +| CurrentDeviceIndex: 0 | ++-----------------------------------------------------------------------------------------------+ +``` + +### 常见问题 + +#### 1. WALL TIME(墙上时间)和 CPU TIME(CPU时间)的区别? + +CPU 时间也称为处理器时间或处理器使用时间,指的是程序在执行过程中实际占用 CPU 进行计算的时间,显示的是程序实际消耗的处理器资源。 + +墙上时间也称为实际时间或物理时间,指的是从程序开始执行到程序结束的总时间,包括了所有等待时间。。 + +1. WALL TIME < CPU TIME 的场景:比如一个查询分片最后被调度器使用两个线程并行执行,真实物理世界上是 10s 过去了,但两个线程,可能一直占了两个 cpu 核跑了 10s,那 cpu time 就是 20s,wall time就是 10s +2. WALL TIME > CPU TIME 的场景:因为系统内可能会存在多个查询并行执行,但查询的执行线程数和内存是固定的, + 1. 所以当查询分片被某些资源阻塞住时(比如没有足够的内存进行数据传输、或等待上游数据)就会放入Blocked Queue,此时查询分片并不会占用 CPU TIME,但WALL TIME(真实物理时间的时间)是在向前流逝的 + 2. 或者当查询线程资源不足时,比如当前共有16个查询线程,但系统内并发有20个查询分片,即使所有查询都没有被阻塞,也只会同时并行运行16个查询分片,另外四个会被放入 READY QUEUE,等待被调度执行,此时查询分片并不会占用 CPU TIME,但WALL TIME(真实物理时间的时间)是在向前流逝的 + + +#### 2. Explain Analyze 是否有额外开销,测出的耗时是否与查询真实执行时有差别? + +几乎没有,因为 explain analyze operator 是单独的线程执行,收集原查询的统计信息,且这些统计信息,即使不explain analyze,原来的查询也会生成,只是没有人去取。并且 explain analyze 是纯 next 遍历结果集,不会打印,所以与原来查询真实执行时的耗时不会有显著差别。 + +#### 3. IO 耗时主要关注几个指标? + +涉及 IO 耗时的指标主要有:loadBloomFilterActualIOSize, loadBloomFilterTime, loadTimeSeriesMetadataAlignedDisk[Seq/Unseq]Time, loadTimeSeriesMetadataActualIOSize, alignedTimeSeriesMetadataModificationTime, constructAlignedChunkReadersDiskTime, loadChunkActualIOSize,各指标的具体含义见上文。 +TimeSeriesMetadata 的加载分别统计了顺序和乱序文件,但 Chunk 的读取暂时未分开统计,但顺乱序比例可以通过TimeseriesMetadata 顺乱序的比例计算出来。 + + +#### 4. 乱序数据对查询性能的影响能否有一些指标展示出来? + +乱序数据产生的影响主要有两个: + +1. 需要在内存中多做一个归并排序(一般认为这个耗时是比较短的,毕竟是纯内存的 cpu 操作) +2. 乱序数据会产生数据块间的时间范围重叠,导致统计信息无法使用 + 1. 无法利用统计信息直接 skip 掉整个不满足值过滤要求的 chunk + 1. 一般用户的查询都是只包含时间过滤条件,则不会有影响 + 2. 无法利用统计信息直接计算出聚合值,无需读取数据 + +单独对于乱序数据的性能影响,目前并没有有效的观测手段,除非就是在有乱序数据的时候,执行一遍查询耗时,然后等乱序合完了,再执行一遍,才能对比出来。 + +因为即使乱序这部分数据进了顺序,也是需要 IO、加压缩、decode,这个耗时少不了,不会因为乱序数据被合并进乱序了,就减少了。 + +#### 5. 执行 explain analyze 时,查询超时后,为什么结果没有输出在 log_explain_analyze.log 中? + +升级时,只替换了 lib 包,没有替换 conf/logback-datanode.xml,需要替换一下 conf/logback-datanode.xml,然后不需要重启(该文件内容可以被热加载),大约等待 1 分钟后,重新执行 explain analyze verbose。 diff --git a/src/zh/UserGuide/latest-Table/User-Manual/Maintenance-statement.md b/src/zh/UserGuide/latest-Table/User-Manual/Maintenance-statement.md new file mode 100644 index 000000000..5453f2f3f --- /dev/null +++ b/src/zh/UserGuide/latest-Table/User-Manual/Maintenance-statement.md @@ -0,0 +1,631 @@ + +# 运维语句 + +## 1 状态查看 + +### 1.1 查看连接的模型 + +**含义**:返回当前连接的 sql_dialect 是树模型/表模型。 + +#### 语法: + +```SQL +showCurrentSqlDialectStatement + : SHOW CURRENT_SQL_DIALECT + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_SQL_DIALECT +``` + +执行结果如下: + +```SQL ++-----------------+ +|CurrentSqlDialect| ++-----------------+ +| TABLE| ++-----------------+ +``` +### 1.2 查看登录的用户名 + +**含义**:返回当前登录的用户名。 + +#### 语法: + +```SQL +showCurrentUserStatement + : SHOW CURRENT_USER + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_USER +``` + +执行结果如下: + +```SQL ++-----------+ +|CurrentUser| ++-----------+ +| root| ++-----------+ +``` + +### 1.3 查看连接的数据库名 + +**含义**:返回当前连接的数据库名,若没有执行过 use 语句,则为 null。 + +#### 语法: + +```SQL +showCurrentDatabaseStatement + : SHOW CURRENT_DATABASE + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_DATABASE; + +IoTDB> USE test; + +IoTDB> SHOW CURRENT_DATABASE; +``` + +执行结果如下: + +```SQL ++---------------+ +|CurrentDatabase| ++---------------+ +| null| ++---------------+ + ++---------------+ +|CurrentDatabase| ++---------------+ +| test| ++---------------+ +``` + +### 1.4 查看集群版本 + +**含义**:返回当前集群的版本。 + +#### 语法: + +```SQL +showVersionStatement + : SHOW VERSION + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW VERSION +``` + +执行结果如下: + +```SQL ++-------+---------+ +|Version|BuildInfo| ++-------+---------+ +|2.0.1.2| 1ca4008| ++-------+---------+ +``` + +### 1.5 查看集群关键参数 + +**含义**:返回当前集群的关键参数。 + +#### 语法: + +```SQL +showVariablesStatement + : SHOW VARIABLES + ; +``` + +关键参数如下: + +1. **ClusterName**:当前集群的名称。 +2. **DataReplicationFactor**:数据副本的数量,表示每个数据分区(DataRegion)的副本数。 +3. **SchemaReplicationFactor**:元数据副本的数量,表示每个元数据分区(SchemaRegion)的副本数。 +4. **DataRegionConsensusProtocolClass**:数据分区(DataRegion)使用的共识协议类。 +5. **SchemaRegionConsensusProtocolClass**:元数据分区(SchemaRegion)使用的共识协议类。 +6. **ConfigNodeConsensusProtocolClass**:配置节点(ConfigNode)使用的共识协议类。 +7. **TimePartitionOrigin**:数据库时间分区的起始时间戳。 +8. **TimePartitionInterval**:数据库的时间分区间隔(单位:毫秒)。 +9. **ReadConsistencyLevel**:读取操作的一致性级别。 +10. **SchemaRegionPerDataNode**:数据节点(DataNode)上的元数据分区(SchemaRegion)数量。 +11. **DataRegionPerDataNode**:数据节点(DataNode)上的数据分区(DataRegion)数量。 +12. **SeriesSlotNum**:数据分区(DataRegion)的序列槽(SeriesSlot)数量。 +13. **SeriesSlotExecutorClass**:序列槽的实现类。 +14. **DiskSpaceWarningThreshold**:磁盘空间告警阈值(单位:百分比)。 +15. **TimestampPrecision**:时间戳精度。 + +#### 示例: + +```SQL +IoTDB> SHOW VARIABLES +``` + +执行结果如下: + +```SQL ++----------------------------------+-----------------------------------------------------------------+ +| Variable| Value| ++----------------------------------+-----------------------------------------------------------------+ +| ClusterName| defaultCluster| +| DataReplicationFactor| 1| +| SchemaReplicationFactor| 1| +| DataRegionConsensusProtocolClass| org.apache.iotdb.consensus.iot.IoTConsensus| +|SchemaRegionConsensusProtocolClass| org.apache.iotdb.consensus.ratis.RatisConsensus| +| ConfigNodeConsensusProtocolClass| org.apache.iotdb.consensus.ratis.RatisConsensus| +| TimePartitionOrigin| 0| +| TimePartitionInterval| 604800000| +| ReadConsistencyLevel| strong| +| SchemaRegionPerDataNode| 1| +| DataRegionPerDataNode| 0| +| SeriesSlotNum| 1000| +| SeriesSlotExecutorClass|org.apache.iotdb.commons.partition.executor.hash.BKDRHashExecutor| +| DiskSpaceWarningThreshold| 0.05| +| TimestampPrecision| ms| ++----------------------------------+-----------------------------------------------------------------+ +``` + +### 1.6 查看集群ID + +**含义**:返回当前集群的ID。 + +#### 语法: + +```SQL +showClusterIdStatement + : SHOW (CLUSTERID | CLUSTER_ID) + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CLUSTER_ID +``` + +执行结果如下: + +```SQL ++------------------------------------+ +| ClusterId| ++------------------------------------+ +|40163007-9ec1-4455-aa36-8055d740fcda| +``` + +### 1.7 查看客户端直连的 DataNode 进程所在服务器的时间 + +#### 语法: + +**含义**:返回当前客户端直连的 DataNode 进程所在服务器的时间。 + +```SQL +showCurrentTimestampStatement + : SHOW CURRENT_TIMESTAMP + ; +``` + +#### 示例: + +```SQL +IoTDB> SHOW CURRENT_TIMESTAMP +``` + +执行结果如下: + +```SQL ++-----------------------------+ +| CurrentTimestamp| ++-----------------------------+ +|2025-02-17T11:11:52.987+08:00| ++-----------------------------+ +``` + +### 1.8 查看正在执行的查询信息 + +**含义**:用于显示所有正在执行的查询信息。 + +#### 语法: + +```SQL +showQueriesStatement + : SHOW (QUERIES | QUERY PROCESSLIST) + (WHERE where=booleanExpression)? + (ORDER BY sortItem (',' sortItem)*)? + limitOffsetClause + ; +``` + +**参数解释**: + +1. **WHERE** 子句:需保证过滤的目标列是结果集中存在的列 +2. **ORDER BY** 子句:需保证`sortKey`是结果集中存在的列 +3. **limitOffsetClause**: + - **含义**:用于限制结果集的返回数量。 + - **格式**:`LIMIT , `, `` 是偏移量,`` 是返回的行数。 +4. **QUERIES** 表中的列: + - **query_id**:查询语句的 ID + - **start_time**:查询开始的时间戳,时间戳精度与系统精度一致 + - **datanode_id**:发起查询语句的 DataNode 的ID + - **elapsed_time**:查询的执行耗时,单位是秒 + - **statement**:查询的 SQL 语句 + - **user**:发起查询的用户 + +#### 示例: + +```SQL +IoTDB> SHOW QUERIES WHERE elapsed_time > 30 +``` + +执行结果如下: + +```SQL ++-----------------------+-----------------------------+-----------+------------+------------+----+ +| query_id| start_time|datanode_id|elapsed_time| statement|user| ++-----------------------+-----------------------------+-----------+------------+------------+----+ +|20250108_101015_00000_1|2025-01-08T18:10:15.935+08:00| 1| 32.283|show queries|root| ++-----------------------+-----------------------------+-----------+------------+------------+----+ +``` + +## 2 状态设置 + +### 2.1 设置连接的模型 + +**含义**:将当前连接的 sql_dialect 置为树模型/表模型。 + +#### 语法: + +```SQL +SET SQL_DIALECT EQ (TABLE | TREE) +``` + +#### 示例: + +```SQL +IoTDB> SET SQL_DIALECT=TABLE +IoTDB> SHOW CURRENT_SQL_DIALECT +``` + +执行结果如下: + +```SQL ++-----------------+ +|CurrentSqlDialect| ++-----------------+ +| TABLE| ++-----------------+ +``` + +### 2.2 更新配置项 + +**含义**:用于更新配置项,执行完成后会进行配置项的热加载,对于支持热修改的配置项会立即生效。 + +#### 语法: + +```SQL +setConfigurationStatement + : SET CONFIGURATION propertyAssignments (ON INTEGER_VALUE)? + ; + +propertyAssignments + : property (',' property)* + ; + +property + : identifier EQ propertyValue + ; + +propertyValue + : DEFAULT + | expression + ; +``` + +**参数解释**: + +1. **propertyAssignments** + - **含义**:更新的配置列表,由多个 `property` 组成。 + - 可以更新多个配置列表,用逗号分隔。 + - **取值**: + - `DEFAULT`:将配置项恢复为默认值。 + - `expression`:具体的值,必须是一个字符串。 +2. **ON INTEGER_VALUE** + - **含义**:指定要更新配置的节点 ID。 + - **可选性**:可选。如果不指定或指定的值低于 0,则更新所有 ConfigNode 和 DataNode 的配置。 + +#### 示例: + +```SQL +IoTDB> SET CONFIGURATION "a"='1',b='1' ON 1; +``` + +### 2.3 读取手动修改的配置文件 + +**含义**:用于读取手动修改过的配置文件,并对配置项进行热加载,对于支持热修改的配置项会立即生效。 + +#### 语法: + +```SQL +loadConfigurationStatement + : LOAD CONFIGURATION localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **localOrClusterMode** + - **含义**:指定配置热加载的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:只对客户端直连的 DataNode 进行配置热加载。 + - `ON CLUSTER`:对集群中所有 DataNode 进行配置热加载。 + +#### 示例: + +```SQL +IoTDB> LOAD CONFIGURATION ON LOCAL; +``` + +### 2.4 设置系统的状态 + +**含义**:用于设置系统的状态。 + +#### 语法: + +```SQL +setSystemStatusStatement + : SET SYSTEM TO (READONLY | RUNNING) localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **RUNNING | READONLY** + - **含义**:指定系统的新状态。 + - **取值**: + - `RUNNING`:将系统设置为运行状态,允许读写操作。 + - `READONLY`:将系统设置为只读状态,只允许读取操作,禁止写入操作。 +2. **localOrClusterMode** + - **含义**:指定状态变更的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:仅对客户端直连的 DataNode 生效。 + - `ON CLUSTER`:对集群中所有 DataNode 生效。 + +#### 示例: + +```SQL +IoTDB> SET SYSTEM TO READONLY ON CLUSTER; +``` + + +## 3 数据管理 + +### 3.1 刷写内存表中的数据到磁盘 + +**含义**:将内存表中的数据刷写到磁盘上。 + +#### 语法: + +```SQL +flushStatement + : FLUSH identifier? (',' identifier)* booleanValue? localOrClusterMode? + ; + +booleanValue + : TRUE | FALSE + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **identifier** + - **含义**:指定要刷写的数据库名称。 + - **可选性**:可选。如果不指定,则默认刷写所有数据库。 + - **多个数据库**:可以指定多个数据库名称,用逗号分隔。例如:`FLUSH test_db1, test_db2`。 +2. **booleanValue** + - **含义**:指定刷写的内容。 + - **可选性**:可选。如果不指定,则默认刷写顺序和乱序空间的内存。 + - **取值**: + - `TRUE`:只刷写顺序空间的内存表。 + - `FALSE`:只刷写乱序空间的MemTable。 +3. **localOrClusterMode** + - **含义**:指定刷写的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:只刷写客户端直连的 DataNode 上的内存表。 + - `ON CLUSTER`:刷写集群中所有 DataNode 上的内存表。 + +#### 示例: + +```SQL +IoTDB> FLUSH test_db TRUE ON LOCAL; +``` + +### 3.2 清除 DataNode 上的缓存 + +**含义**:用于清除 DataNode 上的某种类型的缓存。 + +#### 语法: + +```SQL +clearCacheStatement + : CLEAR clearCacheOptions? CACHE localOrClusterMode? + ; + +clearCacheOptions + : ATTRIBUTE + | QUERY + | ALL + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **clearCacheOptions** + - **含义**:指定要清除的缓存类型。 + - **可选性**:可选。如果不指定,默认清除查询缓存(`QUERY`)。 + - **取值**: + - `ATTRIBUTE`:清除设备属性缓存。 + - `QUERY`:清除存储引擎中的查询缓存。 + - `ALL`:清除所有缓存,包括设备属性缓存、查询缓存以及树模型中的模式缓存。 +2. **localOrClusterMode** + - **含义**:指定清除缓存的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:只清除客户端直连的 DataNode 上的缓存。 + - `ON CLUSTER`:清除集群中所有 DataNode 上的缓存。 + +#### 示例: + +```SQL +IoTDB> CLEAR ALL CACHE ON LOCAL; +``` + +## 4 数据修复 + +### 4.1 启动后台扫描并修复 tsfile 任务 + +**含义**:启动一个后台任务,开始扫描并修复 tsfile,能够修复数据文件内的时间戳乱序类异常。 + +#### 语法: + +```SQL +startRepairDataStatement + : START REPAIR DATA localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **localOrClusterMode** + - **含义**:指定数据修复的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:仅对客户端直连的 DataNode 执行。 + - `ON CLUSTER`:对集群中所有 DataNode 执行。 + +#### 示例: + +```SQL +IoTDB> START REPAIR DATA ON CLUSTER; +``` + +### 4.2 暂停后台修复 tsfile 任务 + +**含义**:暂停后台的修复任务,暂停中的任务可通过再次执行 start repair data 命令恢复。 + +#### 语法: + +```SQL +stopRepairDataStatement + : STOP REPAIR DATA localOrClusterMode? + ; + +localOrClusterMode + : (ON (LOCAL | CLUSTER)) + ; +``` + +**参数解释**: + +1. **localOrClusterMode** + - **含义**:指定数据修复的范围。 + - **可选性**:可选。默认值为 `CLUSTER`。 + - **取值**: + - `ON LOCAL`:仅对客户端直连的 DataNode 执行。 + - `ON CLUSTER`:对集群中所有 DataNode 执行。 + +#### 示例: + +```SQL +IoTDB> STOP REPAIR DATA ON CLUSTER; +``` + +## 5 终止查询 + +### 5.1 主动终止查询 + +**含义**:使用该命令主动地终止查询。 + +#### 语法: + +```SQL +killQueryStatement + : KILL (QUERY queryId=string | ALL QUERIES) + ; +``` + +**参数解释**: + +1. **QUERY queryId=string** + - **含义**:指定要终止的查询的 ID。 `` 是正在执行的查询的唯一标识符。 + - **获取查询 ID**:可以通过 `SHOW QUERIES` 命令获取所有正在执行的查询及其 ID。 +2. **ALL QUERIES** + - **含义**:终止所有正在执行的查询。 + +#### 示例: + +通过指定 `queryId` 可以中止指定的查询,为了获取正在执行的查询 id,用户可以使用 show queries 命令,该命令将显示所有正在执行的查询列表。 + +```SQL +IoTDB> KILL QUERY 20250108_101015_00000_1; -- 终止指定query +IoTDB> KILL ALL QUERIES; -- 终止所有query +``` \ No newline at end of file diff --git a/src/zh/UserGuide/latest-Table/User-Manual/Query-Performance-Analysis.md b/src/zh/UserGuide/latest-Table/User-Manual/Query-Performance-Analysis.md new file mode 100644 index 000000000..b577983a8 --- /dev/null +++ b/src/zh/UserGuide/latest-Table/User-Manual/Query-Performance-Analysis.md @@ -0,0 +1,335 @@ + +# 系统运维 + +## 查询性能分析 + +查询分析的意义在于帮助用户理解查询的执行机制和性能瓶颈,从而实现查询优化和性能提升。这不仅关乎到查询的执行效率,也直接影响到应用的用户体验和资源的有效利用。为了进行有效的查询分析,IoTDB 提供了查询分析语句:Explain 和 Explain Analyze。 + +- Explain 语句:允许用户预览查询 SQL 的执行计划,包括 IoTDB 如何组织数据检索和处理。 +- Explain Analyze 语句:在 Explain 语句基础上增加了性能分析,完整执行 SQL 并展示查询执行过程中的时间和资源消耗。为 IoTDB 用户深入理解查询详情以及进行查询优化提供了详细的相关信息。与其他常用的 IoTDB 排查手段相比,Explain Analyze 没有部署负担,同时能够针对单条 sql 进行分析,能够更好定位问题。各类方法对比如下:: + +| 方法 | 安装难度 | 业务影响 | 功能范围 | +| ------------------- | ------------------------------------------------------------ | ---------------------------------------------------- | ------------------------------------------------------ | +| Explain Analyze语句 | 低。无需安装额外组件,为IoTDB内置SQL语句 | 低。只会影响当前分析的单条查询,对线上其他负载无影响 | 支持分布式,可支持对单条SQL进行追踪 | +| 监控面板 | 中。需要安装IoTDB监控面板工具(企业版工具),并开启IoTDB监控服务 | 中。IoTDB监控服务记录指标会带来额外耗时 | 支持分布式,仅支持对数据库整体查询负载和耗时进行分析 | +| Arthas抽样 | 中。需要安装Java Arthas工具(部分内网无法直接安装Arthas,且安装后,有时需要重启应用) | 高。CPU 抽样可能会影响线上业务的响应速度 | 不支持分布式,仅支持对数据库整体查询负载和耗时进行分析 | + +### Explain 语句 + +#### 语法 + +Explain命令允许用户查看SQL查询的执行计划。执行计划以算子的形式展示,描述了IoTDB会如何执行查询。其语法如下,其中SELECT_STATEMENT是查询相关的SQL语句: + +```SQL +EXPLAIN +``` +#### 含义 + +```SQL +-- 创建数据库 +create database test; + +-- 创建表 +use test; +create table t1 (device_id STRING ID, type STRING ATTRIBUTE, speed float); + +-- 插入数据 +insert into t1(device_id, type, speed) values('car_1', 'Model Y', 120.0); +insert into t1(device_id, type, speed) values('car_2', 'Model 3', 100.0); + +-- 执行 explain 语句 +explain select * from t1; +``` +执行上方SQL,会得到如下结果。不难看出,IoTDB 分别通过两个 TableScan 节点去不同的数据分区中获取表中的数据,最后通过Collect 算子汇总数据后返回。 + +```SQL ++-----------------------------------------------------------------------------------------------+ +| distribution plan| ++-----------------------------------------------------------------------------------------------+ +| ┌─────────────────────────────────────────────┐ | +| │OutputNode-4 │ | +| │OutputColumns-[time, device_id, type, speed] │ | +| │OutputSymbols: [time, device_id, type, speed]│ | +| └─────────────────────────────────────────────┘ | +| │ | +| │ | +| ┌─────────────────────────────────────────────┐ | +| │Collect-21 │ | +| │OutputSymbols: [time, device_id, type, speed]│ | +| └─────────────────────────────────────────────┘ | +| ┌───────────────────────┴───────────────────────┐ | +| │ │ | +|┌─────────────────────────────────────────────┐ ┌───────────┐ | +|│TableScan-19 │ │Exchange-28│ | +|│QualifiedTableName: test.t1 │ └───────────┘ | +|│OutputSymbols: [time, device_id, type, speed]│ │ | +|│DeviceNumber: 1 │ │ | +|│ScanOrder: ASC │ ┌─────────────────────────────────────────────┐| +|│PushDownOffset: 0 │ │TableScan-20 │| +|│PushDownLimit: 0 │ │QualifiedTableName: test.t1 │| +|│PushDownLimitToEachDevice: false │ │OutputSymbols: [time, device_id, type, speed]│| +|│RegionId: 2 │ │DeviceNumber: 1 │| +|└─────────────────────────────────────────────┘ │ScanOrder: ASC │| +| │PushDownOffset: 0 │| +| │PushDownLimit: 0 │| +| │PushDownLimitToEachDevice: false │| +| │RegionId: 1 │| +| └─────────────────────────────────────────────┘| ++-----------------------------------------------------------------------------------------------+ +``` + + +### Explain Analyze 语句 + +#### 语法 + +```SQL +EXPLAIN ANALYZE [VERBOSE] +``` + +其中 SELECT_STATEMENT 对应需要分析的查询语句;VERBOSE为打印详细分析结果,不填写VERBOSE时EXPLAIN ANALYZE将会省略部分信息。 + +#### 含义 + +Explain Analyze 是 IOTDB 查询引擎自带的性能分析 SQL,与 Explain 不同,它会执行对应的查询计划并统计执行信息,可以用于追踪一条查询的具体性能分布,用于对资源进行观察,进行性能调优与异常分析。 + +在 EXPLAIN ANALYZE 的结果集中,会包含如下信息: + +![explain-analyze-1.png](/img/explain-analyze-1.png) + +其中: + +- QueryStatistics 包含查询层面进的统计信息,主要包含各规划阶段耗时,查询分片数量等信息。 + - Analyze Cost: SQL 分析阶段的耗时(包含 FetchPartitionCost 和 FetchSchemaCost) + - Fetch Partition Cost:拉取分区表的耗时 + - Fetch Schema Cost:拉取元数据以及权限校验的耗时 + - Logical Plan Cost:构建逻辑计划的耗时 + - Logical Optimization Cost: 逻辑计划优化的耗时 + - Distribution Plan Cost:构建分布式计划的耗时 + - Fragment Instance Count:总的查询分片的数量,每个查询分片的信息会挨个输出 +- FragmentInstance 是 IoTDB 一个查询分片的封装,每一个查询分片都会在结果集中输出一份分片的执行信息,主要包含 FragmentStatistics 和算子信息。FragmentStastistics 包含 Fragment 的统计信息,包括总实际耗时(墙上时间),所涉及到的 TsFile,调度信息等情况。在一个 Fragment 的信息输出同时会以节点树层级的方式展示该Fragment 下计划节点的统计信息,主要包括:CPU运行时间、输出的数据行数、指定接口被调用的次数、所占用的内存、节点专属的定制信息。 + - Total Wall Time: 该分片从开始执行到执行结束的物理时间 + - Cost of initDataQuerySource:构建查询文件列表 + - Seq File(unclosed): 未封口(memtable)的顺序文件数量, Seq File(closed): 封口的顺序文件数量 + - UnSeq File(unclosed): 未封口(memtable)的乱序文件数量, UnSeq File(closed): 未封口的乱序文件数量 + - ready queued time: 查询分片的所有task在 ready queue 中的总时长(task 未阻塞,但没有查询执行线程资源时,会被放入ready queue),blocked queued time: 查询分片的所有task在 bloced queue 中的总时长(task 因为某些资源,如内存,或者上游数据未发送过来,则会被放入blocked queue) + - BloomFilter 相关(用于判断某个序列在tsfile中是否存在,存储于tsfile尾部) + - loadBloomFilterFromCacheCount: 命中BloomFilterCache的次数 + - loadBloomFilterFromDiskCount: 从磁盘中读取的次数 + - loadBloomFilterActualIOSize: 从磁盘中读取BloomFilter时耗费的磁盘IO(单位为bytes) + - loadBloomFilterTime: 读取BloomFilter + 计算序列是否存在的总耗时(单位为ms) + - TimeSeriesMetadata 相关(序列在tsfile中的索引信息,一个序列在一个tsfile中只会存储一个) + - loadTimeSeriesMetadataDiskSeqCount: 从封口的顺序文件里加载出的TimeSeriesMetadata数量 + - 大部分情况下等于Seq File(closed),但如果有limit等算子,可能实际加载的数量会小于Seq File(closed) + - loadTimeSeriesMetadataDiskUnSeqCount: 从封口的乱序文件里加载出的TimeSeriesMetadata数量 + - 大部分情况下等于UnSeq File(closed),但如果有limit等算子,可能实际加载的数量会小于UnSeq File(closed) + - loadTimeSeriesMetadataDiskSeqTime: 从封口的顺序文件里加载TimeSeriesMetadata的耗时 + - 并不是所有的 TimeSeriesMetadata 加载都涉及磁盘 IO,有可能会命中TimeSeriesMetadataCache,直接从缓存中读取,但输出信息里并没有分开统计这两者的耗时 + - loadTimeSeriesMetadataDiskUnSeqTime: 从未封口的顺序文件里加载TimeSeriesMetadata的耗时 + - loadTimeSeriesMetadataFromCacheCount: 命中TimeSeriesMetadataCache的次数,注意这里对于对齐设备来讲,每个分量(包括time列,都会去单独请求Cache,所以对于对齐设备来讲,(loadTimeSeriesMetadataFromCacheCount + loadTimeSeriesMetadataFromDiskCount)= tsfile number * subSensor number(包括time列) + - loadTimeSeriesMetadataFromDiskCount: 从磁盘中读取TimeSeriesMetadata的次数,一次读取会把该设备下查询所有涉及到的分量都读出来缓存在TimeSeriesMetadataCache中 + - loadTimeSeriesMetadataActualIOSize: 从磁盘中读取TimeSeriesMetadata时耗费的磁盘IO(单位为bytes) + - Mods 文件相关 + - TimeSeriesMetadataModificationTime: 读取mods文件花费的时间 + - Chunk 相关 + - constructAlignedChunkReadersDiskCount: 读取已封口 tsfile 中总的 Chunk 数量 + - constructAlignedChunkReadersDiskTime: 读取已封口 tsfile 中 Chunk 的总耗时(包含磁盘IO和解压缩) + - pageReadersDecodeAlignedDiskCount: 解编码已封口 tsfile 中总的 page 数量 + - pageReadersDecodeAlignedDiskTime: 解编码已封口 tsfile 中 page 的总耗时 + - loadChunkFromCacheCount: 命中ChunkCache的次数,注意这里对于对齐设备来讲,每个分量(包括time列,都会去单独请求Cache,所以对于对齐设备来讲,(loadChunkFromCacheCount + loadChunkFromDiskCount)= tsfile number * subSensor number(包括time列)* avg chunk number in each tsfile + - loadChunkFromDiskCount: 从磁盘中读取Chunk的次数,一次只会读取一个分量,并缓存在ChunkCache中 + - loadChunkActualIOSize: 从磁盘中读取Chunk时耗费的磁盘IO(单位为bytes) + + +##### 特别说明 + +查询超时场景使用 Explain Analyze 语句: + +Explain Analyze 本身是一种特殊的查询,所以当执行超时的时候,Explain Analyze 语句也无法正常返回结果。为了在查询超时的情况下也可以通过分析结果排查超时原因,Explain Analyze 提供了定时日志机制(无需用户配置),每经过一定的时间间隔会将 Explain Analyze 的当前结果以文本的形式输出到专门的日志中。当查询超时时,用户可以前往logs/log_explain_analyze.log中查看对应的日志进行排查。 +日志的时间间隔基于查询的超时时间进行计算,可以保证在超时的情况下至少会有两次的结果记录。 + +##### 示例 + +下面是Explain Analyze的一个例子: + +```SQL +-- 创建数据库 +create database test; + +-- 创建表 +use test; +create table t1 (device_id STRING ID, type STRING ATTRIBUTE, speed float); + +-- 插入数据 +insert into t1(device_id, type, speed) values('car_1', 'Model Y', 120.0); +insert into t1(device_id, type, speed) values('car_2', 'Model 3', 100.0); + +-- 执行 explain analyze 语句 +explain analyze verbose select * from t1; +``` + +得到输出如下: + +```SQL ++-----------------------------------------------------------------------------------------------+ +| Explain Analyze| ++-----------------------------------------------------------------------------------------------+ +|Analyze Cost: 38.860 ms | +|Fetch Partition Cost: 9.888 ms | +|Fetch Schema Cost: 54.046 ms | +|Logical Plan Cost: 10.102 ms | +|Logical Optimization Cost: 17.396 ms | +|Distribution Plan Cost: 2.508 ms | +|Dispatch Cost: 22.126 ms | +|Fragment Instances Count: 2 | +| | +|FRAGMENT-INSTANCE[Id: 20241127_090849_00009_1.2.0][IP: 0.0.0.0][DataRegion: 2][State: FINISHED]| +| Total Wall Time: 18 ms | +| Cost of initDataQuerySource: 6.153 ms | +| Seq File(unclosed): 1, Seq File(closed): 0 | +| UnSeq File(unclosed): 0, UnSeq File(closed): 0 | +| ready queued time: 0.164 ms, blocked queued time: 0.342 ms | +| Query Statistics: | +| loadBloomFilterFromCacheCount: 0 | +| loadBloomFilterFromDiskCount: 0 | +| loadBloomFilterActualIOSize: 0 | +| loadBloomFilterTime: 0.000 | +| loadTimeSeriesMetadataAlignedMemSeqCount: 1 | +| loadTimeSeriesMetadataAlignedMemSeqTime: 0.246 | +| loadTimeSeriesMetadataFromCacheCount: 0 | +| loadTimeSeriesMetadataFromDiskCount: 0 | +| loadTimeSeriesMetadataActualIOSize: 0 | +| constructAlignedChunkReadersMemCount: 1 | +| constructAlignedChunkReadersMemTime: 0.294 | +| loadChunkFromCacheCount: 0 | +| loadChunkFromDiskCount: 0 | +| loadChunkActualIOSize: 0 | +| pageReadersDecodeAlignedMemCount: 1 | +| pageReadersDecodeAlignedMemTime: 0.047 | +| [PlanNodeId 43]: IdentitySinkNode(IdentitySinkOperator) | +| CPU Time: 5.523 ms | +| output: 2 rows | +| HasNext() Called Count: 6 | +| Next() Called Count: 5 | +| Estimated Memory Size: : 327680 | +| [PlanNodeId 31]: CollectNode(CollectOperator) | +| CPU Time: 5.512 ms | +| output: 2 rows | +| HasNext() Called Count: 6 | +| Next() Called Count: 5 | +| Estimated Memory Size: : 327680 | +| [PlanNodeId 29]: TableScanNode(TableScanOperator) | +| CPU Time: 5.439 ms | +| output: 1 rows | +| HasNext() Called Count: 3 +| Next() Called Count: 2 | +| Estimated Memory Size: : 327680 | +| DeviceNumber: 1 | +| CurrentDeviceIndex: 0 | +| [PlanNodeId 40]: ExchangeNode(ExchangeOperator) | +| CPU Time: 0.053 ms | +| output: 1 rows | +| HasNext() Called Count: 2 | +| Next() Called Count: 1 | +| Estimated Memory Size: : 131072 | +| | +|FRAGMENT-INSTANCE[Id: 20241127_090849_00009_1.3.0][IP: 0.0.0.0][DataRegion: 1][State: FINISHED]| +| Total Wall Time: 13 ms | +| Cost of initDataQuerySource: 5.725 ms | +| Seq File(unclosed): 1, Seq File(closed): 0 | +| UnSeq File(unclosed): 0, UnSeq File(closed): 0 | +| ready queued time: 0.118 ms, blocked queued time: 5.844 ms | +| Query Statistics: | +| loadBloomFilterFromCacheCount: 0 | +| loadBloomFilterFromDiskCount: 0 | +| loadBloomFilterActualIOSize: 0 | +| loadBloomFilterTime: 0.000 | +| loadTimeSeriesMetadataAlignedMemSeqCount: 1 | +| loadTimeSeriesMetadataAlignedMemSeqTime: 0.004 | +| loadTimeSeriesMetadataFromCacheCount: 0 | +| loadTimeSeriesMetadataFromDiskCount: 0 | +| loadTimeSeriesMetadataActualIOSize: 0 | +| constructAlignedChunkReadersMemCount: 1 | +| constructAlignedChunkReadersMemTime: 0.001 | +| loadChunkFromCacheCount: 0 | +| loadChunkFromDiskCount: 0 | +| loadChunkActualIOSize: 0 | +| pageReadersDecodeAlignedMemCount: 1 | +| pageReadersDecodeAlignedMemTime: 0.007 | +| [PlanNodeId 42]: IdentitySinkNode(IdentitySinkOperator) | +| CPU Time: 0.270 ms | +| output: 1 rows | +| HasNext() Called Count: 3 | +| Next() Called Count: 2 | +| Estimated Memory Size: : 327680 | +| [PlanNodeId 30]: TableScanNode(TableScanOperator) | +| CPU Time: 0.250 ms | +| output: 1 rows | +| HasNext() Called Count: 3 | +| Next() Called Count: 2 | +| Estimated Memory Size: : 327680 | +| DeviceNumber: 1 | +| CurrentDeviceIndex: 0 | ++-----------------------------------------------------------------------------------------------+ +``` + +### 常见问题 + +#### 1. WALL TIME(墙上时间)和 CPU TIME(CPU时间)的区别? + +CPU 时间也称为处理器时间或处理器使用时间,指的是程序在执行过程中实际占用 CPU 进行计算的时间,显示的是程序实际消耗的处理器资源。 + +墙上时间也称为实际时间或物理时间,指的是从程序开始执行到程序结束的总时间,包括了所有等待时间。。 + +1. WALL TIME < CPU TIME 的场景:比如一个查询分片最后被调度器使用两个线程并行执行,真实物理世界上是 10s 过去了,但两个线程,可能一直占了两个 cpu 核跑了 10s,那 cpu time 就是 20s,wall time就是 10s +2. WALL TIME > CPU TIME 的场景:因为系统内可能会存在多个查询并行执行,但查询的执行线程数和内存是固定的, + 1. 所以当查询分片被某些资源阻塞住时(比如没有足够的内存进行数据传输、或等待上游数据)就会放入Blocked Queue,此时查询分片并不会占用 CPU TIME,但WALL TIME(真实物理时间的时间)是在向前流逝的 + 2. 或者当查询线程资源不足时,比如当前共有16个查询线程,但系统内并发有20个查询分片,即使所有查询都没有被阻塞,也只会同时并行运行16个查询分片,另外四个会被放入 READY QUEUE,等待被调度执行,此时查询分片并不会占用 CPU TIME,但WALL TIME(真实物理时间的时间)是在向前流逝的 + + +#### 2. Explain Analyze 是否有额外开销,测出的耗时是否与查询真实执行时有差别? + +几乎没有,因为 explain analyze operator 是单独的线程执行,收集原查询的统计信息,且这些统计信息,即使不explain analyze,原来的查询也会生成,只是没有人去取。并且 explain analyze 是纯 next 遍历结果集,不会打印,所以与原来查询真实执行时的耗时不会有显著差别。 + +#### 3. IO 耗时主要关注几个指标? + +涉及 IO 耗时的指标主要有:loadBloomFilterActualIOSize, loadBloomFilterTime, loadTimeSeriesMetadataAlignedDisk[Seq/Unseq]Time, loadTimeSeriesMetadataActualIOSize, alignedTimeSeriesMetadataModificationTime, constructAlignedChunkReadersDiskTime, loadChunkActualIOSize,各指标的具体含义见上文。 +TimeSeriesMetadata 的加载分别统计了顺序和乱序文件,但 Chunk 的读取暂时未分开统计,但顺乱序比例可以通过TimeseriesMetadata 顺乱序的比例计算出来。 + + +#### 4. 乱序数据对查询性能的影响能否有一些指标展示出来? + +乱序数据产生的影响主要有两个: + +1. 需要在内存中多做一个归并排序(一般认为这个耗时是比较短的,毕竟是纯内存的 cpu 操作) +2. 乱序数据会产生数据块间的时间范围重叠,导致统计信息无法使用 + 1. 无法利用统计信息直接 skip 掉整个不满足值过滤要求的 chunk + 1. 一般用户的查询都是只包含时间过滤条件,则不会有影响 + 2. 无法利用统计信息直接计算出聚合值,无需读取数据 + +单独对于乱序数据的性能影响,目前并没有有效的观测手段,除非就是在有乱序数据的时候,执行一遍查询耗时,然后等乱序合完了,再执行一遍,才能对比出来。 + +因为即使乱序这部分数据进了顺序,也是需要 IO、加压缩、decode,这个耗时少不了,不会因为乱序数据被合并进乱序了,就减少了。 + +#### 5. 执行 explain analyze 时,查询超时后,为什么结果没有输出在 log_explain_analyze.log 中? + +升级时,只替换了 lib 包,没有替换 conf/logback-datanode.xml,需要替换一下 conf/logback-datanode.xml,然后不需要重启(该文件内容可以被热加载),大约等待 1 分钟后,重新执行 explain analyze verbose。