INSERT and SELECT with key restrictions

Apache Cassandra · Essentials · 12 min

CQL looks like SQL but rejects most queries that don't follow the primary key, so you need its rules to write any reads.

INSERT INTO t (cols) VALUES (...) writes a row; you must give every primary key column. SELECT looks familiar too, but the WHERE clause is restricted so that every query is efficient:

  • you must restrict the full partition key with = (or IN), so the query goes to one known partition,
  • clustering columns can be restricted in order: equality on earlier ones, and a range (<, >=...) only on the last one you restrict,
  • filtering on regular columns isn't allowed without an index.

Within a partition, rows come back in clustering order, and you can ORDER BY a clustering column only in the table's order or its exact reverse. LIMIT caps rows and PER PARTITION LIMIT caps rows per partition.

If a query breaks these rules, Cassandra refuses with an error suggesting ALLOW FILTERING. Adding it makes Cassandra scan and discard data, potentially across the whole cluster; it's acceptable only when the scan is already limited to one small partition. The real fix is a table designed for the query, or an index.

There are no joins, subqueries or GROUP BY on arbitrary columns (GROUP BY works only on primary key columns), and aggregates like COUNT(*) should be used within a partition. SELECT JSON and INSERT JSON convert rows to and from JSON.

Example

INSERT INTO shop.readings (sensor_id, day, ts, value)
VALUES ('s-17', '2026-10-17', '2026-10-17 09:00:00+0000', 21.5);

-- OK: full partition key + range on the clustering column
SELECT ts, value FROM shop.readings
WHERE sensor_id = 's-17' AND day = '2026-10-17'
  AND ts >= '2026-10-17 08:00:00+0000' AND ts < '2026-10-17 10:00:00+0000';
--  ts                              | value
-- ---------------------------------+-------
--  2026-10-17 09:00:00.000000+0000 |  21.5

-- Rejected: partition key incomplete
SELECT * FROM shop.readings WHERE sensor_id = 's-17';
-- InvalidRequest: ... might involve data filtering ... use ALLOW FILTERING
-- (the full partition key must be restricted)

-- Rejected: filtering on a regular column
SELECT * FROM shop.readings WHERE value > 30;

Remember

  • Restrict the full partition key in every normal query
  • Clustering columns: equality in order, then a range on the last
  • ORDER BY only in clustering order or its reverse
  • ALLOW FILTERING means a scan: almost always the wrong fix

Watch out for

  • Adding ALLOW FILTERING to silence the error, then watching the query time out in production.

Check yourself

  1. Table key PRIMARY KEY ((user_id), year, month, day). Which WHERE clause is valid without ALLOW FILTERING?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: cassandra.apache.org/doc/latest/cassandra/developing/cql/dml.html