本文汇总了云数据库ClickHouse的常见问题及解决方案。

云数据库ClickHouse和官方版本对比多了哪些功能和特性?

云数据库ClickHouse主要对社区版本进行稳定性Bug修复,同时提供特有的内核特性:
  • 资源队列进行用户角色级别的资源使用优先级配置。
  • 二级索引支持日志明细类点查询场景。

购买云数据库ClickHouse实例时,推荐选择哪一个版本?

云数据库ClickHouse根据开源社区公开的LTS内核稳定版提供服务,通常在版本推出3个月相对稳定后启动云服务售卖。当前建议购买20.8及以上版本。更多版本功能对比,请参见内核版本功能对比

单双副本实例各有什么特点?

  • 单副本实例每一个Shard节点无副本节点,无高可用服务保障。数据安全性基于云盘多副本存储,性价比高。
  • 双副本实例每一个Shard节点对应一个副本服务节点,在主节点故障不能提供服务时副本节点可提供容灾服务支持。

购买链路资源时显示“当前区域资源不足”,应该如何处理?

解决方案:您可以选择同地域的其他区域购买或提交工单。VPC网络支持相同区域不同可用区之间打通,同区域网络延迟无感知。

水平扩缩容耗时受什么影响?

水平扩缩容过程涉及数据搬迁,实例里面数据越多搬得越多,耗时时间越长。

扩缩容期间对实例有什么影响?

为保证扩缩容中数据搬迁后的数据一致性,扩缩容期间实例处于可读不可写状态。

水平扩缩容升级有什么建议?

水平扩缩容耗时较长,当集群性能不满足时,请优先选择垂直升配。如何进行垂直升配,请参见社区兼容版变配和扩缩容

每个端口的含义是什么?

社区兼容版

端口号 含义
3306 TCP端口。
8123 HTTP端口。
9004 MySQL端口。
8443 HTTPS端口。

云原生版

端口号 含义
9000 TCP端口。
8123 HTTP端口。
9004 MySQL端口。

每个Driver对应的端口是什么?

Driver名称 端口号
Java 8123
Python 3306
Go

Go、Python语言对应推荐什么Driver?

详情请参见第三方开发库

如何处理客户端工具连接集群时报错:connect timed out?

您可以采取如下解决方案。
  • 检查网络是否畅通。通过ping命令检查网络是否通畅,通过telnet命令探测数据库3306和8123端口是否开放。
  • 检查是否配置了ClickHouse白名单,配置方法请参见 设置白名单
  • 检查客户端机器IP是否正确。通常公司办公网内的机器IP经常变动,用户看到的不是正确的IP地址。通过访问专业IP探查服务确定真实IP,示例请参见whatsmyip

为什么MySQL、HDFS、Kafka等外表无法连通?

目前20.3和20.8版本在创建相关外表时程序内会自动进行验证,如果创建表成功,那说明网络是通的。如果无法创建成功,常见原因如下。
  • 目标端和ClickHouse不在同一个VPC内,网络无法连通。
  • MySQL端存在白名单相关设置,需要在MySQL端添加ClickHouse的白名单。

对于Kafka外表,表创建成功,但查询没有结果。常见原因是Kafka中数据通过表结构给出的字段和格式解析失败,报错信息会给出解析失败的具体位置。

为什么程序无法连接ClickHouse?

常见原因如下。
  • VPC网络、公网网络环境不对。同一VPC内可用内网连接,不在同一VPC内需开设公网后连接。
  • 白名单未配置。
  • ECS安全组未放开。
  • 公司设置了网络防火墙。

如何处理ClickHouse超时问题?

详情请参见如何处理ClickHouse超时问题

为什么OSS外表导入ORC、PARQUET等格式的数据,出现内存报错或OOM挂掉?

常见原因:内存使用率比较高。

您可以采取如下解决方案。

如何处理导入数据报错:too many parts?

ClickHouse每次写入都会生成一个data part,如果每次写入一条或者少量的数据,那会造成ClickHouse内部有大量的data part(会给merge和查询造成很大的负担)。为了防止出现大量的data part,ClickHouse内部做了很多限制,这就是too many parts报错的内在原因。出现该错误,第一要做的事情就是增加写入的批量大小。如果确实没有办法调整批量大小,可以适当的修改参数:max_partitions_per_insert_block,将参数的取值设置的小一些。

为什么DataX导入速度慢?

常见原因及解决方案如下。
  • 常见原因1:参数设置不合理。ClickHouse适合使用大batch、少数几个并发进行写入。多数情况下batch可以高达几万甚至几十万(取决于您的单行RowSize大小,一般按照每行100Byte进行评估,您需要根据实际数据特征进行估算)。

    解决方案:并发数建议不超过10个。您可以调整不同参数进行尝试。

  • 常见原因2:DataWorks独享资源组的ECS规格太小。比如独享资源的CPU、Memory太小,导致并发数、网络出口带宽受限;或者是batch设置太大而Memory太小,引起DataWorks进程Java GC等。

    解决方案:您可以通过DataWorks的输出日志对ECS规格大小进行确认。

  • 常见原因3:从数据源中读取慢。

    解决方案:您可以在DataWorks输出日志中搜索totalWaitReaderTime、totalWaitWriterTime,如果发现totalWaitReaderTime明显大于totalWaitWriterTime,则表明主要耗时在读取端,而不是写入端。

  • 常见原因4:使用了公网Endpoint。公网Endpoint的带宽非常有限,无法承载高性能的数据导入导出。

    解决方案:您需要替换为VPC网络的Endpoint。

  • 常见原因5:有脏数据。在没有脏数据的情况下,数据以batch方式写入。但是遇到了脏数据,正在写入的batch就会失败,并回退到逐行写入,生成大量的data part,大幅度降低了写入速度。

    您可以参考如下两种方式判断是否有脏数据。
    • 查看报错信息,如果返回信息包含Cannot parse,则存在脏数据。
      代码如下。
      select written_rows, written_bytes, query_duration_ms, event_time, exception
      from system.query_log
      where event_time between '2021-11-22 22:00:00' and '2021-11-22 23:00:00' and lowerUTF8(query) like '%insert into <table_name>%' and type != 'QueryStart' and exception_code != 0
      order by event_time desc limit 30;
    • 查看batch行数,如果batch行数变为1,则存在脏数据。
      代码如下。
      select written_rows, written_bytes, query_duration_ms, event_time
      from system.query_log
      where event_time between '2021-11-22 22:00:00' and '2021-11-22 23:00:00' and lowerUTF8(query) like '%insert into <table_name>%' and type != 'QueryStart'
      order by event_time desc limit 30;

    解决方案:您需要在数据源删除或修改脏数据。

为什么Hive导入后其数据行数跟ClickHouse对不上?

您可以通过以下手段进行排查。
  1. 首先通过系统表query_log来查看导入的过程中是否有报错,如果有报错,那很有可能出现数据丢失的情况。
  2. 确定使用的表引擎是否可以去重,比如使用ReplacingMergeTree,那很可能出现ClickHouse中的Count小于Hive中的情况。
  3. 重新确认Hive中数据行数的正确性,很有可能出现源头的行数确定错误的情况。

为什么Kafka导入后其数据行数跟ClickHouse对不上?

您可以通过以下手段进行排查。
  1. 确定使用的表引擎是否可以去重,比如使用ReplacingMergeTree,那很可能出现ClickHouse中的Count小于Kafka中的情况。
  2. 查看Kafka外表的配置是否有kafka_skip_broken_messages参数的配置,如果有该参数,那可能会跳过解析失败的Kafka消息,导致ClickHouse总的行数是小于Kafka中的。

如何使用Spark、Flink导入数据?

如何从现有ClickHouse导入数据到云数据库ClickHouse?

您可以采取如下方案。
  • 通过ClickHouse Client以导出文件的形式进行数据迁移,详情请参见从自建ClickHouse迁移上云
  • 通过Remote函数进行数据的迁移。
    insert into <目的表> select * from remote('<连接串>', '<库>', '<表>', '<username>', '<password>');

使用MaterializeMySQL引擎同步MySQL数据时,为什么出现如下报错:The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires

常见原因:MaterializeMySQL引擎停止同步的时间太久,导致MySQL Binlog日志过期被清理掉。

解决方案:删除报错的数据库,重新在云数据库ClickHouse中创建同步的数据库。

使用MaterializeMySQL引擎同步MySQL数据时,为什么出现表停止同步?为什么系统表system.materialize_mysql中sync_failed_tables字段不为空?

常见原因:同步过程中使用了云数据库ClickHouse不支持的MySQL DDL语句。

解决方案:重新同步MySQL数据,具体步骤如下。
  1. 删除停止同步的表。
    drop table <table_name> on cluster default;
    说明 table_name为停止同步的表名。如果停止同步的表有分布式表,那么本地表和分布式表都需要删除。
  2. 重启同步进程。
    alter database <database_name> on cluster default MODIFY SETTING skip_unsupported_tables = 1;
    说明 <database_name>云数据库ClickHouse中同步的数据库。

如何处理insert into select XXX内存超限报错?

常见原因及解决方案如下。
  • 常见原因1:内存使用率比较高。

    解决方案:调整参数max_insert_threads,减少可能的内存使用量。

  • 常见原因2:当前是通过insert into select把数据从一个ClickHouse集群导入到另外一个集群。

    解决方案:通过导入文件的方式来迁移数据,更多信息请参见从自建ClickHouse迁移上云

什么查询耗费的CPU、MEM高?

您可以在system.query_log系统表里自助查看CPU、MEM高期间的查询日志,里面有每个查询的CPU消耗和内存消耗统计。更多信息请参见system.query_log

如何处理查询时内存超出限制?

ClickHouse服务端对所有查询线程都配有memory tracker,同一个查询下的所有线程tracker会汇报给一个memory tracker for query,再上层还是memory tracker for total。您可以根据情况采取如下解决方案。
  • 遇到Memory limit (for query)超限报错说明是查询内存占用过多(实例总内存的70%)导致失败,这种情况下您需要垂直升配提高实例内存规模。
  • 遇到Memory limit (for total)超限报错说明是实例总内存使用超限(实例总内存的90%),这种情况下您可以尝试降低查询并发,如果仍然不行则可能是后台异步任务占用了比较大的内存(常常是写入后主键合并任务),您需要垂直升配提高实例内存规模。

如何处理查询报并发超限?

默认Server查询最大并发数为100,您可以在控制台上进行修改。修改运行参数值具体操作步骤如下。
  1. 登录云数据库ClickHouse控制台
  2. 集群列表页面,选择默认实例列表云原生版本实例列表,单击目标集群ID。
  3. 在集群信息页面单击导航栏左侧的参数配置
  4. 修改max_concurrent_queries参数的运行参数值,输入修改值并单击确定修改参数
  5. 单击提交参数
  6. 单击确定

在数据停止写入时,同一个查询语句每次查询的结果不一致,应该如何处理?

问题详细描述:通过select count(*) 查询数据时只有整体数据的大概一半,或者数据一直在跳变。

您可以采取如下解决方案。
  • 检查是否是多节点集群。多节点集群需要创建分布式表,往分布式表里写入数据并查询,每次查询结果一致。否则每次查询到不同分片的数据,结果不一致。如何创建分布式表请参见创建分布式表
  • 检查是否是多副本集群。多副本集群需要建Replicated系列表引擎的表,才能实现副本间数据同步。否则每次查到不同副本,结果不一致。如何创建Replicated系列表引擎的表请参见表引擎

为什么有时看不到已经创建好的表并且查询结果一直抖动时多时少?

常见原因及解决方案如下。
  • 常见原因1:建表流程存在问题。ClickHouse的分布式集群搭建并没有原生的分布式DDL语义。如果您在自建ClickHouse集群时使用create table创建表,查询虽然返回了成功,但实际这个表只在当前连接的Server上创建了。下次连接重置换一个Server,您就看不到这个表了。

    解决方案:
    1. 建表时,请使用create table <table_name> on cluster default语句,on cluster default声明会把这条语句广播给default集群的所有节点进行执行。示例代码如下。
      Create table test on cluster default (a UInt64) Engine = MergeTree() order by tuple();
    2. 在test表上再创建一个分布式表引擎,建表语句如下。
      Create table test_dis on cluster default as test Engine = Distributed(default, default, test, cityHash64(a));
  • 常见原因2:ReplicatedMergeTree存储表配置有问题。ReplicatedMergeTree表引擎是对应MergeTree表引擎的主备同步增强版,在单副本实例上限定只能创建MergeTree表引擎,在双副本实例上只能创建ReplicatedMergeTree表引擎。

    解决方案:在双副本实例上建表时,请使用ReplicatedMergeTree('/clickhouse/tables/{database}/{table}/{shard}', '{replica}')ReplicatedMergeTree()配置ReplicatedMergeTree表引擎。其中,ReplicatedMergeTree('/clickhouse/tables/{database}/{table}/{shard}', '{replica}')为固定配置,无需修改。

如何处理往表里写入时间戳数据后查询出来的结果与实际数据不同?

SELECT timezone()语句,查看时区是否为当地时区,如果不是修改timezone配置项的值为当地时区。如何修改请参见修改配置项运行参数值

如何处理建表后查询表不存在?

常见原因:DDL语句只在一个节点上执行。

解决方案:检查DDL语句是否有on cluster关键字。更多信息,请参见建表语法

为什么Kafka外表建表后数据不增加?

您可以先对Kafka外表进行select * from的查询,如果查询报错,那可以根据报错信息确定原因(一般是数据解析失败)。如果查询正常返回结果,那需要进一步查看目的表(Kafka外表的具体存储表)和Kafka源表(Kafka外表)的字段是否匹配。如果数据写入失败,那说明字段是匹配不上的。示例语句如下。

insert into <目的表> as select * from <kafka外表>;

为什么客户端看到的时间结果和时区显示的不一样?

客户端设置了use_client_time_zone,并设定在了错误时区上。

为什么数据写入后不可见?

一般原因是分布式表和本地表的表结构不一致造成的。您可以通过查询系统表system.distribution_queue来查看写入分布式表的时候是否发生错误。

为什么optimize任务很慢?

optimize任务非常占用CPU和磁盘吞吐,查询和optimize任务都会相互影响,在机器节点负载压力较大的时候就会表现出optimize很慢问题,目前没有特殊优化方法。

为什么optimize后数据仍未主键合并?

首先为了让数据有正确的主键合并逻辑,需要保证以下两个前提条件。
  • 存储表里的partition by定义字段必须是包含在order by里的,不同分区的数据不会主键合并。
  • 分布式表里定义的Hash算法字段必须是包含在order by里的,不同节点的数据不会主键合并。
optimize常用命令及相关说明如下。
命令 说明
optimize table test; 尝试选取MergeTree的data parts进行合并,有可能没有执行任务就返回。执行了也并不保证全表的记录都完成了主键合并,一般不会使用。
optimize table test partition tuple(); 指定某个分区,选取分区中所有的data parts进行合并,有可能没有执行任务就返回。任务执行后代表某个分区下的数据都合并到了同一个data part,单分区下已经完成主键合并。但是在任务执行期间写入的数据不会参与合并,若是分区下只有一个data part也不会重复执行任务。
说明 对于没有分区键的表,其默认分区就是partition tuple()。
optimize table test final; 对全表所有分区强制进行合并,即使分区下只有一个data part也会进行重新合并,可以用于强制移除TTL过期的记录。任务执行代价最高,但也有可能没有执行合并任务就返回。

对于上面三种命令,您可以设置参数optimize_throw_if_noop通过异常报错感知是否执行任务。

为什么optimize后数据TTL仍未生效?

常见原因及解决方案如下。
  • 常见原因1:数据的TTL淘汰是在主键合并阶段执行的,如果data part迟迟没有进行主键合并,那过期的数据就无法淘汰。

    解决方案:
    • 您可以通过手动optimize final或者optimize 指定分区的方式触发合并任务。
    • 您可以在建表时设置merge_with_ttl_timeout、ttl_only_drop_parts等参数,提高含有过期数据data parts的合并频率。
  • 常见原因2:表的TTL经过修改或者添加,存量的data part里缺少TTL信息或者不正确,这样也可能导致过期数据淘汰不掉。

    解决方案:
    • 您可以通过alter table materialize ttl命令重新生成TTL信息。
    • 您可以通过optimize 分区更新TTL信息。

为什么optimize后更新删除操作没有生效?

云数据库ClickHouse中的更新删除都是异步执行的,目前没有机制可以干预其进度。您可以通过system.mutations系统表查看进度。

如何进行DDL增加列、删除列、修改列操作?

本地表的修改直接执行即可。如果要对分布式表进行修改,需分如下情况进行。
  • 如果没有数据写入,您可以先修改本地表,然后修改分布式表。
  • 如果数据正在写入,您需要区分不同的类型进行操作。
    类型 操作步骤
    增加Nullable的列
    1. 修改本地表。
    2. 修改分布式表。
    修改列的数据类型(类型可以相互转换)
    删除Nullable列
    1. 修改分布式表。
    2. 修改本地表。
    增加非Nullable的列
    1. 停止数据的写入。
    2. 执行SYSTEM FLUSH DISTRIBUTED分布式表。
    3. 修改本地表。
    4. 修改分布式表。
    5. 重新进行数据的写入。
    删除非Nullable的列
    修改列的名称

为什么DDL执行慢,经常卡住?

常见原因:DDL全局的执行是串行执行,复杂查询会导致死锁。

您可以采取如下解决方案。
  • 等待运行结束。
  • 在控制台尝试终止查询。
  • 在云数据库ClickHouse控制台的参数配置页面,对任一参数的参数值进行编辑不修改原来的值,单击提交参数
    说明 如何进行参数值修改请参见修改参数运行值
  • 如果上述方法仍然无法解决,请提交工单。

如何处理分布式DDL报错:longer than distributed_ddl_task_timeout (=xxx) seconds?

您可以通过使用set global on cluster default distributed_ddl_task_timeout=xxx命令修改默认超时时间,xxx为自定义超时时间,单位为秒。全局参数修改请参见集群参数修改

如何处理语法报错:set global on cluster default?

常见原因及解决方案如下。
  • 常见原因1:ClickHouse客户端会进行语法解析,而set global on cluster default是服务端增加的语法。在客户端尚未更新到与服务端对齐的版本时,该语法会被客户端拦截。

    解决方案:
    • 使用JDBC Driver等不会在客户端解析语法的工具,比如DataGrip、DBeaver。
    • 编写JDBC程序来执行该语句。
  • 常见原因2:set global on cluster default key = value; 中value是字符串,但是漏写了引号。

    解决方案:在字符串类型的value两侧加上引号。

有什么BI工具推荐?

Quick BI。

有什么数据查询IDE工具推荐?

DataGrip、DBEaver。

如何查看每张表所占的磁盘空间?

您可以通过如下代码查看每张表所占的磁盘空间。
SELECT table, formatReadableSize(sum(bytes)) as size, min(min_date) as min_date, max(max_date) as max_date FROM system.parts WHERE active GROUP BY table; 

如何查看冷数据大小?

示例代码如下。
select * from system.disks;

如何查询哪些数据在冷存上?

示例代码如下。
select * from system.parts where disk_name = 'cold_disk';

如何移动分区数据到冷存?

示例代码如下。
ALTER TABLE table_name MOVE PARTITION partition_expr TO DISK 'cold_disk';

为什么监控中存在数据中断情况?

常见原因如下。
  • 查询触发OOM。
  • 修改配置触发重启。
  • 升降配后的实例重启。

20.8后的版本是否支持平滑升级,不需要迁移数据?

支持。

常用系统表有哪些?

常用系统表及作用如下。
名称 作用
system.processes 查询正在执行的SQL。
system.query_log 查询历史执行过的SQL。
system.merges 查询集群上的merge信息。
system.mutations 查询集群上的mutation信息。

如何修改系统级别的参数?是否要重启,有什么影响?

系统级别的参数对应config.xml内的部分配置项,具体修改步骤如下。

  1. 登录云数据库ClickHouse控制台
  2. 集群列表页面,选择默认实例列表云原生版本实例列表,单击目标集群ID。
  3. 在集群信息页面单击导航栏左侧的参数配置
  4. 修改max_concurrent_queries参数的运行参数值,输入修改值并单击确定修改参数
  5. 单击提交参数
  6. 单击确定

单击确定后,自动重启clickhouse-server,重启会造成约1min闪断。

如何修改用户级别的参数?

用户级别的参数对应users.xml内的部分配置项,你需要执行如下示例语句。
set global on cluster default ${key}=${value};

无特殊说明的参数执行成功后即可生效。

如何修改Quota?

您可以在执行语句的settings里增加,示例代码如下。
settings max_memory_usage = XXX;