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 无需模式管理。SAI 配置更简单,并使用现有的数据库参数进行调整,例如在 cassandra.yaml 中。使用 SAI,没有提交日志在引导期间接受写入;SAI 无需等待引导即可读取数据库配置。使用 SAI,模式/索引选项驻留在索引元数据中,由本机数据库模式管理处理。
在数据库表的哪一列上可以基于 SAI 索引?
在任何表列上定义每个 SAI 索引。例外:当分区键仅包含一列时,无需定义基于分区键的 SAI 索引;在这种情况下,SAI 会发出 无效查询
消息。
您还可以使用表中复合分区键中的单个列来定义 SAI 索引。复合分区键表示分区基于两个或多个列。在这种情况下,使用 SAI 索引,您将只指定构成复合分区键的列之一。
对于集合映射,您可以在同一列上定义一个或多个 SAI 索引,指定 keys
、values
和 entries
作为映射类型。SAI 还支持 list
和 set
集合。
在具有 SAI 索引的数据库表的 CQL 查询中,
|
当我在同一列上删除并重新创建 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 索引和 SSTable 的虚拟表。
SAI 索引使用哪些写入和读取路径?
SAI 索引 Memtable 和 SSTable,因为它们被写入,在读取时解决这些索引之间的差异。请参阅 SAI 写入路径和读取路径。
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
。
|
SAI 是否支持对集合列进行索引?
是的 - SAI 支持类型为 map
、list
和 set
的集合。请参阅以下主题
在具有 SAI 索引的数据库表的 CQL 查询中,
|
支持哪些查询运算符?
对于对包含 SAI 索引的表的查询
-
数值:
=
、<
、>
、⇐
、>=
、AND
、OR
、IN
-
字符串:
=
、CONTAINS
、CONTAINS KEY
、AND
、OR
、IN
不支持的查询运算符包括
-
字符串或数值:
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';
有关使用 |
在 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 有一个 请参阅 CREATE CUSTOM INDEX 以及 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
,以及用于存储每个客户的 address
、phone_number
和 date_of_birth
的静态列。给定一个类似于以下的查询
SELECT * from transaction_by_customer where customer_id = 'xyz123';
如果有 100,000 行 transaction_by_customer
,由于您定义了这三个静态字段,因此此查询针对的表使用的磁盘空间明显更少,与在每个行中写入每个客户的值(address
、phone_number
、date_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。