Cassandra:无法删除含静态列数据表的最后一条记录
我之前也碰到过这个Cassandra的棘手问题,在2.2、3.0以及3.11.2版本中,只要数据表包含静态列,就没法删除它的最后一行数据,不管复制因子设成1还是更大的值都没用。下面是完整的问题重现步骤,以及对应的根因分析和临时解决办法:
问题重现步骤
- 首先创建包含静态列的目标表:
CREATE TABLE playlists ( username text, playlist_id bigint, playlist_order bigint, last_modified bigint static, PRIMARY KEY ((username, playlist_id), playlist_order) ) WITH CLUSTERING ORDER BY (playlist_order DESC);
- 插入几条测试数据到同一个分区里:
INSERT INTO playlists (username, playlist_id, playlist_order, last_modified) VALUES ('alice', 1001, 3, 1690000000); INSERT INTO playlists (username, playlist_id, playlist_order, last_modified) VALUES ('alice', 1001, 2, 1690000100); INSERT INTO playlists (username, playlist_id, playlist_order, last_modified) VALUES ('alice', 1001, 1, 1690000200);
- 先尝试删除非最后一行的数据,这一步是可以正常执行的:
DELETE FROM playlists WHERE username = 'alice' AND playlist_id = 1001 AND playlist_order = 3; DELETE FROM playlists WHERE username = 'alice' AND playlist_id = 1001 AND playlist_order = 2;
- 最后尝试删除剩下的那一行:
DELETE FROM playlists WHERE username = 'alice' AND playlist_id = 1001 AND playlist_order = 1;
执行完这条语句后查询表,你会发现这行数据依然存在,删除操作根本没生效。
背后的原因
这是因为Cassandra里静态列的特性决定的:静态列是属于整个分区(也就是主键里的(username, playlist_id)部分)的,不属于单独某一行。当分区里还有其他行存在时,静态列的值会和分区绑定;但当你要删除分区的最后一行时,Cassandra需要同时清理掉这个分区的静态列数据,而旧版本的Cassandra这里有逻辑缺陷——删除最后一行的操作没能正确触发静态列的清理流程,导致数据库认为这个分区还存在静态列数据,进而保留了最后一行的记录。
临时解决办法
如果暂时没法升级版本,可以试试这两种办法:
- 先清空静态列再删除:在删除最后一行之前,先把静态列的值设为
NULL,再执行删除操作:
UPDATE playlists SET last_modified = NULL WHERE username = 'alice' AND playlist_id = 1001; DELETE FROM playlists WHERE username = 'alice' AND playlist_id = 1001 AND playlist_order = 1;
- 删除整个分区:如果这个分区里已经没有其他需要保留的数据,直接删除整个分区会更简单:
DELETE FROM playlists WHERE username = 'alice' AND playlist_id = 1001;
当然,最彻底的解决办法还是升级到Cassandra 4.0及以上版本,这个bug在高版本里已经被官方修复了。
内容的提问来源于stack exchange,提问作者Erik Sørgaard
相关产品推荐
相关产品推荐

