如何正确 select 匹配索引的分区键
How to properly select partition keys that match an index
我尝试 select 在索引列中至少包含一行具有特定值的分区键。
使用当前解决方案满足所有其他要求:
- 能够select 根据他们的办公室进行报告。
- 给定一个办公室,能够select使用类型和日期范围。
- 不需要 select 没有排放办公室 and/or 报告类型的基于日期的报告。
最后,我需要能够 select 特定用户已创建报告的所有办公室。根据 cassadra 文档,我在用户列上添加了一个索引。
table定义为:
create table report(
office uuid,
type text,
insert_date timestamp,
...
created_by uuid,
...
primary key(office, type, insert_date));
create index created_by_idx on report (created_by);
使用该索引,如果我没记错的话,就像有一个辅助 table 描述如下:
create table report2(
created_by uuid,
office uuid,
type text,
insert_date timestamp,
...
primary key(created_by ,office, type, insert_date));
我可以成功地 运行 查询如下:
select office from report where created_by = ?
但这会导致多行具有相同的办公室密钥,这是正确的:每个用户可以在每个办公室创建多个报告。
现在我在软件级别过滤重复的办公室,但我问自己是否可以在提取过程中直接过滤该数据。
我试过:
select distinct office from report where created_by = ?
结果是
SELECT DISTINCT with WHERE clause only supports restriction by partition key and/or static columns.
然后我尝试了:
select office from report where created_by = ? group by office
给我正确的结果,但发出警告:
Aggregation query used without partition key
这会不会是个问题?如何处理 cassandra 这样的查询,在这种情况下,是否可以忽略此警告?最后,使用这样的查询来对抗
select * ...
whit 相同的 where 子句?
Cassandra 不支持您描述的功能是有原因的 - 因为它可能效率低下:
首先,正如您所指出的,二级索引确实必须列出所有匹配的行键,而不仅仅是不同的匹配分区键。这是因为您可能会要求所有行而不仅仅是不同的分区键,因此数据必须存在。此数据必须保留在索引中的另一个原因是每个单独的行都可能被单独删除(或过期),因此 Cassandra 需要跟踪所有这些数据以确定整个分区是否仍然存在,或者不再存在。
现在,由于我们已经在搜索结果列表中列出了所有行的键,因此仅输出 "distinct" 分区键是一种低效操作...如果一个分区中有一百万个匹配行,Cassandra 需要扫描所有这些,然后才输出一个结果。 Cassandra 通常不会让用户用低效的操作搬起石头砸自己的脚(例如,看看 "ALLOW FILTERING" 是如何明确允许在 SELECT 查询中进行低效过滤的)。
也就是说,未来的 Cassandra 版本应该允许您请求的 "SELECT DISTINCT" 请求是有道理的,也许需要用户说 "ALLOW FILTERING" 来确认它可能会很慢。此外,替代实现可能涉及更慢的更新(每行更新将检查分区的活动性)但随后快速读取。 Scylla 考虑过这样的实现,但也没有实现(参见 https://github.com/scylladb/scylla/issues/3435)。
我尝试 select 在索引列中至少包含一行具有特定值的分区键。
使用当前解决方案满足所有其他要求:
- 能够select 根据他们的办公室进行报告。
- 给定一个办公室,能够select使用类型和日期范围。
- 不需要 select 没有排放办公室 and/or 报告类型的基于日期的报告。
最后,我需要能够 select 特定用户已创建报告的所有办公室。根据 cassadra 文档,我在用户列上添加了一个索引。
table定义为:
create table report(
office uuid,
type text,
insert_date timestamp,
...
created_by uuid,
...
primary key(office, type, insert_date));
create index created_by_idx on report (created_by);
使用该索引,如果我没记错的话,就像有一个辅助 table 描述如下:
create table report2(
created_by uuid,
office uuid,
type text,
insert_date timestamp,
...
primary key(created_by ,office, type, insert_date));
我可以成功地 运行 查询如下:
select office from report where created_by = ?
但这会导致多行具有相同的办公室密钥,这是正确的:每个用户可以在每个办公室创建多个报告。
现在我在软件级别过滤重复的办公室,但我问自己是否可以在提取过程中直接过滤该数据。
我试过:
select distinct office from report where created_by = ?
结果是
SELECT DISTINCT with WHERE clause only supports restriction by partition key and/or static columns.
然后我尝试了:
select office from report where created_by = ? group by office
给我正确的结果,但发出警告:
Aggregation query used without partition key
这会不会是个问题?如何处理 cassandra 这样的查询,在这种情况下,是否可以忽略此警告?最后,使用这样的查询来对抗
select * ...
whit 相同的 where 子句?
Cassandra 不支持您描述的功能是有原因的 - 因为它可能效率低下:
首先,正如您所指出的,二级索引确实必须列出所有匹配的行键,而不仅仅是不同的匹配分区键。这是因为您可能会要求所有行而不仅仅是不同的分区键,因此数据必须存在。此数据必须保留在索引中的另一个原因是每个单独的行都可能被单独删除(或过期),因此 Cassandra 需要跟踪所有这些数据以确定整个分区是否仍然存在,或者不再存在。
现在,由于我们已经在搜索结果列表中列出了所有行的键,因此仅输出 "distinct" 分区键是一种低效操作...如果一个分区中有一百万个匹配行,Cassandra 需要扫描所有这些,然后才输出一个结果。 Cassandra 通常不会让用户用低效的操作搬起石头砸自己的脚(例如,看看 "ALLOW FILTERING" 是如何明确允许在 SELECT 查询中进行低效过滤的)。
也就是说,未来的 Cassandra 版本应该允许您请求的 "SELECT DISTINCT" 请求是有道理的,也许需要用户说 "ALLOW FILTERING" 来确认它可能会很慢。此外,替代实现可能涉及更慢的更新(每行更新将检查分区的活动性)但随后快速读取。 Scylla 考虑过这样的实现,但也没有实现(参见 https://github.com/scylladb/scylla/issues/3435)。