cassandra 索引列不支持IN限制

g9icjywg  于 8个月前  发布在  Cassandra
关注(0)|答案(2)|浏览(167)

我有一个应用程序,我有多个选择下拉菜单。根据这个函数,我需要从表中获取所有值。

CREATE TABLE generic_keyspace.cust_table (
    account_executive text,
    certification text,
    customer_category text,
    customer_name text,
    engine_model text,
    target_cost_final text,
    target_price_final text,
    PRIMARY KEY (account_executive, certification, customer_category, customer_name, engine_model)
) WITH CLUSTERING ORDER BY (certification ASC, customer_category ASC, customer_name ASC, engine_model ASC)

这是我的table

SELECT * from cust_table
  WHERE customer_name IN ('cust1','cust2')
  AND customer_category IN ('cat1','cat2')
  ALLOW FILTERING;

当尝试执行此查询时,我收到一个错误

InvalidRequest: Error from server: code=2200 [Invalid query] \
  message="IN restrictions are not supported on indexed columns"

我试图从主键中删除列,然后我得到另一个错误

InvalidRequest: Error from server: code=2200 [Invalid query] \
  message="IN predicates on non-primary-key columns (customer_name) is not yet supported"
7gyucuyw

7gyucuyw1#

ALLOW FILTERING是一个创可贴,你不应该在生产Cassandra部署中做。ALLOWFILTERING的唯一推荐用法是当查询限于单个分区时。这里需要考虑一些严肃的数据建模问题。
一般的想法是收集所有需要的读查询,然后定义表的数据模型,然后在其上存储数据。
我强烈建议你通过以下免费的基于浏览器的课程,

  1. Fundamentals
  2. Data modeling by examples
    由于表的主键定义为compound primary key
PRIMARY KEY (account_executive, certification, customer_category, customer_name, engine_model)

其中,

  • account_executive是表的 * 分区键 *。
  • certificationcustomer_categorycustomer_nameengine_model是 * 集群键 *。

在聚类键内,不能跳过前面的键而使用另一个键。例如,您不能使用像SELECT ... FROM ... WHERE account_executive = ? AND customer_category = ?;这样的查询,因为certification列出现在customer_category之前。例如,您可以跳过右侧的其他聚类键列。
如果你想在读查询上得到最快的响应,你将使用完整的主键作为一个整体,

SELECT ... FROM ... WHERE account_executive = ? AND certification = ? AND customer_category = ? AND customer_name = ? AND engine_model = ?;

查询以匹配非主键列是一种反模式,因为查询应始终导致从表中检索到连续的数据片。
可以在非主键列上创建自定义的辅助索引,以帮助提高查询的灵活性。然而,这种技术并不能保证索引的无故障,所以要知道when and when not to use an index
根据您设计表模型的方式,以下是支持的查询,

  • SELECT ... FROM cust_table WHERE account_executive = ? AND certification = ? AND customer_category = ? AND customer_name = ? AND engine_model = ?;--* 更快更高效 *
  • SELECT ... FROM cust_table WHERE account_executive = ? AND certification = ?;
  • SELECT ... FROM cust_table WHERE account_executive = ? AND certification = ? AND customer_category = ?;
  • SELECT ... FROM cust_table WHERE account_executive = ? AND certification = ? AND customer_category = ? AND customer_name = ?;
  • SELECT ... FROM cust_table WHERE account_executive = ?;

你也可以在WHERE子句中执行其他条件,我建议你阅读this CQL WHERE clause understanding blog,它有点旧,但仍然与最近版本的Cassandra®有很多相关性。

cwdobuhd

cwdobuhd2#

IN()操作符主要用于筛选分区键以检索多个分区。
此外,您只能使用IN过滤复合主键的最后一列,前提是前面的所有列都是使用相等(=)运算符指定的。正如您已经发现的,IN运算符不能用于索引列。
为了说明,我将使用此表作为示例:

CREATE TABLE sample_table (
    pk int,
    ck1 int,
    ck2 int,
    ck3 int,
    some_column text,
    another_column text,
    PRIMARY KEY (pk, ck1, ck2, ck3)
)

IN()运算符在此表中的有效用法如下:

SELECT * FROM sample_table WHERE pk IN (...)
SELECT * FROM sample_table WHERE pk = ? AND ck1 IN (...)
SELECT * FROM sample_table WHERE pk = ? AND ck1 = ? AND ck2 IN (...)
SELECT * FROM sample_table WHERE pk = ? AND ck1 = ? AND ck2 = ? AND ck3 IN (...)

注意,IN运算符只用于筛选最后一列--IN运算符不能用于WHERE子句的任何前面的列。
顺便说一下,看起来您的应用程序需要执行多个查询来检索所需的数据,并试图在共享表上执行这些查询。Cassandra是当您遇到规模问题时的首选数据库,这意味着您需要以超高速检索数据。只有通过为每个应用程序查询设计一个表来优化表的读操作时,才能实现这一点。
因此,如果您有一个根据客户名称进行筛选的应用程序查询,则需要对数据进行建模,以便按该列对表进行分区。举例来说:

CREATE TABLE customers_by_name (
    customer_name text,
    ...
    PRIMARY KEY (customer_name)
)

如果需要按类别查询,则设计一个按类别分区的表:

CREATE TABLE customers_by_category (
    customer_category text,
    ...
    PRIMARY KEY (customer_category)
)

作为一般性建议,不鼓励在分区键上使用IN操作符,因为协调器需要为列表中的每个项触发单独的读请求。如果必须,请将其使用限制为2到3个项目以获得最佳性能。
在集群列上使用IN操作符并不成问题,因为查询仅限于单个分区,所以它只对分区内的行进行过滤。干杯!干杯!

相关问题