大数据开发ClickHouse常用的数据类型及使用(第五十六篇)

468 阅读9分钟

这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情

一、常用数据类型

ClickHouse可以在数据库表中存储多种数据类型。可以通过下面的命令查看clickhouse支持哪些数据类型:

select * from system.data_type_families;

1.1、整型

固定长度的整型,包含无符号整型和有符号整型

有符号整型
类型取值范围别名
Int8-128~127TINYINT、BOOLEAN、BOOL、INT1
Int16-32768~32767SMALLINT、INT2
Int32-2147483648~2147483647INT、INT4、INTEGER
Int64-170141183460469231731687303715884105728~170141183460469231731687303715884105727BIGINT
无符号整型
类型取值范围
UInt80~255
UInt160~65535
UInt320~4294967295
UInt640~18446744073709551615
UInt1280~340282366920938463463374607431768211455
UInt2560~115792089237316195423570985008687907853269984665640564039457584007913129639935
1.2、浮点型
  1. Float32-float
  2. Float64-double

尽可能以整数形式存储数据。例如,将固定精度的数字转换为整数值,例如货币数量或页面加载时间用毫秒为单位表示

对浮点数进行计算可能引起四舍五入的误差。

SELECT 1 - 0.9

image-20230215211718494

1.3、NaN和Inf
  1. Inf – 正无穷

    SELECT 0.5 / 0;

    image-20230215211908113

  2. -Inf – 负无穷

    SELECT -0.5 / 0;

    image-20230215211949489

  3. NaN – 非数字

    SELECT 0 / 0;

    image-20230215212018443

1.4、Decimal

有符号的定点数,可在加、减和乘法运算过程中保持精度。对于除法,最低有效数字会被丢弃(不舍入)。

参数:

  • P - 精度。有效范围:[1:38],决定可以有多少个十进制数字(包括分数)。
  • S - 规模。有效范围:[0:P],决定数字的小数部分中包含的小数位数。

类似MySQL的BigDecimal(18,2)。18位数字,小数点后保留2位小数

Decimal还区分:Decimal32、Decimal64、Decimal128

  • -P从[1:9] 使用Decimal32
  • -P从[10:18] 使用Decimal64
  • -P从[19:38] 使用Decimal128

SELECT toDecimal32(2, 4) AS x, x / 3;

image-20230215213512693

精度规则
  • 加法,减法:S = max(S1, S2)。取s1,s2中最大的精度
  • 乘法:S = S1 + S2。取s1,s2精度之和
  • 除法:S = S1。 取被除数 eg: 2/3 2是被除数,3是除数

select toDecimal64(2,3) as x,toTypeName(x) as xType,toDecimal64(1,2) as y,toTypeName(y) as yType,x-y as z,toTypeName(z) as zType;

image-20230215213413564

1.5、布尔值

ClickHouse里面没有单独的类型来存储布尔值。可以使用UInt8类型,取值限制为0和1

image-20230215214119835

image-20230215214107313

1.6、字符串类型

clickhouse里面的字符串有好几个类型:

  1. 字符串

    字符串可以任意长度的。它可以包含任意的字节集,包含空字节。因此,字符串类型可以代替其他 DBMSs 中的 VARCHAR、BLOB、CLOB 等类型。

    ClickHouse 没有编码的概念。字符串可以是任意的字节集,按它们原本的方式进行存储和输出。 若需存储文本,我们建议使用 UTF-8 编码。

  2. 固定字符串

    固定长度 N 的字符串(N 必须是严格的正自然数)。您可以使用下面的语法对列声明为FixedString类型:

    <column_name> FixedString(N)

    当向ClickHouse中插入数据时,

    • 如果字符串包含的字节数少于`N’,将对字符串末尾进行空字节填充。
    • 如果字符串包含的字节数大于N,将抛出Too large value for FixedString(N)异常。
  3. UUID

    通用唯一标识符(UUID)是一个16字节的数字,用于标识记录。

    select generateUUIDv4();

    image-20230215215938916

    如果在插入新记录时未指定UUID列的值,则UUID值将用零填充:

    00000000-0000-0000-0000-000000000000

1.7、时间类型

clickhouse里面有几个时间类型Date、DateTime、DateTime64

  1. Data

    日期类型,用两个字节存储,表示从 1970-01-01 (无符号) 到当前的日期值。允许存储从 Unix 纪元开始到编译阶段定义的上限阈值常量(目前上限是2106年,但最终完全支持的年份为2105)。最小值输出为1970-01-01。

    CREATE TABLE date_test(current_date Date) ENGINE=Memory;

    image-20230215220528681

    insert into date_test values('2023-02-15');

    image-20230215220648822

    image-20230215220706562

  2. DateTime

    时间戳类型。用四个字节(无符号的)存储 Unix 时间戳)。允许存储与日期类型相同的范围内的值。最小值为 1970-01-01 00:00:00。时间戳类型值精确到秒(没有闰秒)。

    值的范围: [1970-01-01 00:00:00, 2106-02-07 06:28:15]。

    使用启动客户端或服务器时的系统时区,时间戳是从文本(分解为组件)转换为二进制并返回。在文本格式中,有关夏令时的信息会丢失。

    默认情况下,客户端连接到服务的时候会使用服务端时区。您可以通过启用客户端命令行选项 --use_client_time_zone 来设置使用客户端时间。

  3. DateTime64

    此类型允许以日期(date)加时间(time)的形式来存储一个时刻的时间值,具有定义的亚秒精度

    DateTime64(precision, [timezone])

    SELECT toDateTime64(now(), 3, 'Asia/Shanghai');

    image-20230215221244677

    SELECT toDateTime64(now(), 4, 'Asia/Shanghai');

    image-20230215221316497

1.8、数组

由T类型元素组成的数组。T可以是任意类型,包含数组类型,但是不推荐使用多维数组,ClickHouse对多维数组支持有限

创建数组

array(T)或者[]

SELECT array(1, 2) AS x, toTypeName(x);

SELECT [1, 2] AS x, toTypeName(x)

image-20230215221544781

1.9、元组

元组,其中每个元素都有单独的 类型。

不能在表中存储元组(除了内存表)。它们可以用于临时列分组。在查询中,IN 表达式和带特定参数的 lambda 函数可以来对临时列进行分组。

创建元组

tuple(T1, T2, ...)

SELECT tuple(1,'a') AS x, toTypeName(x);

image-20230215221816841

1.10、嵌套数据结构

嵌套数据结构类似于嵌套表。嵌套数据结构的参数(列名和类型)与 CREATE 查询类似。每个表可以包含任意多行嵌套数据结构。

CREATE TABLE test
(
    name String,
    age Int8,
    works Nested
    (
      id UInt8,
      location String
    )
) ENGINE = Memory;

insert into table test values('zhangsan',20,[1],['上海']);

image-20230215222442607

二、数据库\表创建

2.1、创建数据库

CREATE DATABASE [IF NOT EXISTS] db_name;

2.2、创建数据表

CREATE TABLE [IF NOT EXISTS] [db.]table_name AS [db2.]name2 [ENGINE = engine]

三、数据库引擎

3.1、Lazy

在最后一次访问之后,只在RAM中保存expiration_time_in_seconds秒,只能用于Log表,它是为了存储许多小Log表而优化的

CREATE DATABASE testlazy ENGINE = Lazy(expiration_time_in_seconds);
3.2、Atomic

默认情况下,使用Atomic数据库引擎。它支持非阻塞的DROP TABLE和RENAME TABLE查询和原子的EXCHANGE TABLES t1 AND t2查询

CREATE DATABASE test[ ENGINE = Atomic];
3.3、MySQL

用于将远程MySQL服务器中的表映射到ClickHouse中,并允许对表进行insertselect查询,方便在clickhouse和mysql之间进行数据库交换

CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster]
ENGINE = MySQL('host:port', ['database' | database], 'user', 'password')

四、表的引擎

表引擎决定了

  1. 数据的存储方式和位置,写到哪里以及从哪里读取数据
  2. 支持哪些查询以及如何支持
  3. 并发数据访问
  4. 索引的使用
  5. 是否可以执行多线程请求
  6. 数据副本参数
4.1、日志引擎

这些引擎是为了写入许多小数据量(少于一百万)的表的场景而开发的。日志引擎包含:

  • StripeLog
  • Log
  • TinyLog
TinyLog

最简单的表引擎,用于将数据存储在磁盘上。每列都存储在单独的压缩文件中。写入时,数据将附加到文件末尾。并发数据访问不受任何限制:

  • 如果同时从表中读取并在不同的查询中写入,则读取操作将抛出异常
  • 如果同时写入多个查询中的表,则数据将被破坏。

适用场景:

这种表引擎的典型用法是 write-once:首先只写入一次数据,然后根据需要多次读取。查询在单个流中执行。换句话说,此引擎适用于相对较小的表(建议最多1,000,000行)。如果您有许多小表,则使用此表引擎是适合的,因为它比Log引擎更简单(需要打开的文件更少)。当您拥有大量小表时,可能会导致性能低下,但在可能已经在其它 DBMS 时使用过,则您可能会发现切换使用 TinyLog 类型的表更容易。不支持索引

测试:

create database test_table_engine;

use test_table_engine;

create table test_tinylog(id UInt16,name String)engine=TinyLog;

插入数据

insert into test_tinylog values(1,'zhangsan'),(2,'lisi');

image-20230216223628165

image-20230216223638677

查询存储位置

/var/lib/clickhouse/data

image-20230216223747137

此时我们可以看到id.bin是存储的id列的数据,name.bin存储的是name列的数据

StripeLog

StripeLog 引擎将所有列存储在一个文件中。对每一次 Insert 请求,ClickHouse 将数据块追加在表文件的末尾,逐列写入。

ClickHouse 为每张表写入以下文件:

  • data.bin — 数据文件。
  • index.mrk — 带标记的文件。标记包含了已插入的每个数据块中每列的偏移量。

StripeLog 引擎不支持 ALTER UPDATEALTER DELETE 操作。

带标记的文件使得 ClickHouse 可以并行的读取数据。这意味着 SELECT 请求返回行的顺序是不可预测的。使用 ORDER BY 子句对行进行排序。

Log

LogTinyLog 的不同之处在于,«标记» 的小文件与列文件存在一起。这些标记写在每个数据块上,并且包含偏移量,这些偏移量指示从哪里开始读取文件以便跳过指定的行数。这使得可以在多个线程中读取表数据。对于并发数据访问,可以同时执行读取操作,而写入操作则阻塞读取和其它写入。Log引擎不支持索引。同样,如果写入表失败,则该表将被破坏,并且从该表读取将返回错误。Log引擎适用于临时数据,write-once 表以及测试或演示目的。

五、Java代码接入ClickHouse

5.1、引入pom文件
<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>clickhouse-jdbc</artifactId>
    <version>0.4.0</version>
</dependency>
更改clickhouse 配置

修改/etc/clickhouse-server目录下的config.xml配置,启用listen_host标签

image-20230216230338120

重启

sudo /etc/init.d/clickhouse-server start

package com.strivelearn.clickhouse;
​
import java.sql.*;
​
/**
 * @author strivelearn
 * @version ClickHouseTest.java, 2023年02月16日
 */
public class ClickHouseTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.clickhouse.jdbc.ClickHouseDriver");
        String url = "jdbc:clickhouse://192.168.234.100:8123/test_table_engine";
        Connection connection = DriverManager.getConnection(url);
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery("select * from test_tinylog");
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            System.out.println("id = " + id);
            System.out.println("name = " + name);
        }
        resultSet.close();
        statement.close();
        connection.close();
    }
}

输出

id = 1
name = zhangsan
id = 2
name = lisi