应用场景

  1. 绝大多数读请求
  2. 数据需要以大批次(大于1000行)进行更新,而不是单行更新,或者没有更新操作
  3. 数据只添加到数据库中,没有必要修改
  4. 读数据时,会从数据库中提取出大量的行,但只用到少量的列
  5. 表很“宽”,即表中包含大量的列
  6. 查询频率相对较低(每台服务器的QPS小于100)
  7. 简单查询,允许大约50ms的延迟
  8. 列的值是比较小的数值和短字符串
  9. 处理单个查询需要高吞吐量(每台服务器每秒高达数十亿行)
  10. 不需要事务
  11. 数据一致性要求低
  12. 每次查询中只会查询一个大表,除了一个大表,其余都是小表
  13. 查询结果显著小于数据源。即数据有过滤或聚合,返回结果不超过单个服务器内存大小

缺点

  1. 不支持真正的删除/更新,不支持事务
  2. 不支持二级索引
  3. 有限的SQL支持
  4. 不支持窗口功能
  5. 元数据维护需要人工干预维护

列式存储

  • 列式存储可以满足快速读取特定列的需求,在线分析处理往往需要在上百列的宽表中读取指定列分析;
  • 列式存储就近存储同一列的数据,使用压缩算法可以得到更高的压缩率,减少存储占用的磁盘空间;

单条查询就能利用整机的CPU处理(不适合高qps的查询业务)

不适合关联查询

引擎:

  • TinyLog:列文件,保存在磁盘,不支持索引,没有并发控制
  • Memory:保存在内存中,不支持索引,读写不会阻塞
  • MergeTree:
  • 主键不唯一,可重复,没有唯一约束
  • 分区时按文件来区分
  • 分区内排序
  • 建表时 order by 必填【必填原因:稀疏索引,必须要有序,有序效率高】(主键必须是order by的前缀)
  • 以列文件+索引文件+表定义文件
  • 分区并行
  • TTL:设置表或者列的生命周期
  • ReplacingMergeTree:
  • 去重功能
  • (去重只会在同批插入或合并的过程中才生效)最终一致性
  • 分区内去重
  • 合并时间不确定
  • optimize 会手动发起合并,但是不应该太频繁,会引发对数据的大量读写
  • 根据order_by字段去重
  • 重复数据保留版本字段最大的,插入先后顺序

文件目录

  • columns.txt :列信息
  • primary.idx:稀疏索引(数据量小,二分查找,跳表)【index granularity,索引粒度】
  • data.bin :数据文件
  • data.mrk:标记文件,标记偏移量

关键参数

  • background_pool_size:后台线程池大小,merge线程就是在该线程池中执行(cpu2倍)
  • background_schedule_pool_size:执行后台任务的线程数(cpu2倍)
  • background_distributed_schedule_pool_size:分布式发送执行后台任务的线程数(cpu2倍)
  • max_concurrent_queries:最大并发处理请求数
  • max_threads:单个查询所能使用的最大cpu个数(cpu核数)
  • max_memory_usage:单次查询占用内存最大值
  • max_bytes_before_external_group_by:当group使用内存超过阈值后会刷新到磁盘进行
  • max_bytes_before_external_sort:当order by使用内存超过阈值后会刷新到磁盘进行

clickhouse不支持多数据目录,为了提升数据io性能,可以挂载虚拟券组 

查询优化

  • 使用count时,尽量可以不指定具体字段,直接去count.xml中获取条数
  • 去除查询中的重复字段
  • 使用prewhere代替where(prewhere会读取指定的列数据,来判断数据过滤,等待数据过滤之后再读取select声明的列字段来补全其余属性)
  • 使用主键字段
  • select 查询的列字段和where字段相同
  • order by要搭配where和limit使用
  • 避免产生虚拟列(select 表中没有的字段a+b)
  • 去重根据业务可以选择 uniqCombined函数,性能提升10倍以上,存在误差,每次查询结果不同
  • 查询熔断(设置单个查询的超时时间问题)
  • 关闭虚拟内存(物理内存和虚拟内存交换数据,导致查询变慢)
  • 表中不配置null值(单独存文件,不能够被索引,效率低)
  • 批量写入时先排序(无需的数据或者涉及的分区太多,导致clickhouse无法及时对新导入的数据进行合并,从而影响查询性能
  • join时小表在右(会把join的表加载到内存)