導入: なぜLIMITとOFFSETが重要なのか
アプリケーション開発において、数万件以上のレコードを持つテーブルからデータをすべて取得するのは、メモリの浪費やネットワーク負荷の増大を招く「アンチパターン」です。DBAとして現場で強く推奨するのは、必要な分だけを段階的に取得する手法です。今回解説するLIMIT句とOFFSET句を使いこなすことで、Webアプリのページネーション(ページ送り)や、大規模データのバッチ処理を効率的かつ安全に実装することが可能になります。
基礎知識: 基本構造と仕組み
SQLにおけるデータ抽出の制御は、以下の2つのキーワードで行います。
・LIMIT: 取得する最大レコード数を指定します。
・OFFSET: 取得を開始する前に「スキップする」レコード数を指定します。
注意すべき点は、OFFSETは「0から始まるインデックス」であるという点です。例えば「OFFSET 10」と指定すると、最初の10件(1番目から10番目まで)が無視され、11番目のデータから取得が始まります。この挙動を正しく理解していないと、1ページ分データがずれるというバグを引き起こす原因になります。
実装/解決策: 具体的な活用テクニック
現場で最も多い利用シーンは、Web画面の「前へ」「次へ」ボタンに応じたデータ取得です。重要なのは、必ずORDER BY句と組み合わせること。データベースのデータは物理的に並んでいるわけではないため、並び順を固定しないと、ページを遷移するたびに表示されるデータが入れ替わるという深刻な不整合が発生します。
サンプルプログラム: 実践的コード例
以下は、ユーザーテーブルから「ID順」でソートし、1ページあたり5件ずつデータを取得するためのSQL例です。
— 1ページ目を取得(先頭から5件)
SELECT id, name, address
FROM user
ORDER BY id ASC
LIMIT 5 OFFSET 0;
— 2ページ目を取得(最初の5件をスキップして、次の5件を取得)
SELECT id, name, address
FROM user
ORDER BY id ASC
LIMIT 5 OFFSET 5;
— (補足) 別の記法:LIMIT [開始位置], [取得件数]
— 意味は「5つ飛ばして、3件取得」となる(MySQL等で一般的)
SELECT id, name, address
FROM user
ORDER BY id ASC
LIMIT 5, 3;
応用・注意点: 現場で陥りやすいバグの回避策
1. パフォーマンスの罠
OFFSETの値が非常に大きくなると(例: OFFSET 100000)、DBはそれまでの10万件を一度スキャンして読み飛ばす必要があるため、クエリが著しく遅延します。大量データのページングでは、OFFSETを使わず「前のページの最後のIDより大きいもの」を検索する「キーセットページネーション(カーソルベース)」という手法への切り替えを検討してください。
2. LIMITの省略不可
SQLiteなどの一部の環境では、OFFSETだけを指定することはできません。必ずLIMITとセットで記述するルールを徹底しましょう。
3. ORDER BYは必須
前述の通り、ORDER BYなしでのLIMIT/OFFSET使用は「結果が毎回変わる可能性がある」という脆弱性につながります。必ずユニークなカラム(IDなど)をキーに含めることで、常に一貫した結果セットを返すように設計してください。

コメント