Cassandra 文档

版本

您正在查看预发布版本的文档。

SAI 常见问题解答

使用此常见问题解答查找常见问题的答案并获得有关存储附加索引 (SAI) 的帮助。

什么是 SAI?

存储附加索引 (SAI) 是 Cassandra 数据库的高度可扩展、全球分布式索引。SAI 结合了

  • 开源 SSTable 附加辅助索引 (SASI) 的存储附加架构

  • 许多高度优化的磁盘索引结构

支持哪些数据库?

目前,Cassandra 5.0 是唯一支持的数据库。

创建数据库、键空间和一个或多个表后,使用 CREATE INDEX ... USING 'sai' 在表上定义一个或多个 SAI 索引。对于 Cassandra 数据库,请使用 cqlsh。相同的 CREATE INDEX ... USING 'sai' 命令适用于两者。请参阅 SAI 快速入门

使用 SAI 时应使用哪些配置设置?

与大多数索引环境相比,SAI 配置和相关设置要简单得多。关键点

  • 增加 --XX:MaxDirectMemorySize,为操作系统和其他内存结构保留大约 15-20% 的内存。

  • 在 cassandra.yaml 中,显式将 file_cache_size_in_mb 设置为该值的 75%。

  • 繁重的混合读/写工作负载可能需要

    • 减少 range_request_timeout_in_ms

    • 增加 write_request_timeout_in_ms

  • 如果 memtable_flush_writers 值设置得太低,写入可能会停滞。如果在您的环境中发生这种情况,请增加 memtable_flush_writers

除了内存之外,SAI 使用与 Cassandra 相同的可调参数,例如压缩吞吐量和压缩执行器。这对于写入性能很重要。对于读取性能,同样,最大限度地利用 Chunk Cache 将有利于 SAI 读取,因为所有磁盘索引组件都是通过此机制访问的。请参阅 配置 SAI 索引

SAI 解决哪些计算挑战?

开发人员经常会问:“如何查询 Apache Cassandra 分区键之外的其他字段?”

SAI 基于表的列实现高效索引,例如复合分区键的一部分。在 SAI 之前,您可以索引聚类键,但不能索引复合分区的各个部分。SAI 的开发灵感来自 SASI,旨在通过创建辅助索引来实现高效且简单的过滤。

SAI 还使数据建模变得更容易,因为您无需创建自定义表来满足特定的查询模式。您可以创建最适合您的表,只写入该表,并以您想要的方式查询它。

使用 SAI 的优势是什么?

SAI 使您能够在同一个数据库表上定义多个索引。每个 SAI 索引都可以基于表中的任何列。例外:当分区键仅包含一列时,无需定义基于分区键的 SAI 索引;在这种情况下,SAI 会发出 无效查询 消息。您还可以使用表中复合分区键中的单个列来定义 SAI 索引。复合分区键表示分区基于两个或多个列。在这种情况下,使用 SAI 索引,您将只指定构成复合分区键的列之一。

对于开发人员来说,SAI 消除了几个以前的问题,包括需要复制非规范化数据以查询非主键列。

对于运营人员来说,SAI 有几个优势,包括使用更少的磁盘空间进行索引;更少的故障点;由于 SAI 的简化架构,更容易实现正常运行时间;以及更少的需要保护的数据副本。

SAI 是完整的搜索解决方案吗?

SAI 不是企业搜索引擎。虽然它确实提供了一些相同的功能,但 SAI 并不是基于文本搜索的完整替代品。SAI 的核心是一个过滤引擎,它简化了数据建模和客户端应用程序,这些应用程序原本会严重依赖于维护多个特定于查询的表。

SAI 是一个索引,而不是一个搜索引擎。与基于文本的搜索不同,SAI 无需模式管理。SAI 配置更简单,并使用现有的数据库参数进行调整,例如在 cassandra.yaml 中。使用 SAI,没有提交日志在引导期间接受写入;SAI 无需等待引导即可读取数据库配置。使用 SAI,模式/索引选项驻留在索引元数据中,由本机数据库模式管理处理。

如何使用 SAI 功能?

存储附加索引的查询完全基于 CQL。这些功能的设计有意简单易用。

从总体上讲,SAI 索引是

  • 通过 CQL CREATE INDEX ... USING 'sai' 命令和 DROP INDEX 命令按列创建和删除。从 SAI 快速入门 开始。

  • 通过 nodetool 重建和备份。请参阅 nodetool

  • 通过 nodetool、CQL 虚拟表、系统指标和 JMX 的组合进行监控。请参阅 监控 SAI 索引

在数据库表的哪一列上可以基于 SAI 索引?

在任何表列上定义每个 SAI 索引。例外:当分区键仅包含一列时,无需定义基于分区键的 SAI 索引;在这种情况下,SAI 会发出 无效查询 消息。

您还可以使用表中复合分区键中的单个列来定义 SAI 索引。复合分区键表示分区基于两个或多个列。在这种情况下,使用 SAI 索引,您将只指定构成复合分区键的列之一。

对于集合映射,您可以在同一列上定义一个或多个 SAI 索引,指定 keysvaluesentries 作为映射类型。SAI 还支持 listset 集合。

在具有 SAI 索引的数据库表的 CQL 查询中,CONTAINS 子句受支持,并且特定于

  • SAI 集合映射,其中包含 keysvaluesentries

  • SAI 集合,其中包含 listset 类型

当我在同一列上删除并重新创建 SAI 索引时,是否会阻止任何读取操作?有没有办法检查索引状态?

当您删除/重新创建 SAI 索引时,您不会被阻止输入不使用该索引的查询。但是,您不能使用该 SAI 索引(基于同一列),直到它完成构建并可查询。要确定给定索引的当前状态,请查询 system_views.indexes 虚拟表。示例

SELECT is_queryable,is_building FROM system_views.indexes WHERE keyspace_name='keyspace'
       AND table_name='table' AND index_name='index';

SAI 索引使用哪些写入和读取路径?

SAI 索引 Memtable 和 SSTable,因为它们被写入,在读取时解决这些索引之间的差异。请参阅 SAI 写入路径和读取路径

SAI 支持哪些磁盘索引格式?

SAI 支持两种磁盘索引格式,针对

  • 字符串上的相等和非精确匹配进行了优化。

    • 字符串使用 trie 数据结构与 postings(术语/行对)列表一起在磁盘上进行索引。trie 对堆友好,为术语提供字符串前缀压缩,并且可以匹配任何可以表示为确定性有限自动机的查询。该功能最大限度地减少了磁盘占用空间,并支持简单的标记跳过。

  • 数字和非文字类型上的相等和范围查询。

    • 数值和其他非文字 CQL 类型(timestampdateUUID)使用 k 维树 在磁盘上进行索引,这是一种平衡结构,可以提供跨一个或多个维度的快速查找,以及对值和 postings 的压缩。

SAI 索引的磁盘占用量是多少?

与其他原生或附加的 Cassandra 索引解决方案相比,SAI 需要的磁盘空间明显更少。与**未索引**的数据相比,SAI 会产生 20-35% 的额外磁盘占用量。SAI 磁盘占用量很大程度上取决于底层数据模型和索引的列数。

SAI 索引支持哪些列数据类型?

支持的类型包括:ASCII, BIGINT, DATE, DECIMAL, DOUBLE, FLOAT, INET, INT, SMALLINT, TEXT, TIME, TIMESTAMP, TIMEUUID, TINYINT, UUID, VARCHAR, VARINT

  • 从 Cassandra ??? 开始,INET 支持 IPv4 和 IPv6。

  • 从 Cassandra ??? 开始,DECIMALVARINT 支持。

  • SAI 还支持集合 - 请参阅 下一个常见问题解答

SAI 是否支持对集合列进行索引?

是的 - SAI 支持类型为 maplistset 的集合。请参阅以下主题

在具有 SAI 索引的数据库表的 CQL 查询中,CONTAINS 子句受支持,并且特定于

  • SAI 集合映射,其中包含 keysvaluesentries

  • SAI 集合,其中包含 listset 类型

支持哪些查询运算符?

对于对包含 SAI 索引的表的查询

  • 数值:=<>>=ANDORIN

  • 字符串:=CONTAINSCONTAINS KEYANDORIN

不支持的查询运算符包括

  • 字符串或数值:LIKE

示例

SELECT * FROM cycling.cyclist_semi_pro WHERE registration > '2010-01-01' AND registration < '2015-12-31' LIMIT 10;
SELECT * FROM audit WHERE text_map CONTAINS KEY 'Giovani';

有关使用 CONTAINS 子句利用 SAI 集合映射、列表和集合的查询示例,请务必参阅 SAI 集合映射示例,包含键、值和条目

在 SAI 的 CREATE INDEX 命令中,有哪些选项可用?

使用 WITH OPTIONS 子句来指示 SAI 如何处理索引中的大小写敏感性和特殊字符。例如,给定一个字符串列 lastname

CREATE INDEX lastname_sai_idx ON cycling.cyclist_semi_pro (lastname)
  USING 'sai' WITH OPTIONS =
  {'case_sensitive': 'false', 'normalize': 'true', 'ascii': 'true'};

SAI 有一个 ascii 选项。默认值为 false。当设置为 true 时,SAI 会将不在基本拉丁 Unicode 块(前 127 个 ASCII 字符)中的字母、数字和符号字符转换为 ASCII 等效字符(如果存在)。例如,此选项会将 à 更改为 a

请参阅 CREATE CUSTOM INDEX 以及 SAI 快速入门 主题中的示例。

SAI 是否支持复合索引:即对多个列进行单一索引?

不支持。SAI 索引与列之间存在一对一映射。但是,您可以在给定表中的每个列上创建单独的索引。此外,SAI 可以在一个读取查询中使用多个定义的索引。

如何查看 SAI 内存使用情况指标?

SAI 内存占用量分为 JVM 堆和块缓存。堆存储 memtable 索引,块缓存存储最近访问的磁盘索引组件以及其他 SSTable 组件。SAI 为堆和块缓存都提供了指标。对于每个索引,SAI 还提供指标来确定磁盘数据结构使用的内存大小(以字节为单位),以及磁盘使用情况。请参阅 索引组指标。SAI 还提供表状态指标,让您能够了解磁盘使用情况、基本表的磁盘使用百分比、正在进行的索引构建以及相关指标。请参阅 表状态指标

在读取查询中添加 SAI 列会对性能产生什么影响?我可以添加多少个 AND 子句?

单个查询中可以使用索引列的数量没有限制。cassandra.yaml 中的 sai_indexes_per_table_failure_threshold 设置控制单个表中允许的 SAI 索引的最大数量(默认值为 10)。但是,对多个索引列进行查询会产生与处理的索引组件数量增加相关的成本。在查询中评估多个索引列时,SAI 会执行一个工作流程(1:遍历。2:合并。3:交集,最终会将来自多个 memtable 和 SSTable 的数据合并在一起。

在查询中,AND 查询最多会处理两个 SAI 索引;如果查询使用了超过两个 SAI 索引,则 SAI 会对剩余的子句执行后过滤。

有关相关信息,请参阅 匹配流和后过滤 示例。

SAI 写入操作是异步的,还是 SAI 会等待确认写入操作后才向用户确认?

SAI 写入路径实际上非常简单。索引与数据一起存在,既存在于 memtable 中,也存在于 SSTable 中。当写入操作被确认到客户端时,数据已经被索引。这是一个**同步**过程。当 memtable 被刷新时,索引也会被刷新。请参阅 SAI 写入路径和读取路径

磁盘索引组件被分解为每个 SSTable 的索引文件和每个列的索引文件。列索引不存储主键或令牌;而是存储可压缩的行 ID。每个 SSTable 的索引文件将来自列索引的行 ID 链接到其支持的 SSTable。这种 SAI 设计允许单个 SSTable 中的所有列索引共享每个 SSTable 的索引文件,这进一步有助于减少磁盘占用量。

关于 SAI 索引的列基数,有哪些指导原则?

基数 会影响副本之间进行范围查询时的读取性能。与高基数列(如信用卡号)的值匹配的行数更有可能孤立在极少数节点上(甚至可能孤立在一个节点上),而与低基数列的值匹配的行数更有可能驻留在多个节点上。如果查询未指定分区键,Cassandra 协调器会扫描令牌环并按端点(节点)对令牌范围进行分组。然后,协调器会并发地执行所有参与端点的读取命令。在最坏的情况下,如果索引列的基数非常高,则可能需要扫描整个集群才能找到匹配项。对于低基数列,请注意,如果您的 LIMIT 高于目标列中的值数量,Cassandra 必须再次搜索所有副本才能确定 LIMIT 是否无法满足。在这种情况下,Cassandra 只会返回匹配结果的数量。

SAI 在哪些情况下会应用后过滤?

SAI 在许多情况下都会应用后过滤。例如,考虑一个简单的表,以及仅对两个非 PK 列中的一个列进行 SAI 索引

CREATE KEYSPACE test WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1};
CREATE TABLE test.mytable (id int PRIMARY KEY,
       col1 text,
       col2 timestamp);
CREATE CUSTOM INDEX mytable_col1_idx ON test.mytable (col1) USING 'StorageAttachedIndex';

给定一个类似于以下的查询

SELECT * FROM test.mytable WHERE col1 = 'hello world' and col2 < toTimestamp(now()) ALLOW FILTERING;

对于此查询,Cassandra 首先通过索引列(col1)缩小搜索范围,然后对 col2 应用后过滤。(谨慎使用 ALLOW FILTERING 子句。)在这种情况下,不需要额外的副本往返;后过滤操作是在副本本身执行的。

后过滤发挥作用的另一个情况是构建涉及多个 SAI 索引的查询。请参阅有关 AND 查询的 相关常见问题解答

我可以基于 静态列 创建 SAI 索引吗?

可以。例如,考虑一个 transaction_by_customer 表,其中您有一个主键 customer_id,以及用于存储每个客户的 addressphone_numberdate_of_birth 的静态列。给定一个类似于以下的查询

SELECT * from transaction_by_customer where customer_id = 'xyz123';

如果有 100,000 行 transaction_by_customer,由于您定义了这三个静态字段,因此此查询针对的表使用的磁盘空间明显更少,与在每个行中写入每个客户的值(addressphone_numberdate_of_birth)的环境相比。

SAI 提供了基于静态列创建索引的选项和优势,同时还实现了节省表空间的优势。

对于索引字符串,SAI 如何处理列数据中的 Unicode 字符?

当您基于字符串列创建 SAI 索引时,如果希望 SAI 对列数据执行 Unicode 规范化,请将 normalize 选项设置为 true。SAI 支持 Unicode 的规范化形式 C (NFC)。当设置为 true 时,SAI 会将给定 Unicode 字符的不同版本规范化为单个版本,保留索引中的所有标记和符号。例如,SAI 会将字符 Å (U+212B) 更改为 Å (U+00C5)。请参阅 CREATE CUSTOM INDEX

索引的列名可以包含特殊字符吗?

SAI 会验证正在定义索引的列名。SAI 仅允许字母数字字符和下划线。如果您尝试在包含其他字符的列名上定义索引,SAI 会返回 InvalidRequestException,并且不会创建索引。

SAI 支持哪些分区器?

SAI 仅支持 Murmur3Partitioner