← Back to Glossary

OFFSET

The OFFSET clause skips a specified number of rows in a query's result set before returning the remaining rows, commonly used for pagination alongside LIMIT.

Overview

OFFSET tells a query how many rows to skip from the beginning of the (typically ordered) result set before it starts returning rows. On its own it's rarely used without LIMIT -- the pair together implement classic page-based pagination: "give me rows 21 through 30."

Copy code

SELECT id, name FROM customers ORDER BY id LIMIT 10 OFFSET 20; -- skip the first 20 rows, return the next 10

Why ORDER BY matters

Like LIMIT, OFFSET only produces a meaningful, repeatable result when the query has a deterministic ORDER BY. Without one, "the first 20 rows" is not well-defined, and different executions (or query plans) could skip a different set of rows.

DuckDB notes

DuckDB implements the standard LIMIT n OFFSET m syntax and, like LIMIT, allows OFFSET to be an arbitrary expression rather than only a literal integer.

Performance

OFFSET is conceptually simple but can be a performance trap at scale: to skip the first 1,000,000 rows, the database generally still has to produce and discard them, so OFFSET cost grows with its value. For deep pagination over large tables, a keyset (a.k.a. "seek") approach -- filtering with WHERE on the last row's sort key instead of using OFFSET -- avoids that cost:

Copy code

-- instead of LIMIT 20 OFFSET 100000 SELECT id, name FROM customers WHERE id > 100000 -- last id seen on the previous page ORDER BY id LIMIT 20;

Related terms

FAQS

Syntactically yes in most databases including DuckDB, but it's uncommon -- without a LIMIT, OFFSET just skips rows and returns everything after them, which is rarely what you want on a large table.

The database typically still has to scan and discard the skipped rows, so cost scales with the offset value; keyset pagination (filtering on the last seen key) avoids this by jumping directly to the right position.