ClickHouse本地表与分布式表

表引擎

ClickHouse表引擎决定了如下几个方面:

  • 怎样存储数据 -将数据写到哪里, 怎样读取数据.
  • 支持何种查询以及怎样支持.
  • 并发数据访问.
  • 索引的使用.
  • 是否多线程的请求执行是可以的.
  • 数据如何同步.

当读取数据时, 引擎只需要抽取必要的列簇. 然而,在一些场景下,查询可能在表引擎中是半处理状态.

在大多数场景中, 我们所使用的引擎主要是 MergeTree 家族

本地表

本地表,顾名思义数据存储、查询计算都依赖本地单节点,ClickHouse的配置文件默认都是本地模式,建表同样默认本地表

1
2
3
4
5
6
7
8
9
CREATE TABLE ontime_local (FlightDate Date,Year UInt16) ENGINE = MergeTree(FlightDate, (Year, FlightDate), 8192);

insert into ontime_local (FlightDate,Year)values('2001-10-12',2001);

insert into ontime_local (FlightDate,Year)values('2002-10-12',2002);

insert into ontime_local (FlightDate,Year)values('2003-10-12',2003);

insert into ontime_local (FlightDate,Year)values('2003-10-12',2004);

以上代码,在新建了本地表ontime_local,并且插入了4条数据

1
2
3
4
5
6
7
8
9
10
:) select count(*) from ontime_local;

SELECT count(*)
FROM ontime_local

┌─count()─┐
│ 4 │
└─────────┘

1 rows in set. Elapsed: 0.002 sec.

分布式表

首先了解测试集群:4节点、4分片、没有做数据副本

1
2
3
4
5
6
7
8
9
10
11
12
13
:) SELECT * FROM system.clusters;

SELECT *
FROM system.clusters

┌─cluster─┬─shard_num─┬─shard_weight─┬─replica_num─┬─host_name─────┬─host_address──┬─port─┬─is_local─┬─user────┬─default_database─┐
│ test │ 1 │ 1 │ 1 │ 192.168.1.1 │ 192.168.1.1 │ 9000 │ 1 │ default │ │
│ test │ 2 │ 1 │ 1 │ 192.168.1.2 │ 192.168.1.2 │ 9000 │ 0 │ default │ │
│ test │ 3 │ 1 │ 1 │ 192.168.1.3 │ 192.168.1.3 │ 9000 │ 0 │ default │ │
│ test │ 4 │ 1 │ 1 │ 192.168.1.4 │ 192.168.1.4 │ 9000 │ 0 │ default │ │
└─────────┴───────────┴──────────────┴─────────────┴───────────────┴───────────────┴──────┴──────────┴─────────┴──────────────────┘

4 rows in set. Elapsed: 0.008 sec.

在每个节点上创建本地表,在每个节点上创建一张分布式表去关联本地表

1
2
CREATE TABLE ontime_d_local (FlightDate Date,Year UInt16) ENGINE = MergeTree(FlightDate, (Year, FlightDate), 8192);
CREATE TABLE ontime_d_all AS ontime_d_local ENGINE = Distributed(test, default, ontime_d_local, rand());

任一节点向分布式表插入数据,千万注意不能向本地表插入数据

此时分布式表可以看作全局视图

1
2
3
4
5
6
7
insert into ontime_d_all (FlightDate,Year)values('2001-10-12',2001);

insert into ontime_d_all (FlightDate,Year)values('2002-10-12',2002);

insert into ontime_d_all (FlightDate,Year)values('2003-10-12',2003);

insert into ontime_d_all (FlightDate,Year)values('2003-10-12',2004);

在任一节点查询

可以发现,分布式表的数据总量是对的,但是本地表只保留了1/4的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
:) select count(*) from ontime_d_all;

SELECT count(*)
FROM ontime_d_all

┌─count()─┐
│ 4 │
└─────────┘

1 rows in set. Elapsed: 0.008 sec.
:) select count(*) from ontime_d_local;

SELECT count(*)
FROM ontime_d_local

┌─count()─┐
│ 1 │
└─────────┘

1 rows in set. Elapsed: 0.002 sec.

分布式表的问题

  • 建表复杂

必须在集群所有节点建本地表和分布式表,而且不能漏掉任何一个节点,不然数据会丢失。

比如集群有4个节点,如果只在2个节点上建表,那么插入数据的时候会有一半数据丢失,而且查询也会报错

  • 扩展性差

分布式表在增加节点的时候会造成数据分布不均匀