2020-04-08 14:22:25 +00:00
|
|
|
|
# 合并 {#merge}
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
`Merge` 引擎 (不要跟 `MergeTree` 引擎混淆) 本身不存储数据,但可用于同时从任意多个其他的表中读取数据。
|
|
|
|
|
读是自动并行的,不支持写入。读取时,那些被真正读取到数据的表的索引(如果有的话)会被使用。
|
|
|
|
|
`Merge` 引擎的参数:一个数据库名和一个用于匹配表名的正则表达式。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
示例:
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
Merge(hits, '^WatchLog')
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-20 18:20:59 +00:00
|
|
|
|
数据会从 `hits` 数据库中表名匹配正则 ‘`^WatchLog`’ 的表中读取。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
除了数据库名,你也可以用一个返回字符串的常量表达式。例如, `currentDatabase()` 。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
正则表达式 — [re2](https://github.com/google/re2) (支持 PCRE 一个子集的功能),大小写敏感。
|
2020-03-20 18:20:59 +00:00
|
|
|
|
了解关于正则表达式中转义字符的说明可参看 «match» 一节。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
当选择需要读的表时,`Merge` 表本身会被排除,即使它匹配上了该正则。这样设计为了避免循环。
|
|
|
|
|
当然,是能够创建两个相互无限递归读取对方数据的 `Merge` 表的,但这并没有什么意义。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
`Merge` 引擎的一个典型应用是可以像使用一张表一样使用大量的 `TinyLog` 表。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
示例 2 :
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-20 18:20:59 +00:00
|
|
|
|
我们假定你有一个旧表(WatchLog\_old),你想改变数据分区了,但又不想把旧数据转移到新表(WatchLog\_new)里,并且你需要同时能看到这两个表的数据。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
CREATE TABLE WatchLog_old(date Date, UserId Int64, EventType String, Cnt UInt64)
|
|
|
|
|
ENGINE=MergeTree(date, (UserId, EventType), 8192);
|
|
|
|
|
INSERT INTO WatchLog_old VALUES ('2018-01-01', 1, 'hit', 3);
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
CREATE TABLE WatchLog_new(date Date, UserId Int64, EventType String, Cnt UInt64)
|
|
|
|
|
ENGINE=MergeTree PARTITION BY date ORDER BY (UserId, EventType) SETTINGS index_granularity=8192;
|
|
|
|
|
INSERT INTO WatchLog_new VALUES ('2018-01-02', 2, 'hit', 3);
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
CREATE TABLE WatchLog as WatchLog_old ENGINE=Merge(currentDatabase(), '^WatchLog');
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
SELECT *
|
|
|
|
|
FROM WatchLog
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
┌───────date─┬─UserId─┬─EventType─┬─Cnt─┐
|
|
|
|
|
│ 2018-01-01 │ 1 │ hit │ 3 │
|
|
|
|
|
└────────────┴────────┴───────────┴─────┘
|
|
|
|
|
┌───────date─┬─UserId─┬─EventType─┬─Cnt─┐
|
|
|
|
|
│ 2018-01-02 │ 2 │ hit │ 3 │
|
|
|
|
|
└────────────┴────────┴───────────┴─────┘
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-20 18:20:59 +00:00
|
|
|
|
## 虚拟列 {#xu-ni-lie}
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
虚拟列是一种由表引擎提供而不是在表定义中的列。换种说法就是,这些列并没有在 `CREATE TABLE` 中指定,但可以在 `SELECT` 中使用。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
下面列出虚拟列跟普通列的不同点:
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-03-21 04:11:51 +00:00
|
|
|
|
- 虚拟列不在表结构定义里指定。
|
|
|
|
|
- 不能用 `INSERT` 向虚拟列写数据。
|
|
|
|
|
- 使用不指定列名的 `INSERT` 语句时,虚拟列要会被忽略掉。
|
|
|
|
|
- 使用星号通配符( `SELECT *` )时虚拟列不会包含在里面。
|
|
|
|
|
- 虚拟列不会出现在 `SHOW CREATE TABLE` 和 `DESC TABLE` 的查询结果里。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
`Merge` 类型的表包括一个 `String` 类型的 `_table` 虚拟列。(如果该表本来已有了一个 `_table` 的列,那这个虚拟列会命名为 `_table1` ;如果 `_table1` 也本就存在了,那这个虚拟列会被命名为 `_table2` ,依此类推)该列包含被读数据的表名。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2019-03-25 06:47:58 +00:00
|
|
|
|
如果 `WHERE/PREWHERE` 子句包含了带 `_table` 的条件,并且没有依赖其他的列(如作为表达式谓词链接的一个子项或作为整个的表达式),这些条件的作用会像索引一样。这些条件会在那些可能被读数据的表的表名上执行,并且读操作只会在那些满足了该条件的表上去执行。
|
2018-11-30 19:26:35 +00:00
|
|
|
|
|
2020-01-30 10:34:55 +00:00
|
|
|
|
[来源文章](https://clickhouse.tech/docs/en/operations/table_engines/merge/) <!--hide-->
|