我是靠谱客的博主 傻傻舞蹈,最近开发中收集的这篇文章主要介绍clickHouse之SQL语法之select(—)select,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

select

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]

from子句

1、从哪个表、子查询(构建在外部查询的内部,外部没有用到的列将被忽略)、表函数取数据

2、查询中未列出如何的列select count() from test,将额外从表中取些列以计算行数

3、final使查询结果在查询过程中被聚合,仅能用在SELECT from CollapsingMergeTree中

      在单个流中读取所有相关的主键列,合并需要的数据(查询变慢,避免使用)

 

sample子句

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、相同采样率(建表使用相同采用表达式)得到结果一致

 

array join子句

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]
│

 

join子句

SELECT <expr_list>
FROM <left_subquery>
[GLOBAL] [ANY|ALL] INNER|LEFT|RIGHT|FULL|CROSS [OUTER] JOIN <right_subquery>
(ON <expr_list>)|(USING <column_list>) ...

any与all

all:同SQL的JOIN,右表存在多个与左表关联的数据

any:右表存在多个与左关联的数据,仅返回第一各与左表匹配的数据

global distribution

普通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。更多信息,参见 外部字典 部分。

 

null的处理

1、JOIN的行为受 join_use_nulls 的影响。当join_use_nulls=1时,JOIN的工作与SQL标准相同。

2、如果JOIN的key是 Nullable 类型的字段,则至少一个存在 NULL 值的key不会被关联。

 

where子句

   该子句中须包含一个UInt8类型的表达式:通常是一个带有比较和逻辑的表达式:在所有数据转换前用来过滤数据;如果在支持索引的数据库表引擎中,这个表达式将被评估是否使用索引

 

PREWHERE 子句

   与WHERE子句的意思相同。主要不同在于表数据的读取;PREWHERE 仅支持*MergeTree系列引擎

  • 使用PREWHERE,只读取PREWHERE表达式中需要的列,根据PREWHERE执行的结果读取其他需要的列。
  • 如在过滤条件中有少量不适合索引过滤的列,但它们又可提供很强的过滤能力,使用PREWHERE很有意义,帮助减少数据的读取。

         例如,在一个需要提取大量列的查询中为少部分列编写PREWHERE是很有作用的。

1、在一个查询中可以同时指定PREWHERE和WHERE,在这种情况下,PREWHERE优先于WHERE执行

 2、PREWHERE不适合用于已经存在于索引中的列:列已经存在于索引中,只有满足索引的数据块才会被读取。

3、如将'optimize_move_to_prewhere'设置为1,并且在查询中不包含PREWHERE,则系统将自动的把适合PREWHERE表达式的部分从WHERE中抽离到PREWHERE中。

 

group by

  必含一个表达式列表,每个表达式将被称之为“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

 

null处理

   对于GROUP BY子句,ClickHouse将 NULL 解释为一个值,并且支持NULL=NULL

   

WITH TOTALS 修饰符

  • 将会在结果中得到一个被额外计算出的行,这一行中将包含所有key的默认值(零或者空值),以及所有聚合函数对所有被选择数据行的聚合结果;该行仅在JSON*, TabSeparated*, Pretty*输出格式中与其他行分开输出。

        在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(在这种情况下,它们各自的总值会被组合在一起)

 

GROUP BY 使用外部存储设备

  • 你可以在GROUP BY中允许将临时数据转存到磁盘上,以限制对内存的使用。 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/

最后

以上就是傻傻舞蹈为你收集整理的clickHouse之SQL语法之select(—)select的全部内容,希望文章能够帮你解决clickHouse之SQL语法之select(—)select所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部