DBAtlas · データベース運用アトラス

行数の制限/ページング(LIMIT/OFFSET、FETCH、ROWNUM、TOP)

Oracle

-- 12c+ standard: OFFSET/FETCH
SELECT name, salary FROM employee
ORDER BY salary DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

-- Older versions: with ROWNUM
SELECT * FROM (
  SELECT name, salary FROM employee ORDER BY salary DESC
) WHERE ROWNUM <= 10;

結果セットの制限/ページングに使用する。Oracle 12c 以降は標準の OFFSET n ROWS FETCH NEXT m ROWS ONLY がサポートされる。それ以前は ROWNUM 疑似列を使用していた。ROWNUM はソート前に割り当てられるため、ORDER BY のサブクエリで囲む必要がある。

PostgreSQL

-- LIMIT/OFFSET
SELECT name, salary FROM employee
ORDER BY salary DESC
LIMIT 10 OFFSET 20;

-- Standard equivalent: FETCH
SELECT name, salary FROM employee
ORDER BY salary DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

PostgreSQL は LIMIT n OFFSET m と標準の OFFSET ... FETCH 形式の両方をサポートする。大きな OFFSET 値は遅い。深いページングにはキーベース(keyset / 'WHERE id > last_id')のページネーションのほうが効率的。ORDER BY のない LIMIT は結果の順序を保証しない。

MySQL

-- LIMIT [offset,] row_count
SELECT name, salary FROM employee
ORDER BY salary DESC
LIMIT 10 OFFSET 20;

-- Short form: LIMIT offset, row_count
SELECT name, salary FROM employee ORDER BY salary DESC LIMIT 20, 10;

MySQL/MariaDB は LIMIT キーワードを 2 つの形式で使用する: LIMIT row_count OFFSET offset または LIMIT offset, row_count。MySQL 8.0.19+ は標準の FETCH 構文も受け付ける。深い OFFSET の性能対策には keyset ページネーションが推奨される。

SQL Server

-- First N with TOP
SELECT TOP 10 name, salary FROM employee ORDER BY salary DESC;

-- OFFSET/FETCH for paging (2012+), ORDER BY mandatory
SELECT name, salary FROM employee
ORDER BY salary DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

SQL Server は先頭 N 行に TOP n(TOP (n) PERCENT / WITH TIES の変形あり)を、2012 以降のページングに OFFSET ... FETCH を使用する。OFFSET/FETCH が動作するには ORDER BY が必須。SQL Server には LIMIT キーワードはない。

MongoDB

// Paging with skip/limit
db.employee.find()
  .sort({ salary: -1 })
  .skip(20)
  .limit(10)

MongoDB では limit() が返すドキュメント数を、skip() がスキップする数を設定し、sort() と組み合わせてページングを行う。大きな skip 値は高コスト。深いページングには、最後に見た値に基づく範囲(keyset)クエリが推奨される。

Redis

# Range read on a sorted set (ZSET):
ZREVRANGE salary_sorted 20 29    # members ranked 21-30
# Range on a list:
LRANGE queue 0 9              # first 10 elements

Redis には SQL の LIMIT はないが、範囲読み取りのコマンドがある: Sorted Set には ZRANGE/ZREVRANGE start stop(インデックスベース)または ZRANGEBYSCORE ... LIMIT offset count、List には LRANGE。これらのコマンドでページングのようなアクセスができる。

Elasticsearch

GET employee/_search
{
  "from": 20,
  "size": 10,
  "sort": [ { "salary": "desc" } ]
}

Elasticsearch では 'size' が返すヒット数を、'from' がスキップする数を設定する(LIMIT/OFFSET に相当)。from+size は最大 index.max_result_window(デフォルト 10,000)まで。深いページングには 'search_after'(keyset)または PIT(point-in-time)を使用する。

DBAtlas で開く →