Cassandra 中的动态模式更改
Dynamic schema changes in Cassandra
我有很多用户(150-2 亿)。每个用户有 N(30-100) 个属性。该属性可以是整数、文本或时间戳类型。属性未知,所以我想动态添加它们。
解决方案 1 - 通过更改 table
添加新列
CREATE TABLE USER_PROFILE(
UID uuid PRIMARY KEY,
LAST_UPDATE_DATE TIMESTAMP,
CREATION_DATE TIMESTAMP
);
对于每个新属性:
ALTER TABLE USER_PROFILE ADD AGE INT;
INSERT INTO USER_PROFILE ( UID, LAST_UPDATE_DATE, CREATION_DATE, AGE) VALUES ('01f63e8b-db53-44ef-924e-7a3ccfaeec28', 2021-01-12 07:34:19.121, 2021-01-12 07:34:19.121, 27);
解决方案 2 - 固定模式:
CREATE TABLE USER_PROFILE(
UID uuid,
ATTRIBUTE_NAME TEXT,
ATTRIBUTE_VALUE_TEXT TEXT,
ATTRIBUTE_VALUE_TIMESTAMP TIMESTAMP,
ATTRIBUTE_VALUE_INT INT,
LAST_UPDATE_DATE TIMESTAMP,
CREATION_DATE TIMESTAMP,
PRIMARY KEY (UID, ATTRIBUTE_NAME)
);
对于每个新属性:
INSERT INTO USER_PROFILE ( UID, ATTRIBUTE_NAME, ATTRIBUTE_VALUE_INT, LAST_UPDATE_DATE, CREATION_DATE) VALUES ('01f63e8b-db53-44ef-924e-7a3ccfaeec28', 'age', 27, 2021-01-12 07:34:19.121, 2021-01-12 07:34:19.121, 27);
就性能而言,哪个是最佳解决方案?
我个人会选择第二种解决方案——为所使用的每种数据类型设置列,并将属性名称用作主键的最后一个组成部分(参见我之前关于该主题的回答中的示例:
- Cassandra dynamic column family
- How to handle Dynamic columns in Cassandra
- How to handle Dynamic columns in Cassandra
- How to understand the 'Flexible schema' in Cassandra?
第一个解决方案存在以下问题:
- 如果您从代码进行架构修改,则需要协调这些更改,否则您将得到 schema disagreement,必须由管理员通过重启节点来解决。协调的更改要么会减慢数据插入速度,要么会造成单点故障
- 存在许多列会对性能产生重大影响。例如,根据 this very good analysis by The Last Pickle,拥有 100 列而不是 10 列会使读取延迟增加 10 倍以上
- 如果需要,您不能更改属性类型 - 在将属性作为聚类列的解决方案中,您可以开始将属性作为另一种类型。如果您将属性作为列,则不能这样做,因为 Cassandra 不允许更改列类型(不要尝试删除列并使用新类型将其添加回来 - 您会破坏现有数据)。因此,您需要为该属性创建一个全新的列。
我有很多用户(150-2 亿)。每个用户有 N(30-100) 个属性。该属性可以是整数、文本或时间戳类型。属性未知,所以我想动态添加它们。
解决方案 1 - 通过更改 table
添加新列 CREATE TABLE USER_PROFILE(
UID uuid PRIMARY KEY,
LAST_UPDATE_DATE TIMESTAMP,
CREATION_DATE TIMESTAMP
);
对于每个新属性:
ALTER TABLE USER_PROFILE ADD AGE INT;
INSERT INTO USER_PROFILE ( UID, LAST_UPDATE_DATE, CREATION_DATE, AGE) VALUES ('01f63e8b-db53-44ef-924e-7a3ccfaeec28', 2021-01-12 07:34:19.121, 2021-01-12 07:34:19.121, 27);
解决方案 2 - 固定模式:
CREATE TABLE USER_PROFILE(
UID uuid,
ATTRIBUTE_NAME TEXT,
ATTRIBUTE_VALUE_TEXT TEXT,
ATTRIBUTE_VALUE_TIMESTAMP TIMESTAMP,
ATTRIBUTE_VALUE_INT INT,
LAST_UPDATE_DATE TIMESTAMP,
CREATION_DATE TIMESTAMP,
PRIMARY KEY (UID, ATTRIBUTE_NAME)
);
对于每个新属性:
INSERT INTO USER_PROFILE ( UID, ATTRIBUTE_NAME, ATTRIBUTE_VALUE_INT, LAST_UPDATE_DATE, CREATION_DATE) VALUES ('01f63e8b-db53-44ef-924e-7a3ccfaeec28', 'age', 27, 2021-01-12 07:34:19.121, 2021-01-12 07:34:19.121, 27);
就性能而言,哪个是最佳解决方案?
我个人会选择第二种解决方案——为所使用的每种数据类型设置列,并将属性名称用作主键的最后一个组成部分(参见我之前关于该主题的回答中的示例:
- Cassandra dynamic column family
- How to handle Dynamic columns in Cassandra
- How to handle Dynamic columns in Cassandra
- How to understand the 'Flexible schema' in Cassandra?
第一个解决方案存在以下问题:
- 如果您从代码进行架构修改,则需要协调这些更改,否则您将得到 schema disagreement,必须由管理员通过重启节点来解决。协调的更改要么会减慢数据插入速度,要么会造成单点故障
- 存在许多列会对性能产生重大影响。例如,根据 this very good analysis by The Last Pickle,拥有 100 列而不是 10 列会使读取延迟增加 10 倍以上
- 如果需要,您不能更改属性类型 - 在将属性作为聚类列的解决方案中,您可以开始将属性作为另一种类型。如果您将属性作为列,则不能这样做,因为 Cassandra 不允许更改列类型(不要尝试删除列并使用新类型将其添加回来 - 您会破坏现有数据)。因此,您需要为该属性创建一个全新的列。