Timescale Cloud:性能、规模、企业级

自托管产品

MST

自 TimescaleDB v2.20.0 起成为旧 API,已由 CREATE TABLE 取代。

将标准 PostgreSQL 关系表替换为按单个维度分区的超表

超表是 PostgreSQL 表,可按时间自动对数据进行分区。维度定义了数据分区的方式。所有操作都在生成的超表上进行。例如,ALTER TABLESELECT

如果要转换的表已包含数据,请将 migrate_data 设置为 TRUE。但是,这可能需要很长时间,并且当表包含外键约束时存在限制。

您不能在已使用 声明式分区继承分区的表上运行 create_hypertable()。时间列必须定义为 NOT NULL。如果表创建时未指定此项,create_hypertable 在执行时会自动向表中添加此约束。

本页描述了 TimescaleDB v2.13 中引入的通用超表 API。create_hypertable 的旧接口也可用

在调用 create_hypertable 之前,您需要创建一个标准的 PostgreSQL 关系表。例如:

CREATE TABLE conditions (
time TIMESTAMPTZ NOT NULL,
location text NOT NULL,
temperature DOUBLE PRECISION NULL
);

以下示例演示了如何从现有表或函数创建超表

以下示例展示了创建超表的不同方式

  • time 列上使用范围分区进行转换

    SELECT create_hypertable('conditions', by_range('time'));
  • 转换为 24 小时 set_chunk_time_interval:选择以下任一方式

    SELECT create_hypertable('conditions', by_range('time', 86400000000));

    SELECT create_hypertable('conditions', by_range('time', INTERVAL '1 day'));
  • time 列上使用范围分区,如果 conditions 已经是超表,则不发出警告

    SELECT create_hypertable('conditions', by_range('time'), if_not_exists => TRUE);
注意

如果您调用 SELECT * FROM create_hypertable(...),返回值将格式化为带有列标题的表。

以下示例展示了如何使用范围分区函数,在复合列类型上对 measurements 关系表进行时间分区。

  1. 创建报告类型,然后创建一个将列值转换为支持的列值的不可变函数

    CREATE TYPE report AS (reported timestamp with time zone, contents jsonb);
    CREATE FUNCTION report_reported(report)
    RETURNS timestamptz
    LANGUAGE SQL
    IMMUTABLE AS
    'SELECT $1.reported';
  2. 使用不可变函数创建超表

    SELECT create_hypertable('measurements', by_range('report', partition_func => 'report_reported'));

以下示例展示了如何对 events 表按 jsonbevent)列类型进行时间分区,该列类型有一个包含 ISO 8601 格式时间戳的顶级 started

CREATE FUNCTION event_started(jsonb)
RETURNS timestamptz
LANGUAGE SQL
IMMUTABLE AS
$func$SELECT ($1->>'started')::timestamptz$func$;
SELECT create_hypertable('events', by_range('event', partition_func => 'event_started'));
名称类型默认值是否必需描述
create_default_indexesBOOLEANTRUE在时间/分区列上创建默认索引。
dimensionDIMENSION_INFO-要创建 _timescaledb_internal.dimension_info 实例以分区超表,您可以调用 by_rangeby_hash
if_not_existsBOOLEANFALSE设置为 TRUE 可在 relation 已是超表时打印警告。默认情况下,会引发异常。
migrate_dataBOOLEANFALSE设置为 TRUE 以将 relation 中任何现有数据迁移到新超表的分块中。根据要迁移的数据量,设置 migrate_data 可能会长时间锁定表。如果数据中存在指向其他表的外键约束create_hypertable() 可能会遇到死锁。超表只能包含指向另一个超表的外键。UNIQUEPRIMARY 约束必须包含分区键。
当并发事务同时尝试将数据插入外键约束中引用的表以及正在转换的表本身时,可能会发生死锁。为避免死锁,请在调用 create_hypertable 的同一事务中,手动获取引用表上的 SHARE ROW EXCLUSIVE 锁。
如果您将 migrate_data 保持默认设置,则在调用 create_hypertable 时,非空表将生成错误。
relationREGCLASS-要转换为超表的表标识符。

要创建 _timescaledb_internal.dimension_info 实例,您可以调用 add_dimension 到现有超表。

超表必须始终具有主范围维度,后跟任意数量的附加维度,可以是范围或哈希维度。通常这只是一个哈希维度。例如:

SELECT add_dimension('conditions', by_range('time'));
SELECT add_dimension('conditions', by_hash('location', 2));

对于不兼容的数据类型(如 jsonb),您可以为维度构建的 partition_func 参数指定一个函数来提取兼容的数据类型。请参阅下面的示例部分。

默认情况下,TimescaleDB 调用 PostgreSQL 内部的给定类型的哈希函数。对于没有原生 PostgreSQL 哈希函数的值类型,您可以使用自定义分区函数。

您可以为范围分区和哈希分区指定自定义分区函数。分区函数应以 anyelement 参数作为唯一参数,并返回一个正 integer 哈希值。此哈希值*不是*分区标识符,而是插入值在维度键空间中的位置,然后将其分配到各个分区中。

创建按范围的维度构建器。您可以单独使用 by_range 进行分区。

示例
  • 使用 CREATE TABLE 按时间分区

    最简单的用法是按时间列进行分区

    CREATE TABLE conditions (
    time TIMESTAMPTZ NOT NULL,
    location TEXT NOT NULL,
    device TEXT NOT NULL,
    temperature DOUBLE PRECISION NULL,
    humidity DOUBLE PRECISION NULL
    ) WITH (
    tsdb.hypertable,
    tsdb.partition_column='time'
    );

    如果您是自托管 TimescaleDB v2.19.3 及以下版本,请先创建 PostgreSQL 关系表,然后使用 create_hypertable 进行转换。然后通过调用 ALTER TABLE 启用 Hypercore。

    这是默认分区,您无需显式添加。

  • 使用 create_hypertable 从非时间列中提取时间

    如果您的表有一个包含时间的非时间列(例如 JSON 列),请添加一个分区函数来提取时间

    CREATE TABLE my_table (
    metric_id serial not null,
    data jsonb,
    );
    CREATE FUNCTION get_time(jsonb) RETURNS timestamptz AS $$
    SELECT ($1->>'time')::timestamptz
    $$ LANGUAGE sql IMMUTABLE;
    SELECT create_hypertable('my_table', by_range('data', '1 day', 'get_time'));
参数
名称类型默认值是否必需描述
column_nameNAME-要进行分区的列名称。
partition_funcREGPROC-用于计算值分区的函数。
partition_intervalANYELEMENT-列分区的时间间隔。

如果待分区的列是:

  • TIMESTAMPTIMESTAMPTZDATE:将 partition_interval 指定为 INTERVAL 类型或以*微秒*为单位的整数值。

  • 另一种整数类型:将 partition_interval 指定为一个整数,该整数反映了列的底层语义。例如,如果此列以 UNIX 时间表示,则以毫秒为单位指定 partition_interval

分区类型和默认值取决于列类型:

列类型分区类型默认值
TIMESTAMP WITHOUT TIMEZONEINTERVAL/INTEGER1 周
TIMESTAMP WITH TIMEZONEINTERVAL/INTEGER1 周
DATEINTERVAL/INTEGER1 周
SMALLINTSMALLINT10000
INTINT100000
BIGINTBIGINT1000000

哈希分区的主要目的是在同一时间间隔内实现多个磁盘的并行化。哈希分区中的每个不同项都被哈希到 N 个桶中的一个。默认情况下,TimescaleDB 使用灵活的范围间隔来管理分块大小。

您在以下场景中使用并行 I/O:

  • 两个或更多并发查询应能够并行从不同磁盘读取。
  • 单个查询应能够使用查询并行化从多个磁盘并行读取。

对于以下选项:

  • RAID:在多个物理磁盘上使用 RAID 设置,并将单个逻辑磁盘暴露给超表。也就是说,使用单个表空间。

    最佳实践是尽可能使用 RAID,因为您无需在数据库中手动管理表空间。

  • 多个表空间:对于每个物理磁盘,向数据库添加一个单独的表空间。TimescaleDB 允许您向*单个*超表添加多个表空间。然而,尽管在底层,超表的分块分布在与该超表关联的表空间中。

    使用多个表空间时,最佳实践是向超表添加第二个哈希分区维度,并为每个磁盘至少分配一个哈希分区。虽然单个时间维度也可以工作,但这将意味着第一个分块写入一个表空间,第二个写入另一个表空间,依此类推,因此只有当查询的时间范围超过单个分块时才能并行化。

添加哈希分区维度时,将分区数量设置为磁盘数量的倍数。例如,分区数量 P=N*Pd,其中 N 是磁盘数量,Pd 是每个磁盘的分区数量。这使您可以在以后添加更多磁盘,并将分区从其他磁盘移动到新磁盘。

TimescaleDB 不会从非常大数量的哈希分区中受益,例如您预期分区字段中包含的唯一项的数量。非常大数量的哈希分区会导致每个分区的负载均衡(使用哈希将项映射到分区)效果更差,并且某些类型查询的规划延迟也会大大增加。

示例
CREATE TABLE conditions (
"time" TIMESTAMPTZ NOT NULL,
location TEXT NOT NULL,
device TEXT NOT NULL,
temperature DOUBLE PRECISION NULL,
humidity DOUBLE PRECISION NULL
) WITH (
tsdb.hypertable,
tsdb.partition_column='time',
tsdb.chunk_interval='1 day'
);
SELECT add_dimension('conditions', by_hash('location', 2));
参数
名称类型默认值是否必需描述
column_nameNAME-要进行分区的列名称。
partition_funcREGPROC-用于计算值分区的函数。
number_partitionsANYELEMENT-用于 partitioning_column 的哈希分区数量。必须大于 0。

by_rangeby-hash 返回一个不透明的 _timescaledb_internal.dimension_info 实例,其中包含此函数使用的维度信息。

类型描述
hypertable_idINTEGER您创建的超表的 ID。
createdBOOLEAN超表创建时为 TRUE。当 if_not_existstrue 且未创建超表时为 FALSE

关键词

发现此页面有问题?报告问题 或 在 GitHub 上编辑此页面