SQLで検索結果を取得する際、全件表示してしまうと遅い・見づらい・サーバーに負荷がかかることがあります。
よくある問題
- 100万件のデータを全て取得して画面が固まる
- 検索結果が多すぎてどれを見ればいいかわからない
- サーバーのメモリが不足してエラーになる
- ネットワーク通信が重くなってユーザーが待たされる
件数制限が役立つ場面
- ユーザー一覧を上位10件だけ表示
- ページネーションで1ページあたり20件
- ランキングでスコア順の上位5件
- 新着情報を最新10件のみ表示
こうした場合に便利なのが、表示件数を制限するSQL構文です。
LIMIT句(MySQL/PostgreSQL/SQLiteなど)

基本構文
SELECT 列名
FROM テーブル名
ORDER BY 並び替える列
LIMIT 件数;
重要なポイント:
ORDER BY
を必ず使って、取得順を明確にするLIMIT
は最後に書く
例1:上位10件を取得
-- 成績上位10名を取得
SELECT name, score
FROM students
ORDER BY score DESC
LIMIT 10;
実行結果例:
name | score
---------|------
山田 | 98
田中 | 95
佐藤 | 92
鈴木 | 89
青木 | 87
... | ...
(10件のみ表示)
例2:最新の投稿5件を取得
-- 最新の投稿5件を取得
SELECT title, created_at
FROM posts
ORDER BY created_at DESC
LIMIT 5;
OFFSETを使ったページ制御
基本構文
SELECT 列名
FROM テーブル名
ORDER BY 並び替える列
LIMIT 件数 OFFSET スキップする件数;
例:ページネーションの実装
-- 1ページ目(1〜10件目)
SELECT * FROM products
ORDER BY id
LIMIT 10 OFFSET 0;
-- 2ページ目(11〜20件目)
SELECT * FROM products
ORDER BY id
LIMIT 10 OFFSET 10;
-- 3ページ目(21〜30件目)
SELECT * FROM products
ORDER BY id
LIMIT 10 OFFSET 20;
計算式:
OFFSET = (ページ番号 - 1) × 1ページの件数
例:
1ページ目: OFFSET = (1 - 1) × 10 = 0
2ページ目: OFFSET = (2 - 1) × 10 = 10
3ページ目: OFFSET = (3 - 1) × 10 = 20
実用例:商品一覧のページング
-- 商品一覧:1ページ20件で3ページ目を表示
SELECT
product_id,
product_name,
price
FROM products
WHERE price > 0 -- 価格が設定されている商品のみ
ORDER BY product_name
LIMIT 20 OFFSET 40; -- 41〜60件目
MySQLでの注意点
パフォーマンスの考慮
-- 悪い例:大きなOFFSETは遅い
SELECT * FROM large_table
ORDER BY id
LIMIT 10 OFFSET 100000; -- 10万件スキップは重い
-- 良い例:WHERE条件で絞り込む
SELECT * FROM large_table
WHERE id > 100000
ORDER BY id
LIMIT 10;
TOP句(SQL Server)

基本構文
SELECT TOP 件数 列名
FROM テーブル名
ORDER BY 並び替える列;
重要な特徴:
TOP
はSELECT
の直後に書くORDER BY
を必ず使って取得順を明確にする
例1:売上上位5件を取得
-- 売上上位5件の商品を取得
SELECT TOP 5 product_name, sales_amount
FROM sales
ORDER BY sales_amount DESC;
例2:最新のログ10件を取得
-- 最新のエラーログ10件を取得
SELECT TOP 10
log_id,
error_message,
created_at
FROM error_logs
ORDER BY created_at DESC;
TOP PERCENTを使った割合指定
-- 全体の上位10%を取得
SELECT TOP 10 PERCENT
employee_name,
salary
FROM employees
ORDER BY salary DESC;
ページング機能(SQL Server 2012以降)
-- OFFSET/FETCHを使用
SELECT
product_name,
price
FROM products
ORDER BY product_name
OFFSET 20 ROWS -- 20件スキップ
FETCH NEXT 10 ROWS ONLY; -- 次の10件を取得
FETCH句(Oracle/標準SQL対応DB)

基本構文(Oracle 12c以降)
SELECT 列名
FROM テーブル名
ORDER BY 並び替える列
OFFSET スキップ件数 ROWS
FETCH NEXT 取得件数 ROWS ONLY;
例1:上位10件を取得
-- 給与上位10名を取得
SELECT employee_name, salary
FROM employees
ORDER BY salary DESC
FETCH NEXT 10 ROWS ONLY;
例2:ページング機能
-- 21〜30件目を取得
SELECT
customer_id,
customer_name,
registration_date
FROM customers
ORDER BY registration_date DESC
OFFSET 20 ROWS -- 20件スキップ
FETCH NEXT 10 ROWS ONLY; -- 次の10件を取得
FETCHの詳細オプション
FETCH FIRST(最初のN件)
-- 最初の5件を取得
SELECT product_name, price
FROM products
ORDER BY price
FETCH FIRST 5 ROWS ONLY;
WITH TIESオプション
-- 同じ値がある場合、すべて含める
SELECT student_name, score
FROM students
ORDER BY score DESC
FETCH FIRST 3 ROWS WITH TIES;
例: 3位が同点の場合、3位の人すべてを含めて結果を返す
データベース別完全比較
データベース | 基本構文 | ページング | 特徴 |
---|---|---|---|
MySQL | LIMIT 10 | LIMIT 10 OFFSET 20 | 最もシンプル |
PostgreSQL | LIMIT 10 または FETCH NEXT 10 ROWS ONLY | 両方の構文が使用可能 | 柔軟性が高い |
SQLite | LIMIT 10 | LIMIT 10 OFFSET 20 | 軽量DBに最適 |
SQL Server | TOP 10 | OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY | 独自構文とSQL標準の両方 |
Oracle | ROWNUM (旧版)または FETCH NEXT 10 ROWS ONLY (12c〜) | 新しい標準構文推奨 | バージョンで大きく異なる |
具体的な書き方の比較
上位5件を取得する場合
-- MySQL, PostgreSQL, SQLite
SELECT name, score FROM students
ORDER BY score DESC
LIMIT 5;
-- SQL Server
SELECT TOP 5 name, score FROM students
ORDER BY score DESC;
-- Oracle (12c以降)
SELECT name, score FROM students
ORDER BY score DESC
FETCH NEXT 5 ROWS ONLY;
-- Oracle (11g以前)
SELECT name, score FROM (
SELECT name, score FROM students
ORDER BY score DESC
) WHERE ROWNUM <= 5;
21〜30件目を取得する場合
-- MySQL, PostgreSQL, SQLite
SELECT * FROM products
ORDER BY id
LIMIT 10 OFFSET 20;
-- SQL Server (2012以降)
SELECT * FROM products
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
-- Oracle (12c以降)
SELECT * FROM products
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
実用的な活用例

活用例1:ランキング表示
売上ランキングトップ10
-- MySQL/PostgreSQL
SELECT
ROW_NUMBER() OVER (ORDER BY total_sales DESC) as rank,
employee_name,
total_sales
FROM (
SELECT
employee_name,
SUM(sales_amount) as total_sales
FROM sales
WHERE YEAR(sales_date) = 2023
GROUP BY employee_name
) ranked_sales
ORDER BY total_sales DESC
LIMIT 10;
人気商品ランキング
-- SQL Server
SELECT TOP 5
p.product_name,
COUNT(oi.product_id) as order_count,
SUM(oi.quantity) as total_quantity
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id
JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_date >= DATEADD(MONTH, -1, GETDATE())
GROUP BY p.product_name
ORDER BY order_count DESC;
活用例2:ページネーション機能
Webアプリケーションでの実装
-- PHP + MySQLでの例
-- $page: ページ番号(1から開始)
-- $per_page: 1ページあたりの件数
SET @page = 2;
SET @per_page = 20;
SET @offset = (@page - 1) * @per_page;
SELECT
article_id,
title,
created_at,
author_name
FROM articles
WHERE published = 1
ORDER BY created_at DESC
LIMIT @per_page OFFSET @offset;
総ページ数の計算
-- 総件数を取得
SELECT COUNT(*) as total_count
FROM articles
WHERE published = 1;
-- アプリケーション側で計算
-- total_pages = ceil(total_count / per_page)
活用例3:サンプリング
データ分析用のサンプル抽出
-- PostgreSQL: ランダムサンプリング
SELECT *
FROM large_dataset
ORDER BY RANDOM()
LIMIT 1000;
-- SQL Server: ランダムサンプリング
SELECT TOP 1000 *
FROM large_dataset
ORDER BY NEWID();
時系列データの間引き
-- 1時間ごとのデータから1日1件を抽出
SELECT *
FROM sensor_data
WHERE DATE(recorded_at) IN (
SELECT DISTINCT DATE(recorded_at)
FROM sensor_data
ORDER BY DATE(recorded_at) DESC
LIMIT 30 -- 過去30日分
)
AND HOUR(recorded_at) = 12 -- 正午のデータのみ
ORDER BY recorded_at DESC;
活用例4:パフォーマンス最適化
バッチ処理での分割実行
-- 大量データを1000件ずつ処理
-- 処理ループ(アプリケーション側)
SET @offset = 0;
SET @batch_size = 1000;
-- 1回の処理
UPDATE products
SET updated_at = NOW()
WHERE product_id IN (
SELECT product_id
FROM products
ORDER BY product_id
LIMIT @batch_size OFFSET @offset
);
-- @offset を @batch_size ずつ増やして繰り返し
インデックス効果の活用
-- 効率的:インデックスがある列でORDER BY
SELECT * FROM users
WHERE active = 1
ORDER BY user_id -- user_idにインデックスあり
LIMIT 50;
-- 非効率:計算結果でORDER BY
SELECT * FROM users
WHERE active = 1
ORDER BY CONCAT(first_name, last_name) -- 計算結果
LIMIT 50;
注意点とベストプラクティス

注意点1:ORDER BYの重要性
悪い例:ORDER BYなし
-- 悪い例:毎回違う結果が返る可能性
SELECT * FROM products
LIMIT 10; -- 順序が不定
良い例:明確な順序指定
-- 良い例:一意の順序が保証される
SELECT * FROM products
ORDER BY product_id
LIMIT 10;
注意点2:大きなOFFSETのパフォーマンス問題
問題のあるクエリ
-- 100万件目から10件取得(非常に遅い)
SELECT * FROM large_table
ORDER BY id
LIMIT 10 OFFSET 1000000;
改善されたクエリ
-- カーソル方式:前回の最後のIDを覚えておく
SELECT * FROM large_table
WHERE id > 1000000 -- 前回の最後のID
ORDER BY id
LIMIT 10;
注意点3:COUNT(*)との組み合わせ
総件数とデータを同時取得
-- PostgreSQL: ウィンドウ関数を活用
SELECT
*,
COUNT(*) OVER() as total_count
FROM products
WHERE category = 'electronics'
ORDER BY price DESC
LIMIT 20 OFFSET 0;
別々に実行する方法
-- 1. 総件数を取得
SELECT COUNT(*) as total_count
FROM products
WHERE category = 'electronics';
-- 2. データを取得
SELECT *
FROM products
WHERE category = 'electronics'
ORDER BY price DESC
LIMIT 20 OFFSET 0;
ベストプラクティス
1. 適切なインデックスの設定
-- ORDER BYで使用する列にインデックス
CREATE INDEX idx_products_price ON products(price);
CREATE INDEX idx_users_created_at ON users(created_at);
2. 条件絞り込みとの組み合わせ
-- WHERE条件で絞り込んでからLIMIT
SELECT *
FROM orders
WHERE order_date >= '2023-01-01'
AND status = 'completed'
ORDER BY order_date DESC
LIMIT 50;
3. 適切な件数の設定
-- ユーザビリティを考慮した件数設定
-- 一覧画面:10〜50件程度
-- API:100〜1000件程度
-- レポート:制限なしまたは大きな値
トラブルシューティング

エラー1:構文エラー
MySQL/PostgreSQLでTOPを使用
-- ❌ エラー:MySQLでTOPは使えない
SELECT TOP 10 * FROM users;
-- ✅ 正解:LIMITを使用
SELECT * FROM users LIMIT 10;
SQL ServerでLIMITを使用
-- ❌ エラー:SQL ServerでLIMITは使えない
SELECT * FROM users LIMIT 10;
-- ✅ 正解:TOPを使用
SELECT TOP 10 * FROM users;
エラー2:OFFSETとFETCHの組み合わせミス
-- ❌ エラー:OFFSETなしでFETCHは使えない
SELECT * FROM products
FETCH NEXT 10 ROWS ONLY;
-- ✅ 正解:OFFSETも指定
SELECT * FROM products
ORDER BY product_id
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY;
エラー3:ページ番号の計算ミス
// JavaScript での正しい計算例
const page = 3; // ページ番号(1から開始)
const perPage = 20; // 1ページの件数
const offset = (page - 1) * perPage; // 40
// SQL
// SELECT * FROM products ORDER BY id LIMIT 20 OFFSET 40;
まとめ:効率的な件数制限のために
目的 | 推奨構文 | 注意点 |
---|---|---|
上位N件を取得 | LIMIT N / TOP N | ORDER BYを必ず使用 |
ページング | LIMIT N OFFSET M | 大きなOFFSETは避ける |
標準SQL対応 | FETCH NEXT N ROWS ONLY | 将来性が高い |
ランダムサンプリング | ORDER BY RANDOM() LIMIT N | パフォーマンスに注意 |
データベース選択の指針
初心者におすすめ
→ MySQL + LIMIT – 最もシンプルで理解しやすい
企業システムでよく使われる
→ SQL Server + TOP/OFFSET-FETCH – 豊富な機能
標準SQL重視
→ PostgreSQL + FETCH – 互換性が高い
パフォーマンス重視のポイント
- 適切なインデックスの設定
- WHERE条件での事前絞り込み
- カーソル方式による大量データ処理
- バッチサイズの最適化
コメント