SELECT [DISTINCT] expr_list
[FROM [db.]table | (subquery) | table_function] [FINAL]
[SAMPLE sample_coeff]
[ARRAY JOIN ...]
[GLOBAL] ANY|ALL INNER|LEFT JOIN (subquery)|table USING columns_list
[PREWHERE expr]
[WHERE expr]
[GROUP BY expr_list] [WITH TOTALS]
[HAVING expr]
[ORDER BY expr_list]
[LIMIT [n, ]m]
[UNION ALL ...]
[INTO OUTFILE filename]
[FORMAT format]
[LIMIT n BY columns]
1、从哪个表、子查询(构建在外部查询的内部,外部没有用到的列将被忽略)、表函数取数据
2、查询中未列出如何的列select count() from test,将额外从表中取些列以计算行数
3、final使查询结果在查询过程中被聚合,仅能用在SELECT from CollapsingMergeTree中
在单个流中读取所有相关的主键列,合并需要的数据(查询变慢,避免使用)
1、近似查询,近工作在MergeTree*类型的表中,且建表时指定采样表达式
2、sample子句可用sample k来表示,k可以是0-1的小数值或一个足够大的正整数
k为小数时,查询将使用k做百分比选取数据,sample 0.1只检索数据总量的10%
k足够大的正整数,k为最大样本数,sample 10000000检索最多10000000行数据
取数据总量的0.1 (10%)的数据,查不会自动校正聚合函数最终结果,为更精确结果,count()*10
SELECT
Title,
count() * 10 AS PageViews
FROM hits_distributed
SAMPLE 0.1
WHERE
CounterID = 34
AND toDate(EventDate) >= toDate('2013-01-29')
AND toDate(EventDate) <= toDate('2013-02-04')
AND NOT DontCountHits
AND NOT Refresh
AND Title != ''
GROUP BY Title
ORDER BY PageViews DESC LIMIT 1000
3、相同采样率(建表使用相同采用表达式)得到结果一致
1、等同于innert join;使查询与数组和nested类型连接,类似array join函数
2、一个查询只能出现一个array join,where/prewhere使用array join子句,其将优先于where/prewhere子句执行,否则将在where/prewhere子句之后执行
SELECT * FROM arrays_test
┌─s───────┬─arr─────┐
│ Hello │ [1,2] │
│ World │ [3,4,5] │
│ Goodbye │ [] │
SELECT s, arr FROM arrays_test ARRAY JOIN arr
┌─s─────┬─arr─┐
│ Hello │ 1 │
│ Hello │ 2 │
│ World │ 3 │
│ World │ 4 │
│ World │ 5 │
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 │
SELECT s, arr, a, num, mapped FROM arrays_test
ARRAY JOIN arr AS a, arrayEnumerate(arr) AS num, arrayMap(lambda(tuple(x), plus(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 │
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] │
SELECT
FROM
[GLOBAL] [ANY|ALL] INNER|LEFT|RIGHT|FULL|CROSS [OUTER] JOIN
(ON )|(USING ) ...
all:同SQL的JOIN,右表存在多个与左表关联的数据
any:右表存在多个与左关联的数据,仅返回第一各与左表匹配的数据
普通join,查询发送给远程服务器,并在其上生成右表与之关联(右表来自服务器)
使用global join,在请求服务器上计算右表并一临时表的方式将其发送到所有服务器,每台服务器使用它计算
从子查询中删除所有join不需要的列
执行时无进行执行顺序的优化:join先于where与聚合执行,为显示指定执行顺序,使用子查询方式执行join
子查询
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 │
子查询不允许设置别名或在其他地方引用, USING
中指定的列必须在两个子查询中具有相同的名称。可通过使用别名来更改子查询的列名(示例中就分别使用了'hits'与'visits'别名)
USING
子句指定要进行链接的一或多个列,系统将列在两表中相等的值连接起来。如果列是一个列表,不需要使用括号包裹。同时JOIN不支持其他更复杂的Join方式,只能在查询中指定一个JOIN
;若运行多个JOIN
,你可将它们放入子查询中。
右表(子查询的结果)将会保存在内存中。如果没有足够的内存,则无法运行JOIN;
每次运行相同的JOIN
查询,会再次计算, 为避免这情况,可用‘Join’引擎,一个预处理的Join数据结构,总是保存在内存中。更多信息,参见“Join引擎”部分。
在各种类型的JOIN中,最高效的是ANY LEFT JOIN
,然后是ANY INNER JOIN
,效率最差的是ALL LEFT JOIN
以及ALL INNER JOIN
。
如果你需要使用JOIN
来关联一些纬度表(包含纬度属性的一些相对比较小的表,例如广告活动的名称),那么JOIN
可能不是好的选择,因为语法负责,并且每次查询都将重新访问这些表。对于这种情况,您应该使用“外部字典”的功能来替换JOIN
。更多信息,参见 外部字典 部分。
1、JOIN的行为受 join_use_nulls 的影响。当join_use_nulls=1
时,JOIN
的工作与SQL标准相同。
2、如果JOIN的key是 Nullable 类型的字段,则至少一个存在 NULL 值的key不会被关联。
该子句中须包含一个UInt8类型的表达式:通常是一个带有比较和逻辑的表达式:在所有数据转换前用来过滤数据;如果在支持索引的数据库表引擎中,这个表达式将被评估是否使用索引。
与WHERE子句的意思相同。主要不同在于表数据的读取;PREWHERE 仅支持*MergeTree
系列引擎
例如,在一个需要提取大量列的查询中为少部分列编写PREWHERE是很有作用的。
1、在一个查询中可以同时指定PREWHERE和WHERE,在这种情况下,PREWHERE优先于WHERE执行。
2、PREWHERE不适合用于已经存在于索引中的列:列已经存在于索引中,只有满足索引的数据块才会被读取。
3、如将'optimize_move_to_prewhere'设置为1,并且在查询中不包含PREWHERE,则系统将自动的把适合PREWHERE表达式的部分从WHERE中抽离到PREWHERE中。
必含一个表达式列表,每个表达式将被称之为“key”。 SELECT,HAVING,ORDER BY子句中的表达式列表必须来自于这些“key”或聚合函数。被选择的列中不能包含非聚合函数或key之外的其他列。
如查询表达式中仅含聚合函数,则可省略GROUP BY,这时会假定将所有数据聚合成一组空“key”。
SELECT
count(),
median(FetchTiming > 60 ? 60 : FetchTiming),
count() - sum(Refresh)
FROM hits
1、与SQL标准不同,如表中不存在任何数据(表不存在任何数据,或被WHERE过滤掉了),将返回一个空结果,而不是一个包含聚合函数初始值的结果。
2、与MySQL不同(实际上这是符合SQL标准的),不能获得一个不在key中的非聚合函数列(除了常量表达式),但可使用‘any’(返回遇到的第一个值)、max、min等聚合函数使它工作
ELECT
domainWithoutWWW(URL) AS domain,
count(),
any(Title) AS title -- getting the first occurred page header for each domain.
FROM hits
GROUP BY domain
GROUP BY子句会为遇到的每一个不同的key计算一组聚合函数的值
在GROUP BY子句中不使用Array类型的列
常量不能作为聚合函数的参数传入聚合函数中,如sum(1),这种情况下你可以省略常量:count()
┌─x─┬────y─┐ │ 1 │ 2 │ │ 2 │ ᴺᵁᴸᴸ │ │ 3 │ 2 │ │ 3 │ 3 │ │ 3 │ ᴺᵁᴸᴸ │ └───┴──────┘ |
┌─sum(x)─┬────y─┐ │ 4 │ 2 │ │ 3 │ 3 │ │ 5 │ ᴺᵁᴸᴸ │ └────────┴──────┘ |
再向GROUP BY 中放入几个key,结果将列出所有的组合可能 |
SELECT sum(x), y FROM t_null_big GROUP BY y |
对于GROUP BY子句,ClickHouse将 NULL 解释为一个值,并且支持NULL=NULL
在JSON*输出格式中,这行将出现在Json的‘totals’字段中。在TabSeparated*输出格式中,这行将位于其他结果之后,同时与其他结果使用空白行分隔。在Pretty*输出格式中,这行将作为单独的表在所有结果之后输出。
WITH TOTALS
与HAVING子句同时存在,它的行为受‘totals_mode’配置的影响。 默认情况下,totals_mode = 'before_having'
,这时WITH TOTALS
将会在HAVING前计算最多不超过max_rows_to_group_by
行的数据。group_by_overflow_mode = 'any'
并指定了max_rows_to_group_by
的情况下,WITH TOTALS
的行为受totals_mode
的影响。after_having_exclusive
- 在HAVING后进行计算,计算不超过max_rows_to_group_by
行的数据。after_having_inclusive
- 在HAVING后进行计算,计算不少于max_rows_to_group_by
行的数据。after_having_auto
- 在HAVING后进行计算,采用统计通过HAVING的行数,在超过不超过‘max_rows_to_group_by’指定值(默认为50%)的情况下,包含所有行的结果。否则排除这些结果。totals_auto_threshold
- 默认 0.5,是after_having_auto
的参数。group_by_overflow_mode != 'any'
并没有指定max_rows_to_group_by
情况下,所有的模式都与after_having
相同。你可以在子查询,包含子查询的JOIN子句中使用WITH TOTALS(在这种情况下,它们各自的总值会被组合在一起)
max_bytes_before_external_group_by
这个配置确定了在GROUP BY中启动将临时数据转存到磁盘上的内存阈值。如果你将它设置为0(这是默认值),这项功能将被禁用。max_bytes_before_external_group_by
时,建议将max_memory_usage设置为它的两倍。因为一个聚合需两个阶段完成:(1)读取数据并形成中间数据 (2)合并中间数据。临时数据的转存只会发生在第一个阶段。如果没有发生临时文件的转存,那么阶段二将最多消耗与1阶段相同的内存大小。 如果将max_memory_usage
设置为10000000000并且你想要开启外部聚合,那需将max_bytes_before_external_group_by
=10000000000,将max_memory_usage
=20000000000。当外部聚合被触发时(如果刚好只形成了一份临时数据),它的内存使用量将会稍高于max_bytes_before_external_group_by
。
在分布式查询处理中,外部聚合将会在远程的服务器中执行。为了使请求服务器只使用较少的内存,可以设置distributed_aggregation_memory_efficient
为1。
当合并被刷到磁盘的临时数据以及合并远程的服务器返回的结果时,如在启动distributed_aggregation_memory_efficient
的情况下,将消耗1/256 * 线程数的总内存大小。
当启动外部聚合时,如果数据的大小小于max_bytes_before_external_group_by
设置的值(数据没有被刷到磁盘中),那么数据的聚合速度将会和没有启动外部聚合时一样快。如果有临时数据被刷到了磁盘中,那么这个查询的运行时间将会被延长几倍(大约是3倍)。
如你在GROUP BY后面存在ORDER BY子句,并且ORDER BY后面存在一个极小限制的LIMIT,那么ORDER BY子句将不会使用太多内存。 否则请不要忘记启动外部排序(max_bytes_before_external_sort
)。
注意:
如查询中不包含distinct、group by、order by及in、join子查询,将使用O(1)数量的内存完成,否则将消耗大量内存,除非设置了
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
https://clickhouse.yandex/docs/zh/query_language/select/