https://clickhouse.tech/docs/en/sql-reference/statements/select/
版本:v20.11
目录
参考资料
总览
语法
select字句
COLUMNS表达式
星号
极值
AS
实施细节
SELECT修饰符
APPLY
EXCEPT
REPLACE
Modifier Combinations
ARRAY JOIN 子句
语法
例子
使用别名
具有嵌套数据结构的ARRAY JOIN
实施细节
DISTINCT子句
空值处理
和groupby的不同
局限性
例子
FORMAT子句
默认格式
实施细节
例子
FROM子句
FINAL修饰符
缺点
实施细节
GROUP BY子句
NULL值处理
WITH ROLLUP修饰符
举例
WITH CUBE修饰符
举例
WITH TOTALS修饰符
totals处理配置
实施细节
外部存储器中的GROUP BY
HAVING子句
限制
INTO OUTFILE子句
实施细节
JOIN子句
语法
支持的join类型
设置
ASOF JOIN 使用
举例
分布式联接
使用建议
空值处理
句法
语法限制
性能
内存限制
举例
LIMIT子句
LIMIT…WITH TIES修饰符
LIMIT BY子句
举例
ORDER BY子句
特殊值排序
举例
大小写支持
实施细节
优化数据读取
ORDER BY Expr WITH FILL修饰符
举例
OFFSET FETCH修饰符
举例
PREWHERE子句
手动控制前置位置
限制
SAMPLE子句
SAMPLE K
SAMPLE N
SAMPLE K OFFSET M
UNION子句
UNION ALL
UNION DISTINCT
实施细节
WHERE子句
WITH子句
语法
举例
[WITH expr_list|(subquery)]
SELECT [DISTINCT] expr_list
[FROM [db.]table | (subquery) | table_function] [FINAL]
[SAMPLE sample_coeff]
[ARRAY JOIN ...]
[GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table (ON )|(USING )
[PREWHERE expr]
[WHERE expr]
[GROUP BY expr_list] [WITH ROLLUP|WITH CUBE] [WITH TOTALS]
[HAVING expr]
[ORDER BY expr_list] [WITH FILL] [FROM expr] [TO expr] [STEP expr]
[LIMIT [offset_value, ]n BY columns]
[LIMIT [n, ]m] [WITH TIES]
[UNION ...]
[INTO OUTFILE filename]
[FORMAT format]
除了紧随在SELECT之后的必需的表达式列表(将在下面更详细介绍)之外,其他所有子句都是可选的。
COLUMNS
表达式要将结果中的某些列与re2正则表达式匹配,可以使用该COLUMNS
表达式。
COLUMNS('regexp')
--例如,考虑表:
CREATE TABLE default.col_names (aa Int8, ab Int8, bc Int8) ENGINE = TinyLog
--以下查询从a名称中包含符号的所有列中选择数据。
SELECT COLUMNS('a') FROM col_names
┌─aa─┬─ab─┐
│ 1 │ 1 │
└────┴────┘
--所选列不按字母顺序返回。
--您可以COLUMNS在查询中使用多个表达式并将函数应用于它们。
--例如:
SELECT COLUMNS('a'), COLUMNS('c'), toTypeName(COLUMNS('c')) FROM col_names
┌─aa─┬─ab─┬─bc─┬─toTypeName(bc)─┐
│ 1 │ 1 │ 1 │ Int8 │
└────┴────┴────┴────────────────┘
--COLUMNS表达式返回的每一列都作为单独的参数传递给函数。如果支持其他参数,您也可以将其传递给该函数。使用功能时要小心。如果函数不支持传递给它的参数数量,则ClickHouse会引发异常。
--例如:
SELECT COLUMNS('a') + COLUMNS('c') FROM col_names
Received exception from server (version 19.14.1):
Code: 42. DB::Exception: Received from localhost:9000. DB::Exception: Number of arguments for function plus doesn't match: passed 3, should be 2.
--因为COLUMNS('a')返回两列,COLUMNS('c')返回一列,+号没有办法同时操作三个参数
您可以在查询的任何部分放置星号,而不是表达式。分析查询后,星号会展开到所有表列的列表(不包括虚拟列)。
仅在少数情况下使用星号是合理的:
LIMIT 1
。但是最好使用DESC TABLE
查询。PREWHERE
。在所有其他情况下,我们不建议使用星号,因为它只会给您带来柱状DBMS的缺点,而不是优点。换句话说,不建议使用星号。
除了结果之外,您还可以获取结果列的最小值和最大值。
为此,将 extremes 设置为1。将为数字类型,日期和带时间的日期计算最小值和最大值。对于其他列,将输出默认值。
计算出另外两行–分别为最小值和最大值。 这些额外的两行以JSON *,TabSeparated *和Pretty *格式输出,与其他行分开。 它们不会以其他格式输出。
将为LIMIT之前但LIMIT BY之后的行计算极值。
但是,当使用LIMIT偏移量,大小时,偏移量之前的行将包含在极端中。
在流请求中,结果还可能包含少量通过LIMIT的行。
您可以在查询的任何部分使用同义词(AS别名)。
GROUP BY和ORDER BY子句不支持位置参数。 这与MySQL矛盾,但符合标准SQL。 例如,GROUP BY 1、2将被解释为按常量分组(即,将所有行聚合为一个)。
如果查询省略了DISTINCT,GROUP BY和ORDER BY子句以及IN和JOIN子查询,则将使用O(1)数量的RAM对查询进行完全的流处理。
如果没有省略,则需要指定适当的限制,否则查询可能会消耗大量RAM。设置项:
max_memory_usage
max_rows_to_group_by
max_rows_to_sort
max_rows_in_distinct
max_bytes_in_distinct
max_rows_in_set
max_bytes_in_set
max_rows_in_join
max_bytes_in_join
max_bytes_before_external_sort
max_bytes_before_external_group_by
更多信息查看常规设置项。
您可以在SELECT
查询中使用以下修饰符。
允许您为通过查询的外部表表达式返回的每一行调用一些函数。
SELECT
INSERT INTO columns_transformers VALUES (100, 10, 324), (120, 8, 23);
SELECT * APPLY(sum) FROM columns_transformers;
┌─sum(i)─┬─sum(j)─┬─sum(k)─┐
│ 220 │ 18 │ 347 │
└────────┴────────┴────────┘
从结果中排除一列或多列的名称。 输出中将省略所有匹配的列名。
SELECT
SELECT * EXCEPT (i) from columns_transformers;
┌──j─┬───k─┐
│ 10 │ 324 │
│ 8 │ 23 │
└────┴─────┘
指定一个或多个表达式别名。每个别名必须与SELECT *语句中的列名匹配。
在输出列列表中,与别名匹配的列被该REPLACE中的表达式替换。此修饰符不会更改列的名称或顺序。 但是,它可以更改值和值类型。
SELECT
SELECT * REPLACE(i + 1 AS i) from columns_transformers;
┌───i─┬──j─┬───k─┐
│ 101 │ 10 │ 324 │
│ 121 │ 8 │ 23 │
└─────┴────┴─────┘
您可以单独使用每个修饰符,也可以组合使用它们。
--多次使用相同的修饰符。
SELECT COLUMNS('[jk]') APPLY(toString) APPLY(length) APPLY(max) from columns_transformers;
┌─max(length(toString(j)))─┬─max(length(toString(k)))─┐
│ 2 │ 3 │
└──────────────────────────┴──────────────────────────┘
--在单个查询中使用多个修饰符。
SELECT * REPLACE(i + 1 AS i) EXCEPT (j) APPLY(sum) from columns_transformers;
┌─sum(plus(i, 1))─┬─sum(k)─┐
│ 222 │ 347 │
└─────────────────┴────────┘
对于包含数组列的表来说,这是一种常见的操作,以产生一个新表,该表具有一个包含该初始列的每个单独数组元素的列,而其他列的值则重复。 这是ARRAY JOIN子句的基本情况。
它可以看作是使用数组或嵌套数据结构执行JOIN。 目的类似于arrayJoin函数,但子句功能更广泛。
SELECT
FROM
[LEFT] ARRAY JOIN
[WHERE|PREWHERE ]
...
您只能在SELECT查询中指定一个ARRAY JOIN子句。
下面列出了受支持的ARRAY JOIN类型:
下面的示例演示了ARRAY JOIN和LEFT ARRAY JOIN子句的用法。
CREATE TABLE arrays_test
(
s String,
arr Array(UInt8)
) ENGINE = Memory;
INSERT INTO arrays_test
VALUES ('Hello', [1,2]), ('World', [3,4,5]), ('Goodbye', []);
┌─s───────────┬─arr─────┐
│ Hello │ [1,2] │
│ World │ [3,4,5] │
│ Goodbye │ [] │
└─────────────┴─────────┘
--使用ARRAY JOIN的例子:
SELECT s, arr
FROM arrays_test
ARRAY JOIN arr;
┌─s─────┬─arr─┐
│ Hello │ 1 │
│ Hello │ 2 │
│ World │ 3 │
│ World │ 4 │
│ World │ 5 │
└───────┴─────┘
--使用LEFT ARRAY JOIN的例子:
SELECT s, arr
FROM arrays_test
LEFT ARRAY JOIN arr;
┌─s───────────┬─arr─┐
│ Hello │ 1 │
│ Hello │ 2 │
│ World │ 3 │
│ World │ 4 │
│ World │ 5 │
│ Goodbye │ 0 │
└─────────────┴─────┘
可以在ARRAY JOIN子句中为数组指定别名。 在这种情况下,可以使用此别名访问数组项,也可以使用原始名称访问数组本身。 例:
SELECT s, arr, a
FROM arrays_test
ARRAY JOIN arr AS a;
┌─s─────┬─arr─────┬─a─┐
│ Hello │ [1,2] │ 1 │
│ Hello │ [1,2] │ 2 │
│ World │ [3,4,5] │ 3 │
│ World │ [3,4,5] │ 4 │
│ World │ [3,4,5] │ 5 │
└───────┴─────────┴───┘
--使用别名,您可以对外部数组执行ARRAY JOIN。
SELECT s, arr_external
FROM arrays_test
ARRAY JOIN [1, 2, 3] AS arr_external;
┌─s───────────┬─arr_external─┐
│ Hello │ 1 │
│ Hello │ 2 │
│ Hello │ 3 │
│ World │ 1 │
│ World │ 2 │
│ World │ 3 │
│ Goodbye │ 1 │
│ Goodbye │ 2 │
│ Goodbye │ 3 │
└─────────────┴──────────────┘
--多个数组可以在ARRAY JOIN子句中以逗号分隔。 在这种情况下,JOIN与它们同时执行(直接和,而不是笛卡尔积)。 请注意,所有数组的大小必须相同。 例:
SELECT s, arr, a, num, mapped
FROM arrays_test
ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(x -> x + 1, arr) AS mapped;
┌─s─────┬─arr─────┬─a─┬─num─┬─mapped─┐
│ Hello │ [1,2] │ 1 │ 1 │ 2 │
│ Hello │ [1,2] │ 2 │ 2 │ 3 │
│ World │ [3,4,5] │ 3 │ 1 │ 4 │
│ World │ [3,4,5] │ 4 │ 2 │ 5 │
│ World │ [3,4,5] │ 5 │ 3 │ 6 │
└───────┴─────────┴───┴─────┴────────┘
--下面的示例使用arrayEnumerate函数:
SELECT s, arr, a, num, arrayEnumerate(arr)
FROM arrays_test
ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num;
┌─s─────┬─arr─────┬─a─┬─num─┬─arrayEnumerate(arr)─┐
│ Hello │ [1,2] │ 1 │ 1 │ [1,2] │
│ Hello │ [1,2] │ 2 │ 2 │ [1,2] │
│ World │ [3,4,5] │ 3 │ 1 │ [1,2,3] │
│ World │ [3,4,5] │ 4 │ 2 │ [1,2,3] │
│ World │ [3,4,5] │ 5 │ 3 │ [1,2,3] │
└───────┴─────────┴───┴─────┴─────────────────────┘
CREATE TABLE nested_test
(
s String,
nest Nested(
x UInt8,
y UInt32)
) ENGINE = Memory;
INSERT INTO nested_test
VALUES ('Hello', [1,2], [10,20]), ('World', [3,4,5], [30,40,50]), ('Goodbye', [], []);
┌─s───────┬─nest.x──┬─nest.y─────┐
│ Hello │ [1,2] │ [10,20] │
│ World │ [3,4,5] │ [30,40,50] │
│ Goodbye │ [] │ [] │
└─────────┴─────────┴────────────┘
SELECT s, `nest.x`, `nest.y`
FROM nested_test
ARRAY JOIN nest;
┌─s─────┬─nest.x─┬─nest.y─┐
│ Hello │ 1 │ 10 │
│ Hello │ 2 │ 20 │
│ World │ 3 │ 30 │
│ World │ 4 │ 40 │
│ World │ 5 │ 50 │
└───────┴────────┴────────┘
--在ARRAY JOIN中指定嵌套数据结构的名称时,其含义与ARRAY JOIN及其组成的所有数组元素相同。 示例如下:
SELECT s, `nest.x`, `nest.y`
FROM nested_test
ARRAY JOIN `nest.x`, `nest.y`;
┌─s─────┬─nest.x─┬─nest.y─┐
│ Hello │ 1 │ 10 │
│ Hello │ 2 │ 20 │
│ World │ 3 │ 30 │
│ World │ 4 │ 40 │
│ World │ 5 │ 50 │
└───────┴────────┴────────┘
--另一种变化:
SELECT s, `nest.x`, `nest.y`
FROM nested_test
ARRAY JOIN `nest.x`;
┌─s─────┬─nest.x─┬─nest.y─────┐
│ Hello │ 1 │ [10,20] │
│ Hello │ 2 │ [10,20] │
│ World │ 3 │ [30,40,50] │
│ World │ 4 │ [30,40,50] │
│ World │ 5 │ [30,40,50] │
└───────┴────────┴────────────┘
--别名可用于嵌套数据结构,以便选择JOIN结果或源数组。 例:
SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y`
FROM nested_test
ARRAY JOIN nest AS n;
┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┐
│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │
│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │
│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │
│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │
│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │
└───────┴─────┴─────┴─────────┴────────────┘
--使用arrayEnumerate函数的示例:
SELECT s, `n.x`, `n.y`, `nest.x`, `nest.y`, num
FROM nested_test
ARRAY JOIN nest AS n, arrayEnumerate(`nest.x`) AS num;
┌─s─────┬─n.x─┬─n.y─┬─nest.x──┬─nest.y─────┬─num─┐
│ Hello │ 1 │ 10 │ [1,2] │ [10,20] │ 1 │
│ Hello │ 2 │ 20 │ [1,2] │ [10,20] │ 2 │
│ World │ 3 │ 30 │ [3,4,5] │ [30,40,50] │ 1 │
│ World │ 4 │ 40 │ [3,4,5] │ [30,40,50] │ 2 │
│ World │ 5 │ 50 │ [3,4,5] │ [30,40,50] │ 3 │
└───────┴─────┴─────┴─────────┴────────────┴─────┘
运行ARRAY JOIN时,查询执行顺序已优化。
尽管必须在查询的WHERE / PREWHERE子句之前指定ARRAY JOIN,但从技术上讲,它们可以按任意顺序执行,除非使用ARRAY JOIN的结果进行过滤。
处理顺序由查询优化器控制。
如果指定了SELECT DISTINCT,则查询结果中仅保留唯一行。 因此,结果中所有完全匹配的行集中仅剩下一行。
DISTINCT与NULL一起使用,认为NULL是特定值,并且NULL == NULL。
换句话说,在DISTINCT结果中,与NULL的不同组合仅发生一次。 在大多数其他情况下,它与NULL处理不同。
使用distinct的结果和使用groupby但是不使用聚合函数的结果很有可能相同。不同点:
当 SELECT
包含有数组列,不支持distinct。
--ClickHouse支持使用 DISTINCT 和 ORDER BY 在一个查询中的不同的列。 DISTINCT 子句在 ORDER BY 子句前被执行。
--示例表:
┌─a─┬─b─┐
│ 2 │ 1 │
│ 1 │ 2 │
│ 3 │ 3 │
│ 2 │ 4 │
└───┴───┘
--当执行 SELECT DISTINCT a FROM t1 ORDER BY b ASC 来查询数据,我们得到以下结果:
┌─a─┐
│ 2 │
│ 1 │
│ 3 │
└───┘
--如果我们改变排序方向 SELECT DISTINCT a FROM t1 ORDER BY b DESC,我们得到以下结果:
┌─a─┐
│ 3 │
│ 1 │
│ 2 │
└───┘
行 2, 4 排序前被切割。
ClickHouse支持广泛的序列化格式,这些格式可用于查询结果等。 有多种选择SELECT输出格式的方法,其中一种方法是在查询结束时指定FORMAT格式,以获取任何特定格式的结果数据。
为了方便起见,与其他系统集成或提高性能,可以使用特定格式。
如果省略FORMAT子句,则使用默认格式,这取决于设置和用于访问ClickHouse服务器的接口。
使用命令行客户端时,数据始终以内部有效格式(本机)通过网络传递。 客户端独立解释查询的FORMAT子句并格式化数据本身(从而减轻了网络和服务器的额外负担)。
--使用TabSeparated格式
vm:) select * from rmTest format TabSeparated;
SELECT *
FROM rmTest
FORMAT TabSeparated
1 lisi 2020-10-10 90
1 zhangsan 2020-10-10 88
1 zhangsan 2020-10-11 89
15 lmt 2020-11-24 1
16 lmt 2020-11-24 1
5 rows in set. Elapsed: 0.011 sec.
--使用默认格式
vm:) select * from rmTest;
SELECT *
FROM rmTest
┌─id─┬─name─┬───────date─┬─score─┐
│ 15 │ lmt │ 2020-11-24 │ 1 │
│ 16 │ lmt │ 2020-11-24 │ 1 │
└────┴──────┴────────────┴───────┘
┌─id─┬─name─────┬───────date─┬─score─┐
│ 1 │ zhangsan │ 2020-10-11 │ 89 │
└────┴──────────┴────────────┴───────┘
┌─id─┬─name─────┬───────date─┬─score─┐
│ 1 │ lisi │ 2020-10-10 │ 90 │
│ 1 │ zhangsan │ 2020-10-10 │ 88 │
└────┴──────────┴────────────┴───────┘
5 rows in set. Elapsed: 0.006 sec.
FROM子句指定读取数据来源:
JOIN和ARRAY JOIN子句也可用于扩展FROM子句的功能。
子查询是另一个SELECT查询,可以在FROM子句中的括号中指定。
FROM子句可以包含多个数据源,以逗号分隔,等效于对它们执行CROSS JOIN。
指定FINAL后,ClickHouse会在返回结果之前完全合并数据,执行在合并期间发生的数据转换。
FINAL修饰符支持:
使用FINAL的查询比不使用FINAL的类似查询执行速度稍慢,原因是:
在大多数情况下,请避免使用FINAL。
常见的做法是不同的查询,比如当前mergetree引擎的后台进程还没有发生,可以使用聚合(例如,丢弃重复项)来解决。
如果忽略FROM子句,将从system.one表中读取数据。system.one表仅包含一行(该表与其他DBMS中的DUAL表的目的相同)
要执行查询,查询中列出的所有列均从相应的表中提取;查询中不需要的列都从子查询中抛出。
如果查询未列出任何列(例如SELECT count()FROM t),会从表中提取一些列(选出最小的列),以计算行数。
GROUP BY子句将SELECT查询切换到聚合模式,其工作方式如下:
如果查询中包含的键列都在聚合函数中被使用,那么可以省略掉groupby
对于分组,ClickHouse将NULL解释为值,并且NULL == NULL。
假如有表:
┌─x─┬────y─┐
│ 1 │ 2 │
│ 2 │ ᴺᵁᴸᴸ │
│ 3 │ 2 │
│ 3 │ 3 │
│ 3 │ ᴺᵁᴸᴸ │
└───┴──────┘
SELECT sum(x), y FROM t_null_big GROUP BY y:
┌─sum(x)─┬────y─┐
│ 4 │ 2 │
│ 3 │ 3 │
│ 5 │ ᴺᵁᴸᴸ │
└────────┴──────┘
如果将多个键传递给GROUP BY,则结果将为您提供选择的所有组合。
WITH ROLLUP修饰符用于根据他们在GROUP BY列表中的顺序计算关键值表达式的小计。
小计的计算顺序和给定顺序相反:首先计算列表中最后一个键表达式的小计,然后计算前一个键的小计,依此类推,直到第一个键表达式。
在小计行中,已经“分组”的键表达式的值设置为0或空行。
HAVING子句会影响小计结果。
--考虑表:
┌─year─┬─month─┬─day─┐
│ 2019 │ 1 │ 5 │
│ 2019 │ 1 │ 15 │
│ 2020 │ 1 │ 5 │
│ 2020 │ 1 │ 15 │
│ 2020 │ 10 │ 5 │
│ 2020 │ 10 │ 15 │
└──────┴───────┴─────┘
SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH ROLLUP;
--由于GROUP BY部分具有三个键表达式,因此结果包含四个表,其小计从右到左“汇总”:
--GROUP BY:
--year, month, day
--year, month(day列用零填充)
--year(month, day列用零填充)
┌─year─┬─month─┬─day─┬─count()─┐
│ 2020 │ 10 │ 15 │ 1 │
│ 2020 │ 1 │ 5 │ 1 │
│ 2019 │ 1 │ 5 │ 1 │
│ 2020 │ 1 │ 15 │ 1 │
│ 2019 │ 1 │ 15 │ 1 │
│ 2020 │ 10 │ 5 │ 1 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 2019 │ 1 │ 0 │ 2 │
│ 2020 │ 1 │ 0 │ 2 │
│ 2020 │ 10 │ 0 │ 2 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 2019 │ 0 │ 0 │ 2 │
│ 2020 │ 0 │ 0 │ 4 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 0 │ 0 │ 0 │ 6 │
└──────┴───────┴─────┴─────────┘
WITH CUBE修饰符用于计算GROUP BY列表中每个键表达式组合的小计。 小计行将添加到结果表之后。
在小计行中,所有“分组”键表达式的值都设置为0或空行。
HAVING子句会影响小计结果。
--考虑表
┌─year─┬─month─┬─day─┐
│ 2019 │ 1 │ 5 │
│ 2019 │ 1 │ 15 │
│ 2020 │ 1 │ 5 │
│ 2020 │ 1 │ 15 │
│ 2020 │ 10 │ 5 │
│ 2020 │ 10 │ 15 │
└──────┴───────┴─────┘
SELECT year, month, day, count(*) FROM t GROUP BY year, month, day WITH CUBE;
--由于GROUP BY部分具有三个键表达式,因此结果包含八个表,其中包含所有键表达式组合的小计:
--GROUP BY :
--year, month, day
--year, month
--year, day
--year
--month, day
--month
--day
--全部
--从GROUP BY中排除的列将填充零。
┌─year─┬─month─┬─day─┬─count()─┐
│ 2020 │ 10 │ 15 │ 1 │
│ 2020 │ 1 │ 5 │ 1 │
│ 2019 │ 1 │ 5 │ 1 │
│ 2020 │ 1 │ 15 │ 1 │
│ 2019 │ 1 │ 15 │ 1 │
│ 2020 │ 10 │ 5 │ 1 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 2019 │ 1 │ 0 │ 2 │
│ 2020 │ 1 │ 0 │ 2 │
│ 2020 │ 10 │ 0 │ 2 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 2020 │ 0 │ 5 │ 2 │
│ 2019 │ 0 │ 5 │ 1 │
│ 2020 │ 0 │ 15 │ 2 │
│ 2019 │ 0 │ 15 │ 1 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 2019 │ 0 │ 0 │ 2 │
│ 2020 │ 0 │ 0 │ 4 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 0 │ 1 │ 5 │ 2 │
│ 0 │ 10 │ 15 │ 1 │
│ 0 │ 10 │ 5 │ 1 │
│ 0 │ 1 │ 15 │ 2 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 0 │ 1 │ 0 │ 4 │
│ 0 │ 10 │ 0 │ 2 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 0 │ 0 │ 5 │ 3 │
│ 0 │ 0 │ 15 │ 3 │
└──────┴───────┴─────┴─────────┘
┌─year─┬─month─┬─day─┬─count()─┐
│ 0 │ 0 │ 0 │ 6 │
└──────┴───────┴─────┴─────────┘
如果指定了WITH TOTALS修饰符,则将计算另外的一行。
该行将包含:包含默认值(零或空行)的键列,具有在所有行中计算的值(“total”值)的聚合函数列。
此额外的行仅以JSON *,TabSeparated *和Pretty *格式产生,与其他行分开:
存在HAVING时,可以以不同的方式运行WITH TOTALS。 行为取决于totals_mode设置。
before_having
默认情况(我在20.8.3版本中默认的是‘after_having_exclusive’)。在这种情况下,“total”是针对所有行(包括未通过HAVING和max_rows_to_group_by传递的行)计算的。
其它选项都是计算通过having的行,并在设置max_rows_to_group_by和group_by_overflow_mode ='any'的情况下得到的结果不同。
after_having_exclusive
在“totals”中不包含未通过“max_rows_to_group_by“限制的行。
after_having_inclusive
在“totals”中包含未通过“ max_rows_to_group_by”限制的行。
after_having_auto
计算通过HAVING限制的行数。如果超过一定数量(默认为50%),在“totals”中包含未通过“ max_rows_to_group_by”限制的行。否则,不包括。
totals_auto_threshold
默认为0.5。 after_having_auto的系数。
如果未使用max_rows_to_group_by和group_by_overflow_mode ='any',则after_having的所有变体都是相同的,您可以使用其中任何一个(例如after_having_auto)。
您可以在子查询中使用WITH TOTALS,包括JOIN子句中的子查询(在这种情况下,将合计各个总计值)。
聚合是面向列的DBMS的最重要功能之一,因此,它的实现是ClickHouse最优化的部分之一。
默认情况下,聚合是使用哈希表在内存中完成的。它有40多个不同方式,可以根据“分组键”数据类型自动选择。
可以启用将临时数据转储到磁盘来约束GROUP BY的内存使用。
max_bytes_before_external_group_by参数设定使用RAM的阈值。如果设置为0(默认值),则将其禁用。
使用max_bytes_before_external_group_by时,建议将max_memory_usage设置为大约两倍。
因为聚合有两个阶段:(1)读取数据和形成中间数据;(2)合并中间数据。将数据转储到磁盘只能在第1阶段进行。如果没有转储临时数据,则第2阶段可能需要与第1阶段相同的内存量。
例如,如果将max_memory_usage设置为10000000000,并且您要使用外部聚合,则可以将max_bytes_before_external_group_by设置为10000000000,将max_memory_usage设置为20000000000。触发外部聚合(如果至少有一个临时数据转储)时,最大值RAM消耗仅略大于max_bytes_before_external_group_by。
通过分布式查询处理,可以在远程服务器上执行外部聚合。为了使请求者服务器仅使用少量的RAM,请将distributed_aggregation_memory_efficient设置为1。
当将合并的数据刷新到磁盘时,以及当启用distributed_aggregation_memory_efficiency设置并从远程服务器合并结果时,最多消耗RAM总量的1/256 * the_number_of_threads。
启用外部聚合后,如果数据少于max_bytes_before_external_group_by(即未刷新数据到磁盘),查询的运行速度与没有外部聚合时一样快。 如果刷新了任何临时数据,则运行时间将延长几倍(大约三倍)。
如果在GROUP BY之后有一个带有LIMIT的ORDER BY,则RAM的使用量取决于LIMIT中的数据量,而不是整个表中的数据量。 但是,如果ORDER BY没有LIMIT,需要设置外部排序(max_bytes_before_external_sort)
允许过滤GROUP BY产生的聚合结果。 它与WHERE子句相似,但是区别在于WHERE在聚合之前执行,而HAVING在聚合之后执行。
可以通过别名引用HAVING子句中SELECT子句的聚合结果。 另外,HAVING子句可以过滤查询结果中未返回的其他聚合的结果。
如果未执行汇总,则无法使用HAVING。 请改用WHERE。
在SELECT查询中添加[INTO OUTFILE filename]子句(其中filename是字符串文字),以将其输出重定向到客户端上的指定文件。
join通过使用一张或者多张表中的内容,使相同字段相同,构建出一张新表。这是具有SQL支持的数据库中的常见操作,它对应于关系代数联接。 一个表联接的特殊情况通常称为“自联接”。
来自ON子句的表达式和来自USING子句的列称为“连接键”。 除非另有说明,否则join从具有匹配“ join键”的行中生成笛卡尔乘积,这可能会产生比源表多得多的行的结果。
SELECT
FROM
[GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ASOF] JOIN
(ON )|(USING ) ...
支持所有标准SQL JOIN类型:
没有指定类型的JOIN表示INNER。 可以安全地省略关键字OUTER。
CROSS JOIN的另一种语法是在FROM子句中指定多个表,并用逗号分隔。
ClickHouse中可用的其他联接类型:
可以使用join_default_strictness设置覆盖默认的联接类型。ClickHouse服务器对ANY JOIN操作的行为取决于any_join_distinct_right_table_keys设置。
当需要连接不完全匹配的记录时,ASOF JOIN很有用。
该算法需要表格中的特殊列,列需要满足以下性质:
SELECT expressions_list
FROM table_1
ASOF LEFT JOIN table_2
ON equi_cond AND closest_match_cond
--您可以使用任意数量的相等条件和一个最接近的匹配条件
SELECT count() FROM table_1 ASOF LEFT JOIN table_2 ON table_1.a == table_2.b AND table_2.t <= table_1.t.
支持最接近匹配的条件: >
, >=
, <
, <=
.
--ASOF JOIN使用equi_columnX进行相等性联
--ASOF JOIN使用asof_column进行与给定条件(例如table_1.asof_column> = table_2.asof_column)最接近的联接。
--asof_column列始终是USING子句中的最后一个。
SELECT expressions_list
FROM table_1
ASOF JOIN table_2
USING (equi_column1, ... equi_columnN, asof_column)
ASOF JOIN可以从表1中选择一个时间戳,并从表2中选择最匹配给定条件的事件。如果有相等的,那么相等的是最接近的。
在这个例子中,user_id列可用于相等性联接,而ev_time列可用于最接近匹配项联接。例子中,事件_1_1可以与事件_2_1合并,事件_1_2可以与事件_2_3合并,但事件_2_2无法合并。
table_1 table_2
event | ev_time | user_id event | ev_time | user_id
----------|---------|---------- ----------|---------|----------
... ...
event_1_1 | 12:00 | 42 event_2_1 | 11:59 | 42
... event_2_2 | 12:30 | 42
event_1_2 | 13:00 | 42 event_2_3 | 13:00 | 42
... ...
Join表引擎中不支持ASOF连接。
有两种执行涉及分布式表的联接的方法:
小心使用global,可以了解 Distributed subqueries
在联接表时,可能会出现空单元格。 设置join_use_nulls定义ClickHouse如何处理。
如果JOIN键是Nullable类型的字段,那么至少有一个键为NULL的行将不被连接。
在USING中指定的列在两个子查询中必须具有相同的名称,而其他列的名称必须不同。 您可以使用别名来更改子查询中的列名称。
USING子句指定一个或多个要连接的列,以建立这些列的相等性。 设置的列列表不带方括号。 不支持更复杂的连接条件。
对于单个SELECT查询中的多个JOIN子句:
对于ON,WHERE和GROUP BY子句:
运行JOIN时,与查询的其他阶段有关的执行顺序没有优化。JOIN(在右表中进行搜索)在WHERE中进行过滤之前和聚合之前运行。
每次使用相同的JOIN运行查询时,由于不缓存结果,因此每次查询都要重新执行。为避免这种情况,请使用特殊的Join表引擎。
在某些情况下,使用IN代替JOIN更有效。
如果您需要一个JOIN来与维表连接(这些表是较小的表,其中包含维属性,例如广告活动的名称),则JOIN可能不是很方便,因为每个用户都需要重新访问正确的表 查询。
在这种情况下,应使用“外部词典”功能代替JOIN。 有关更多信息,请参见“外部词典”部分。
默认情况下,ClickHouse使用哈希联接算法。 ClickHouse使用
如果需要限制JOIN操作的内存消耗,请使用以下设置:
当达到任何这些限制时,ClickHouse会按照join_overflow_mode设置的指示进行操作。
SELECT
CounterID,
hits,
visits
FROM
(
SELECT
CounterID,
count() AS hits
FROM test.hits
GROUP BY CounterID
) ANY LEFT JOIN
(
SELECT
CounterID,
sum(Sign) AS visits
FROM test.visits
GROUP BY CounterID
) USING CounterID
ORDER BY hits DESC
LIMIT 10
┌─CounterID─┬───hits─┬─visits─┐
│ 1143050 │ 523264 │ 13665 │
│ 731962 │ 475698 │ 102716 │
│ 722545 │ 337212 │ 108187 │
│ 722889 │ 252197 │ 10547 │
│ 2237260 │ 196036 │ 9522 │
│ 23057320 │ 147211 │ 7689 │
│ 722818 │ 90109 │ 17847 │
│ 48221 │ 85379 │ 4652 │
│ 19762435 │ 77807 │ 7026 │
│ 722884 │ 77492 │ 11056 │
└───────────┴────────┴────────┘
LIMIT m允许从结果中选择前m行。
LIMIT n,m允许在跳过前n行之后从结果中选择m行。 LIMIT m OFFSET n语法是等效的。
n和m必须为非负整数。
如果没有用于显式排序结果的ORDER BY子句,则结果行的选择可能是任意的,也可能是不确定的。
设置WITH TIES修饰符并指定ORDER BY expr_list时,您将得到结果前n行或n,m行,和所有与这些结果具有相同ORDER BY字段值的行
该修饰符还可以与ORDER BY…WITH FILL修饰符结合使用。
SELECT * FROM (
SELECT number%50 AS n FROM numbers(100)
) ORDER BY n LIMIT 0,5
SELECT * FROM (
SELECT number%50 AS n FROM numbers(100)
) ORDER BY n LIMIT 0,5
┌─n─┐
│ 0 │
│ 0 │
│ 1 │
│ 1 │
│ 2 │
└───┘
--添加WITH TIES修饰符
SELECT * FROM (
SELECT number%50 AS n FROM numbers(100)
) ORDER BY n LIMIT 0,5 WITH TIES
┌─n─┐
│ 0 │
│ 0 │
│ 1 │
│ 1 │
│ 2 │
│ 2 │
└───┘
--因为第6行的字段n与第5行具有相同的值“ 2”
带有LIMIT n BY expressions子句的查询为每个不同的表达式值选择前n行。 LIMIT BY的键可以包含任意数量的表达式。
ClickHouse支持以下语法变体:
LIMIT [offset_value, ]n BY expressions
LIMIT n OFFSET offset_value BY expressions
在查询处理期间,ClickHouse选择按排序键排序的数据。
排序键是使用ORDER BY子句显式设置的,也可以作为表引擎的属性隐式设置。
然后,ClickHouse应用LIMIT n BY expressions,并为每种不同的表达式组合返回最多n行。
如果指定了OFFSET,则对于属于不同表达式组合的每个数据块,ClickHouse从块的开头开始跳过offset_value行数,并返回最多n行。 如果offset_value大于数据块中的行数,则ClickHouse从该块返回零行。
LIMIT BY与LIMIT不相关。 它们都可以在同一查询中使用。
--创建一张表
CREATE TABLE limit_by(id Int, val Int) ENGINE = Memory;
INSERT INTO limit_by VALUES (1, 10), (1, 11), (1, 12), (2, 20), (2, 21);
SELECT * FROM limit_by ORDER BY id, val LIMIT 2 BY id
┌─id─┬─val─┐
│ 1 │ 10 │
│ 1 │ 11 │
│ 2 │ 20 │
│ 2 │ 21 │
└────┴─────┘
SELECT * FROM limit_by ORDER BY id, val LIMIT 1, 2 BY id
┌─id─┬─val─┐
│ 1 │ 11 │
│ 1 │ 12 │
│ 2 │ 21 │
└────┴─────┘
--SELECT * FROM limit_by ORDER BY id, val LIMIT 2 OFFSET 1 BY id也会返回上面结果
--以下查询返回每个域的前5个网址,device_type对,总共最多100行(LIMIT n BY + LIMIT)。
SELECT
domainWithoutWWW(URL) AS domain,
domainWithoutWWW(REFERRER_URL) AS referrer,
device_type,
count() cnt
FROM hits
GROUP BY domain, referrer, device_type
ORDER BY cnt DESC
LIMIT 5 BY domain, device_type
LIMIT 100
ORDER BY子句包含一个表达式列表,每个表达式都可以使用DESC(降序)或ASC(升序)修饰符来确定排序方向。 如果未指定方向,则采用ASC,因此通常将其省略。
排序方向适用于单个表达式,而不适用于整个列表。 示例:ORDER BY vistss DESC,SearchPhrase
排序表达式列表中具有相同值的行以任意顺序输出,该顺序可能不确定(每次都不同)。
如果省略ORDER BY子句,行的顺序也未定义,返回结果不确定。
NaN和NULL排序顺序有两种方法:
┌─x─┬────y─┐
│ 1 │ ᴺᵁᴸᴸ │
│ 2 │ 2 │
│ 1 │ nan │
│ 2 │ 2 │
│ 3 │ 4 │
│ 5 │ 6 │
│ 6 │ nan │
│ 7 │ ᴺᵁᴸᴸ │
│ 6 │ 7 │
│ 8 │ 9 │
└───┴──────┘
SELECT * FROM t_null_nan ORDER BY y NULLS FIRST
┌─x─┬────y─┐
│ 1 │ ᴺᵁᴸᴸ │
│ 7 │ ᴺᵁᴸᴸ │
│ 1 │ nan │
│ 6 │ nan │
│ 2 │ 2 │
│ 2 │ 2 │
│ 3 │ 4 │
│ 5 │ 6 │
│ 6 │ 7 │
│ 8 │ 9 │
└───┴──────┘
对浮点数进行排序时,NaN与其他值分开。 不管排序顺序如何,NaN都会排在最后。
换句话说,对于升序排序,它们比所有其他数字都大,而对于降序排序,它们比其余数字都小。
对于按字符串值排序,可以指定排序规则(比较)。 举例:ORDER BY SearchPhrase COLLATE 'tr'——使用土耳其字母按升序对关键字进行排序,不区分大小写,假设字符串是UTF-8编码的。
可以为ORDER BY中的每个表达式分别指定或不指定COLLATE。 如果指定了ASC或DESC,则在其后指定COLLATE。 使用COLLATE时,排序始终不区分大小写。
我们仅建议使用COLLATE进行少量行的最终排序,因为使用COLLATE进行排序的效率不如按字节进行常规排序。
如果除ORDER BY之外还指定了足够小的LIMIT,则使用较少的RAM。否则,花费的内存量与要排序的数据量成正比。
对于分布式查询处理,如果省略GROUP BY,则在远程服务器上部分完成排序,然后在请求者服务器上合并结果。这意味着对于分布式排序,要排序的数据量可能大于单个服务器上的内存量。
如果没有足够的RAM,则可以在外部存储器中执行排序(在磁盘上创建临时文件)。为此,请设置max_bytes_before_external_sort,如果将其设置为0(默认值),则禁用外部排序。
如果启用,则当要排序的数据量达到指定的字节数时,将对收集的数据进行排序并转储到临时文件中。 读取所有数据后,将合并所有排序的文件并输出结果。 临时文件路径在tmp_path中被设置。
运行查询可能比max_bytes_before_external_sort占用更多的内存。 因此,此设置的值必须明显小于max_memory_usage。 例如,如果您的服务器具有128 GB的RAM,并且您需要运行一个查询,请将max_memory_usage设置为100 GB,将max_bytes_before_external_sort设置为80 GB。
外部排序的工作效率远不及RAM排序。
如果ORDER BY表达式的前缀与表排序键一致,则可以使用optimize_read_in_order设置来优化查询。
启用optimize_read_in_order设置后,Clickhouse服务器将使用表索引并按照ORDER BY键的顺序读取数据。 这样可以避免在指定LIMIT的情况下读取所有数据。 因此,对具有小限制的大数据的查询将更快地处理。
优化可同时用于ASC和DESC,而不能与GROUP BY子句和FINAL修饰符一起使用。
禁用optimize_read_in_order设置后,Clickhouse服务器在处理SELECT查询时将不使用表索引。
当运行具有ORDER BY子句,较大的LIMIT和WHERE条件(要求在找到查询的数据之前先读取大量记录)的查询时,手动禁用optimize_read_in_order。
以下表引擎支持优化:
在MaterializedView-engine表中,优化可与SELECT ... FROM merge_tree_table ORDER BY pk之类的视图一起使用。 但是,如果SELECT ... FROM view ORDER BY pk之类的查询中不包含ORDER BY子句,则该查询不支持该查询。
该修饰符还可以与LIMIT…WITH TIES修饰符结合使用。
可以在ORDER BY expr之后使用可选的FROM expr,TO expr和STEP expr参数设置WITH FILL修饰符。
expr列的所有缺失值将被顺序填充,而其他列将被填充为默认值。
使用以下语法填充多列,然后在ORDER BY部分的每个字段名称后添加WITH FILL修饰符和可选参数。
ORDER BY expr [WITH FILL] [FROM const_expr] [TO const_expr] [STEP const_numeric_expr], ... exprN [WITH FILL] [FROM expr] [TO expr] [STEP numeric_expr]
WITH FILL仅适用于数字(所有类型的浮点,十进制,整数)或日期/日期时间类型的字段。
SELECT n, source FROM (
SELECT toFloat32(number % 10) AS n, 'original' AS source
FROM numbers(10) WHERE number % 3 = 1
) ORDER BY n
┌─n─┬─source───┐
│ 1 │ original │
│ 4 │ original │
│ 7 │ original │
└───┴──────────┘
--使用WITH FILL
SELECT n, source FROM (
SELECT toFloat32(number % 10) AS n, 'original' AS source
FROM numbers(10) WHERE number % 3 = 1
) ORDER BY n WITH FILL FROM 0 TO 5.51 STEP 0.5
┌───n─┬─source───┐
│ 0 │ │
│ 0.5 │ │
│ 1 │ original │
│ 1.5 │ │
│ 2 │ │
│ 2.5 │ │
│ 3 │ │
│ 3.5 │ │
│ 4 │ original │
│ 4.5 │ │
│ 5 │ │
│ 5.5 │ │
│ 7 │ original │
└─────┴──────────┘
当有多个order by字段:
SELECT
toDate((number * 10) * 86400) AS d1,
toDate(number * 86400) AS d2,
'original' AS source
FROM numbers(10)
WHERE (number % 3) = 1
ORDER BY
d2 WITH FILL,
d1 WITH FILL STEP 5;
┌───d1───────┬───d2───────┬─source───┐
│ 1970-01-11 │ 1970-01-02 │ original │
│ 1970-01-01 │ 1970-01-03 │ │
│ 1970-01-01 │ 1970-01-04 │ │
│ 1970-02-10 │ 1970-01-05 │ original │
│ 1970-01-01 │ 1970-01-06 │ │
│ 1970-01-01 │ 1970-01-07 │ │
│ 1970-03-12 │ 1970-01-08 │ original │
└────────────┴────────────┴──────────┘
SELECT
toDate((number * 10) * 86400) AS d1,
toDate(number * 86400) AS d2,
'original' AS source
FROM numbers(10)
WHERE (number % 3) = 1
ORDER BY
d1 WITH FILL STEP 5,
d2 WITH FILL;
┌───d1───────┬───d2───────┬─source───┐
│ 1970-01-11 │ 1970-01-02 │ original │
│ 1970-01-16 │ 1970-01-01 │ │
│ 1970-01-21 │ 1970-01-01 │ │
│ 1970-01-26 │ 1970-01-01 │ │
│ 1970-01-31 │ 1970-01-01 │ │
│ 1970-02-05 │ 1970-01-01 │ │
│ 1970-02-10 │ 1970-01-05 │ original │
│ 1970-02-15 │ 1970-01-01 │ │
│ 1970-02-20 │ 1970-01-01 │ │
│ 1970-02-25 │ 1970-01-01 │ │
│ 1970-03-02 │ 1970-01-01 │ │
│ 1970-03-07 │ 1970-01-01 │ │
│ 1970-03-12 │ 1970-01-08 │ original │
└────────────┴────────────┴──────────┘
OFFSET和FETCH允许您按部分检索数据。可以指定数据行块。
OFFSET offset_row_count {ROW | ROWS}] [FETCH {FIRST | NEXT} fetch_row_count {ROW | ROWS} {ONLY | WITH TIES}]
offset_row_count或fetch_row_count值可以是数字或文字常量。 可以省略fetch_row_count; 默认情况下,它等于1。
OFFSET指定在查询返回的行数需要从开始跳过多少行,FETCH指定查询结果中可以包含的最大行数。ONLY选项用于返回紧接在OFFSET省略的行之后的行。
在这种情况下,FETCH是LIMIT子句的替代方法。
--以下两个查询返回结果相同
SELECT * FROM test_fetch ORDER BY a OFFSET 1 ROW FETCH FIRST 3 ROWS ONLY;
SELECT * FROM test_fetch ORDER BY a LIMIT 3 OFFSET 1;
WITH TIES选项用于根据ORDER BY子句返回与结果集中最后一位相关的所有其他行。 例如,如果fetch_row_count设置为5,但另外两行与第五行中ORDER BY列的值匹配,则结果集将包含七行。
根据标准,如果同时存在,OFFSET子句必须在FETCH子句之前。
--考虑表
┌─a─┬─b─┐
│ 1 │ 1 │
│ 2 │ 1 │
│ 3 │ 4 │
│ 1 │ 3 │
│ 5 │ 4 │
│ 0 │ 6 │
│ 5 │ 7 │
└───┴───┘
--使用ONLY
SELECT * FROM test_fetch ORDER BY a OFFSET 3 ROW FETCH FIRST 3 ROWS ONLY;
┌─a─┬─b─┐
│ 2 │ 1 │
│ 3 │ 4 │
│ 5 │ 4 │
└───┴───┘
--使用WITH TIES
SELECT * FROM test_fetch ORDER BY a OFFSET 3 ROW FETCH FIRST 3 ROWS WITH TIES;
┌─a─┬─b─┐
│ 2 │ 1 │
│ 3 │ 4 │
│ 5 │ 4 │
│ 5 │ 7 │
└───┴───┘
Prewhere是一项优化,可以更有效地应用过滤。 即使未显式指定PREWHERE子句,默认情况下也会启用。它自动将WHERE条件的一部分移动到预备阶段来工作。
PREWHERE子句的作用仅是在您认为自己比默认情况下做得更好的情况下控制优化
该子句与WHERE子句具有相同的含义。
区别在于从表中读取数据的方式不同。 手动控制PREWHERE给少数列使用过滤条件,可提供强大的数据过滤功能。 这减少了读取的数据量。
查询可以同时指定PREWHERE和WHERE。 在这种情况下,PREWHERE在WHERE之前工作。
如果将optimize_move_to_prewhere设置为0,将禁用将部分表达式从WHERE移至PREWHERE。
只适用于MergeTree家族的引擎表。
SAMPLE子句允许进行近似的SELECT查询处理。
启用数据采样后,不会对所有数据执行查询,而是仅对特定部分数据(采样)执行查询。 例如,如果您需要计算所有访问的统计信息,那么只需对所有访问的1/10部分执行查询,然后将结果乘以10就足够了。
在以下场景使用近似查询处理:
仅在表创建期间指定了采样表达式的情况下,才可以对MergeTree家族中的表使用采样(请参见MergeTree引擎)。
数据采样的功能如下:
使用方法为:
--从数据中取10%,因为聚合函数的值不会自动更正,因此要得到一个近似结果,请将count()手动乘以10。
SELECT
Title,
count() * 10 AS PageViews
FROM hits_distributed
SAMPLE 0.1
WHERE
CounterID = 34
GROUP BY Title
ORDER BY PageViews DESC LIMIT 1000
在此,n是足够大的整数。例如,SAMPLE 10000000。至少在10,000,000行上运行查询。
由于数据读取的最小单位是一个颗粒(其大小由index_granularity设置设置),因此设置一个比颗粒大得多的样本是有意义的。
使用SAMPLE n子句时,您不知道处理了哪些相对百分比的数据。 因此,您不知道聚合函数应乘以的系数。 使用_sample_factor虚拟列来获取近似结果。_sample_factor列包含动态计算的相对系数。 使用指定的采样键创建表时,将自动创建此列。 _sample_factor列的用法示例如下所示。
SELECT sum(PageViews * _sample_factor)
FROM visits
SAMPLE 10000000
SELECT sum(_sample_factor)
FROM visits
SAMPLE 10000000
--平均值不需要使用系数
SELECT avg(Duration)
FROM visits
SAMPLE 10000000
SAMPLE 1/10
[++------------]
SAMPLE 1/10 OFFSET 1/2
[------++------]
默认情况下,UNION具有与UNION DISTINCT相同的行为,但是您可以通过设置union_default_mode来指定联合模式,值可以是“ ALL”,“ DISTINCT”或空字符串。
但是,如果您使用UNION并将union_default_mode设置为空字符串,它将引发异常。
使用UNION ALL进行结果扩展,来结合任意数量的SELECT查询。
SELECT CounterID, 1 AS table, toInt64(count()) AS c
FROM test.hits
GROUP BY CounterID
UNION ALL
SELECT CounterID, 2 AS table, sum(Sign) AS c
FROM test.visits
GROUP BY CounterID
HAVING c > 0
结果列按其索引匹配(SELECT内的顺序)。 如果列名不匹配,则从第一个查询中获取最终结果的名称。
对联合执行类型转换。 例如,如果两个查询组合在一起的字段,同时具有是兼容类型的不可为空和可为空类型的相同字段,则所得的UNION ALL将具有可为空的类型字段。
属于UNION ALL的查询不能放在圆括号中。 ORDER BY和LIMIT应用于单独的查询,而不是最终结果。 如果需要对最终结果进行转换,则可以将带有UNION ALL的所有查询放在FROM子句的子查询中。
UNION ALL和UNION DISTINCT之间的区别在于UNION DISTINCT将对联合结果进行不同的转换,等效于包含UNION ALL的子查询中的SELECT DISTINCT。
可以同时运行属于UNION / UNION ALL / UNION DISTINCT的查询,并且可以将它们的结果混合在一起。
WHERE子句允许筛选来自SELECT的FROM子句的数据。
如果有WHERE子句,则它必须包含UInt8类型的表达式。 这通常是带有比较和逻辑运算符的表达式。 该表达式计算为0的行将从进一步的转换或结果中排除。
如果基础表引擎支持,则将根据使用索引和分区修剪的能力来评估WHERE表达式。
有一个称为prewhere的过滤优化。
Clickhouse支持通用表表达式(CTE),该表提供在SELECT查询中使用WITH子句的结果。
命名子查询可以包含到表对象当前所在的位置和子查询上下文中。
通过从WITH表达式中隐藏当前级别的CTE,可以防止递归。
WITH AS
WITH AS
--将常量表达式用作“变量”
WITH '2019-08-01 15:23:00' as ts_upper_bound
SELECT *
FROM hits
WHERE
EventDate = toDate(ts_upper_bound) AND
EventTime <= ts_upper_bound;
--从SELECT子句列列表中选出一个sum(bytes)表达式结果
WITH sum(bytes) as s
SELECT
formatReadableSize(s),
table
FROM system.parts
GROUP BY table
ORDER BY s;
--使用标量子查询的结果
/* this example would return TOP 10 of most huge tables */
WITH
(
SELECT sum(bytes)
FROM system.parts
WHERE active
) AS total_disk_usage
SELECT
(sum(bytes) / total_disk_usage) * 100 AS table_disk_usage,
table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10;
--在子查询中重用表达式
WITH test1 AS (SELECT i + 1, j + 1 FROM test1)
SELECT * FROM test1;