Clustering order and range queries

Apache Cassandra · Practical · 10 min

Time-series and feed queries are fast only when the table's on-disk order matches what the query asks for.

Rows inside a partition are stored sorted by the clustering columns, so a query that reads a contiguous slice in that order is a sequential read. Design the clustering order around your most common access:

  • "latest 20 messages" wants CLUSTERING ORDER BY (sent_at DESC), so the newest rows come first and LIMIT 20 stops early,
  • "readings between 08:00 and 10:00" is a range on the clustering column,
  • with several clustering columns, (year, month, day), you can restrict a prefix with equality and range on the next.

Reading in the reverse of the declared order works (ORDER BY sent_at ASC on a DESC table), but forward-order reads are more efficient, so declare the order your hot query uses.

Paging through a partition is natural: drivers page automatically using a paging state, and you can also page manually with a range on the clustering column: WHERE channel_id = ? AND sent_at < :last_seen LIMIT 20.

Multi-column restrictions such as (sent_at, msg_id) < ('2026-10-17 09:00', ...) compare tuples in clustering order, which is how you continue exactly after the last row when several rows share a timestamp.

Clustering order is fixed when the table is created; changing it means a new table and copying data.

Example

-- table messages: PRIMARY KEY ((channel_id), sent_at, msg_id)
--                 WITH CLUSTERING ORDER BY (sent_at DESC, msg_id DESC)

-- newest 20 messages: one sequential read, stops after 20 rows
SELECT sent_at, author, body FROM shop.messages
WHERE channel_id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47
LIMIT 20;

-- next page: continue strictly after the last (sent_at, msg_id) seen
SELECT sent_at, msg_id, body FROM shop.messages
WHERE channel_id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47
  AND (sent_at, msg_id) < ('2026-10-17 09:00:00+0000', 50554d6e-29bb-11ef-9f3c-0242ac120002)
LIMIT 20;

-- reverse order is allowed, but less efficient
SELECT body FROM shop.messages
WHERE channel_id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47
ORDER BY sent_at ASC, msg_id ASC LIMIT 5;

Remember

  • Rows are stored sorted by clustering columns within a partition
  • Declare CLUSTERING ORDER BY to match the hot query (often DESC)
  • Ranges apply to the next clustering column after equality prefixes
  • Tuple comparisons continue paging exactly after the last row

Watch out for

  • Declaring ascending order for a latest-first feed and paying for reverse reads on every request.

Check yourself

  1. A table has CLUSTERING ORDER BY (ts DESC). Which ORDER BY clauses are allowed?

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