【问题标题】:Converting PostgreSQL table to TimescaleDB hypertable将 PostgreSQL 表转换为 TimescaleDB 超表
【发布时间】:2021-08-07 11:21:30
【问题描述】:

我有一个 PostgreSQL 表,我正在尝试将其转换为 TimescaleDB 超表。

表格如下:

CREATE TABLE public.data
(
    event_time timestamp with time zone NOT NULL,
    pair_id integer NOT NULL,
    entry_id bigint NOT NULL,
    event_data int NOT NULL,
    CONSTRAINT con1 UNIQUE (pair_id, entry_id ),
    CONSTRAINT pair_id_fkey FOREIGN KEY (pair_id)
        REFERENCES public.pairs (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

当我尝试使用以下命令将此表转换为 TimescaleDB 超表时:

SELECT create_hypertable(
        'data',
        'event_time',
        chunk_time_interval => INTERVAL '1 hour',
        migrate_data => TRUE
);

我收到错误:ERROR: cannot create a unique index without the column "event_time" (used in partitioning)

问题 1: 从这篇帖子 How to convert a simple postgresql table to hypertable or timescale db table using created_at for indexing 我的理解是,这是因为我指定了一个唯一约束 (pair_id_fkey),它不包含我正在分区的列 - event_time。对吗?

问题 2:我应该如何更改我的表或超表才能进行转换?我已经添加了一些关于我计划如何使用数据和数据结构的数据。

数据属性和用途:

  • 可以有多个具有相同 event_time 的条目 - 这些条目的 entry_id 是按顺序排列的
    • 这意味着如果我有 2 个条目 (event_time 2021-05-18::10:16, id 105, ) 和 (event_time 2021-05-18::10:16, id 107, ) 那么 id 为 106 的条目也会有 event_time 2021-05-18::10:16
  • entry_id 不是我生成的,我使用唯一约束 con1 来确保我没有插入重复数据
  • 我将主要在 event_time 上查询数据,例如创建绘图并执行其他分析
  • 此时数据库包含大约 46 亿行,但应该很快会包含更多
  • 我想利用 TimescaleDB 的速度和良好的压缩性能
  • 我不太关心插入性能

我一直在考虑的解决方案:

  • 以某种方式将具有相同时间戳的所有事件打包到一个数组中,并将它们保持在一行中。我认为这会对压缩产生不利影响,并且在查询数据时提供较少的灵活性。此外,我可能最终不得不解压缩每个查询的数据。
  • 删除唯一约束 con1 - 那我如何确保不会将同一行添加两次?
  • 扩展唯一约束 con1 以包含 event_time - 这不会以某种方式降低性能,同时会导致我不小心插入 2 行的 entry_id 和 pair_id 但 event_time 不同的错误? (我怀疑这可能会发生)

【问题讨论】:

    标签: postgresql timescaledb


    【解决方案1】:

    您正确理解UNIQUE (pair_id, entry_id ) 不允许从表创建超表,因为唯一约束需要包含分区键,即在您的情况下为event_time

    1. 我不理解第一个选项如何将具有相同时间戳的记录打包到单个记录中,这将有助于提高唯一性。

    2. 删除唯一约束将允许创建超表,正如您所提到的,您将失去检查约束的可能性。

    3. 添加时间列,例如UNIQUE (pair_id, entry_id, event_time) 是很常见的方法,但它允许插入具有不同时间戳的重复项,如您所述。在插入过程中,它的性能会比选项 2 差。你可以用unique index替换event_time上的索引(这是你需要的,因为你在这个列上查询,它是由TimescaleDB自动创建的),所以你可以节省一点,例如,

    CREATE UNIQUE INDEX indx ON (event_time, pair_id, entry_id);
    
    1. 在每个块表上手动创建唯一约束。这将保证块内的唯一性,但仍然可能在不同的块中有重复。主要缺点是您需要弄清楚在创建新块时如何创建它。

    TimescaleDB 不支持没有分区键的唯一约束,因为它需要访问所有现有块来检查唯一性,并且会降低性能。 (或者它需要创建一个可能很大的全局索引)我不认为时间序列数据具有唯一约束是常见的情况,因为它通常与人工生成的基于计数器的标识符有关。

    【讨论】:

    • 根据您的回答,我倾向于解决方案 3。因为我不太关心插入性能,并且我认为 entry_id 唯一地标识了 event_time。不过我不太明白你的最后一句话。我没有关于 event_time 的索引?我会保存什么?最后,我认为我只需要一个关于 event_time 和 pair_id 的索引,因为我将根据这两个值进行查找。
    • @sev 创建超表时,TimescaleDB 会自动在event_time 上创建索引。抱歉不清楚。
    • 啊,好吧,除了对 (event_time, pair_id, entry_id) 的唯一约束之外,我会在迁移到 timescaledb 之前在 postgres 中创建一个索引 (event_time, pair_id, entry_id) 然后说不要t 创建默认索引?
    • 我用关于默认索引的信息更新了选项 3。
    • @sev 创建唯一索引就足够了。请参阅我的答案中的语法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 2020-05-15
    • 2018-11-22
    • 2020-01-14
    • 2021-02-03
    相关资源
    最近更新 更多