Timescale Cloud:性能、规模、企业级
自托管产品
MST
本页面包含来自 TimescaleDB 社区 关于如何解决常见问题的建议。使用这些代码示例作为指导,处理您自己的数据。
要遵循本页的步骤
创建一个启用时序和分析的目标 Timescale Cloud 服务。
您需要您的连接详细信息。此过程也适用于自托管的 TimescaleDB。
本节包含关于超表的秘籍。
想要从现有超表中移除重复项?一种方法是运行 `PARTITION BY` 查询以获取 `ROW_NUMBER()`,然后获取 `row_number>1` 的行的 `ctid`。然后删除这些行。但是,您需要检查 `tableoid` 和 `ctid`。这是因为 `ctid` 并非唯一,并且可能在不同的块中重复。以下代码示例处理一个包含 4000 万行的表耗时 17 小时
CREATE OR REPLACE FUNCTION deduplicate_chunks(ht_name TEXT, partition_columns TEXT, bot_id INT DEFAULT NULL)RETURNS TABLE(chunk_schema name,chunk_name name,deleted_count INT)AS$$DECLAREchunk RECORD;where_clause TEXT := '';deleted_count INT;BEGINIF bot_id IS NOT NULL THENwhere_clause := FORMAT('WHERE bot_id = %s', bot_id);END IF;FOR chunk INSELECT c.chunk_schema, c.chunk_nameFROM timescaledb_information.chunks cWHERE c.hypertable_name = ht_nameLOOPEXECUTE FORMAT('WITH cte AS (SELECT ctid,ROW_NUMBER() OVER (PARTITION BY %s ORDER BY %s ASC) AS row_num,*FROM %I.%I%s)DELETE FROM %I.%IWHERE ctid IN (SELECT ctidFROM cteWHERE row_num > 1)RETURNING 1;', partition_columns, partition_columns, chunk.chunk_schema, chunk.chunk_name, where_clause, chunk.chunk_schema,chunk.chunk_name)INTO deleted_count;RETURN QUERY SELECT chunk.chunk_schema, chunk.chunk_name, COALESCE(deleted_count, 0);END LOOP;END$$ LANGUAGE plpgsql;SELECT *FROM deduplicate_chunks('nudge_events', 'bot_id, session_id, nudge_id, time', 2540);
特别感谢 **Mathias Ose** 和 **Christopher Piggott** 提供此秘籍。
假设有一个查询,它通过共享键将一个超表连接到另一个表
SELECT timestamp,FROM hypertable as hJOIN related_table as rtON rt.id = h.related_table_idWHERE h.timestamp BETWEEN '2024-10-10 00:00:00' AND '2024-10-17 00:00:00'
如果您对此查询运行 `EXPLAIN`,您会看到查询规划器在这两个表之间执行 `NestedJoin`,这意味着多次查询超表。即使超表索引良好,如果它也很庞大,查询也会很慢。如何强制只执行一次查找?使用具象化的公共表表达式 (CTE)。
如果您使用 CTE 将查询分成两部分,您可以具象化超表查找并强制 PostgreSQL 只执行一次。
WITH cached_query AS materialized (SELECT *FROM hypertableWHERE BETWEEN '2024-10-10 00:00:00' AND '2024-10-17 00:00:00')SELECT *FROM cached_query as cJOIN related_table as rtON rt.id = h.related_table_id
现在,如果您再次运行 `EXPLAIN`,您会看到此查询只执行一次查找。根据您的超表大小,这可能会使一个耗时数小时的查询缩短到仅仅几秒钟。
特别感谢 **Rowan Molony** 提供此秘籍。
本节包含解决物联网问题的秘籍
窄表和中等宽度表是存储物联网数据的好方法。许多原因在《设计您的数据库模式:PostgreSQL 的宽表 vs. 窄表》中都有阐述。
窄表的主要优点之一是,当您添加新传感器时,模式不必更改。另一个重要优点是每个传感器可以以不同的速率和时间进行采样。这有助于支持诸如滞后现象,即除非值变化达到一定量,否则很少写入新值。
使用窄表数据结构会带来一些挑战。在物联网领域,一个问题是许多数据分析方法——包括机器学习和更传统的数据分析——都要求您的数据被重新采样并同步到一个共同的时间基准。幸运的是,TimescaleDB 为您提供了超函数和其他工具来帮助您处理这些数据。
一个窄表格式的示例如下
ts | sensor_id | value |
---|---|---|
2024-10-31 11:17:30.000 | 1007 | 23.45 |
通常,您可以将其与一个传感器表结合使用
sensor_id | sensor_name | units |
---|---|---|
1007 | 温度 | 摄氏度 |
1012 | 加热模式 | 开/关 |
1013 | 冷却模式 | 开/关 |
1041 | 占用率 | 房间人数 |
中等宽度的表保留了通用结构,但添加了各种类型的列,以便您可以使用同一张表存储浮点数、整数、布尔值甚至 JSON (jsonb) 数据
ts | sensor_id | d | i | b | t | j |
---|---|---|---|---|---|---|
2024-10-31 11:17:30.000 | 1007 | 23.45 | null | null | null | null |
2024-10-31 11:17:47.000 | 1012 | null | null | TRUE | null | null |
2024-10-31 11:18:01.000 | 1041 | null | 4 | null | null | null |
要移除所有空值条目,请使用可选约束,例如
CONSTRAINT at_least_one_not_nullCHECK ((d IS NOT NULL) OR (i IS NOT NULL) OR (b IS NOT NULL) OR (j IS NOT NULL) OR (t IS NOT NULL))
有几种方法可以获取每个传感器的最新值。以下示例使用窄表格式示例中定义的结构作为参考
`SELECT DISTINCT ON`
如果您有一个传感器列表,获取每个传感器最新值的简单方法是使用 `SELECT DISTINCT ON`
WITH latest_data AS (SELECT DISTINCT ON (sensor_id) ts, sensor_id, dFROM iot_dataWHERE d is not nullAND ts > CURRENT_TIMESTAMP - INTERVAL '1 week' -- importantORDER BY sensor_id, ts DESC)SELECTsensor_id, sensors.name, ts, dFROM latest_dataLEFT OUTER JOIN sensors ON latest_data.sensor_id = sensors.idWHERE latest_data.d is not nullORDER BY sensor_id, ts; -- Optional, for displaying results ordered by sensor_id
上面使用的公共表表达式 (CTE) 并非严格必要。但是,它是一种优雅的方式来连接传感器列表,以在输出中获取传感器名称。如果您不关心这一点,可以将其省略。
SELECT DISTINCT ON (sensor_id) ts, sensor_id, dFROM iot_dataWHERE d is not nullAND ts > CURRENT_TIMESTAMP - INTERVAL '1 week' -- importantORDER BY sensor_id, ts DESC
在向下选择此数据时,务必小心。在前面的示例中,查询回溯的时间是有限的。但是,如果有些传感器长时间未报告,或者在最坏的情况下从未报告,则此查询将退化为全表扫描。
在一个拥有 1000 多个传感器和 4100 万行的数据库中,不受约束的查询需要一个多小时。
`SELECT DISTINCT ON` 的一个替代方法是使用 `JOIN LATERAL`。通过从传感器表中选择整个传感器列表,而不是使用 `SELECT DISTINCT` 提取 ID,`JOIN LATERAL` 可以在性能方面提供一些改进。
SELECT sensor_list.id, latest_data.ts, latest_data.dFROM sensors sensor_list-- Add a WHERE clause here to downselect the sensor list, if you wishLEFT JOIN LATERAL (SELECT ts, dFROM iot_data raw_dataWHERE sensor_id = sensor_list.idORDER BY ts DESCLIMIT 1) latest_data ON trueWHERE latest_data.d is not null -- only pulling out float values ("d" column) in this exampleAND latest_data.ts > CURRENT_TIMESTAMP - interval '1 week' -- importantORDER BY sensor_list.id, latest_data.ts;
限制时间范围很重要,特别是当您拥有大量数据时。最佳实践是将这类查询用于仪表板和快速状态检查。要在更大的时间范围内进行查询,请将前面的示例封装到一个不经常刷新(例如每天一次)的具象化查询中。
特别感谢 **Christopher Piggott** 提供此秘籍。
在本页面上发现问题?报告问题 或 在 GitHub 上编辑此页面
。