优化Cloud Spanner读取延迟:用户元数据表是否应采用交错设计?
Cloud Spanner交错表设计与读取性能疑问
我为Cloud Spanner数据库设计了利用交错表存储关联记录的表结构以优化读取性能,具体结构如下:
CREATE TABLE all_ids ( userid INT64 NOT NULL, ) PRIMARY KEY(userid); CREATE TABLE connections_in ( userid INT64 NOT NULL, child_userid INT64 NOT NULL, connect_time TIMESTAMP NOT NULL, ) PRIMARY KEY(userid, child_userid), INTERLEAVE IN PARENT all_ids ON DELETE CASCADE; CREATE TABLE connections_out ( userid INT64 NOT NULL, child_userid INT64 NOT NULL, connect_time TIMESTAMP NOT NULL, ) PRIMARY KEY(userid, child_userid), INTERLEAVE IN PARENT all_ids ON DELETE CASCADE;
其中connections_in和connections_out表存储用户数据库节点间的图连接,每个用户最多有数百条连接。
我需要存储用户的元数据历史,每个用户拥有数千条历史元数据记录,不确定是否应将user_metadata表与父表all_ids进行交错设计,当前设计如下:
CREATE TABLE user_metadata ( userid INT64 NOT NULL, snapshot_time TIMESTAMP NOT NULL, username STRING(1024) NOT NULL, user_description STRING(1024) NOT NULL, ) PRIMARY KEY(userid, snapshot_time DESC), INTERLEAVE IN PARENT all_ids ON DELETE CASCADE;
已知Spanner采用字典序排列主键,有两个疑问:
user_metadata的行是否可能与connections_in或connections_out的行物理相邻?- 若情况属实,基于
userid读取connections_in/out的速度是否会慢于将user_metadata设为非交错表(如下设计)的情况?
CREATE TABLE user_metadata ( userid INT64 NOT NULL, snapshot_time TIMESTAMP NOT NULL, username STRING(1024) NOT NULL, user_description STRING(1024) NOT NULL, ) PRIMARY KEY(userid, snapshot_time DESC);
解答
1. 交错表行的物理存储位置
Cloud Spanner中,交错表的行会与父表的对应行物理相邻,所有属于同一父行的交错子表行,会按照子表的主键后缀进行字典序排列。
针对你的结构:
- 父表
all_ids的主键是userid,所有关联子表(connections_in、connections_out、user_metadata)的行,都会跟在对应userid的父行之后。 - 子表行的顺序由主键后缀的字典序决定:
connections_in/connections_out的主键后缀是INT64类型的child_userid,user_metadata的主键后缀是TIMESTAMP类型的snapshot_time DESC。由于两种类型的二进制编码会直接参与字典序比较,user_metadata的行完全可能夹杂在connections_in/connections_out的行之间,且因为每个用户的元数据记录数远多于连接数,会占据同一userid关联行的大部分存储空间。
2. 对connections_in/out读取性能的影响
是的,将user_metadata设为交错表会降低connections_in/out的读取速度,核心原因如下:
- 数据局部性变差:按
userid读取连接记录时,Spanner需要扫描的范围会包含大量无关的user_metadata行,原本只需读取数百条连接记录,现在要跳过数千条元数据记录,增加了IO开销和扫描时间。 - 缓存效率降低:大量元数据记录会占用缓存空间,导致连接记录更难被缓存命中,重复读取的性能会进一步下降。
- 分片压力增加:单个
userid的关联数据(元数据+连接)体积过大时,可能会触发Spanner调整分片策略,增加跨分片读取的概率,间接影响性能。
最优设计建议
鉴于每个用户的元数据记录数远多于连接记录数,建议将user_metadata设为非交错表:
- 非交错表的行存储在独立区域,不会干扰
connections_in/out的数据局部性,读取连接记录时无需扫描无关数据。 - 若需要关联查询元数据和连接记录,
userid作为两个表的主键前缀,Spanner依然可以高效定位数据,跨表查询性能不受影响。 - 保留
connections_in和connections_out的交错设计,这仍能提升这两个表之间或与父表关联读取的性能。
内容的提问来源于stack exchange,提问作者randomdatascientist
相关产品推荐
相关产品推荐

