历史数据保序导入
ProtonBase 选择 LSM Tree(Log-Structured Merge Tree)作为其底层存储结构,是一个非常合理的选择,尤其是在处理大规模数据、高吞吐和高并发的场景下。作为一个高性能的分布式数据库,ProtonBase 需要处理大规模的数据写入和更新,特别是在数据仓库和实时数据分析场景下。LSM Tree能够满足这种高吞吐量写入的需求,避免了像传统B树那样频繁的随机写入操作带来的性能瓶颈。
在业务迁移到 ProtonBase 的过程中,往往需要将存量数据一次性导入 ProtonBase。可能会通过datax/teleport/dts等同步工具,也可能会使用copy的批量导入方式。但无论哪种方式导入,都有可能因为数据的时间序写入被破坏造成在有 时间range查询的query性能退化 的问题。
下面将从原因和 ProtonBase 提供的最佳实践来描述这个问题和解决方案。
问题描述
LSM Tree 的核心特性是顺序写入和后台合并。当数据被批量写入 ProtonBase 时,首先进入内存中的 MemTable,然后定期合并到磁盘上的 SSTable 文件。写入顺序并不一定保持数据的时间顺序,因为数据会被批量整理和合并,在此过程中可能会打乱原始数据的时间顺序。这就可能导致数据的存储顺序在物理层面不再按照时间顺序排列。进一步会影响数据的时间范围查询的效率。
在许多应用中,尤其是涉及时间过滤或时间范围查询的场景(如日志数据、监控数据、IoT数据等),时间戳通常是最重要的查询条件。而当数据存储时是按时间顺序组织的,基于时间的查询可以通过以下几种方式得到优化:
-
列存表优化:列存表存储方式在读取时可以只扫描与查询条件相关的列,而忽略其他无关列。如果数据在物理存储中是按时间顺序排列的,那么扫描一个时间范围内的数据就可以更高效地进行,因为数据已经在物理存储上是有序的,查询时的跳跃扫描较少,I/O成本也会降低。
-
时间过滤的优化:在有序存储结构中,比如列存表按时间顺序排列数据,可以利用索引或范围扫描等技术,更高效地定位到符合时间范围的部分数据,而不需要扫描整个数据集
由于数据在从应用层写入数据库或者数仓系统时,天然是按时间序进行写入的。所以在做业务迁移时,需要通过一定方式来将导入 ProtonBase 的存量数据进行保时间序操作,避免因为时间序被打乱造成的时间过滤相关查询sql性能回退。
最佳实践
在 ProtonBase 中,解决按时间顺序导入数据的主要方法是使用一个GUC参数来指定一个字段,确保在执行 COPY 或 INSERT 操作时,按照指定字段(如时间戳字段)的顺序导入数据。
- 指定时间字段: 在执行数据导入之前,你需要设置会话级别的GUC参数,指定你希望使用的时间字段(例如
event_time
或created_at
等)。这一字段的顺序将会影响数据写入的顺序。
-- 1.0版本
SET experimental_copy_processing_time_field = 'event_time';
-- 1.1版本
SET experimental_processing_time_field = 'event_time';
- 执行数据导入: 一旦设置了GUC参数后,你就可以进行数据导入操作。此时ProtonBase会根据你指定的时间字段,确保数据按时间顺序写入。你可以使用
COPY
或INSERT
命令导入数据。