SQLレベルの制限
SQLクエリ結果セットのサイズを制限するには、SQL:008構文を使用できます。
SELECT title
FROM post
ORDER BY created_on DESC
OFFSET 50 ROWS
FETCH NEXT 50 ROWS ONLY
これは、Oracle 12、SQL Server 2012、またはPostgreSQL8.4以降のバージョンで動作します。
MySQLの場合、LIMIT句とOFFSET句を使用できます。
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
OFFSET 50
SQLレベルのページ付けを使用する利点は、データベース実行プランでこの情報を使用できることです。
したがって、created_on
にインデックスがある場合 列:
CREATE INDEX idx_post_created_on ON post (created_on DESC)
そして、LIMIT
を使用して次のクエリを実行します 条項:
EXPLAIN ANALYZE
SELECT title
FROM post
ORDER BY created_on DESC
LIMIT 50
オプティマイザーは50レコードのみがフェッチされることを認識しているため、データベースエンジンがインデックスを使用していることがわかります。
Execution plan:
Limit (cost=0.28..25.35 rows=50 width=564)
(actual time=0.038..0.051 rows=50 loops=1)
-> Index Scan using idx_post_created_on on post p
(cost=0.28..260.04 rows=518 width=564)
(actual time=0.037..0.049 rows=50 loops=1)
Planning time: 1.511 ms
Execution time: 0.148 ms
JDBCステートメントmaxRows
それはあまり安心できません!
したがって、PostgreSQLで次のクエリを実行すると:
try (PreparedStatement statement = connection
.prepareStatement("""
SELECT title
FROM post
ORDER BY created_on DESC
""")
) {
statement.setMaxRows(50);
ResultSet resultSet = statement.executeQuery();
int count = 0;
while (resultSet.next()) {
String title = resultSet.getString(1);
count++;
}
}
PostgreSQLログに次の実行プランが記録されます。
Execution plan:
Sort (cost=65.53..66.83 rows=518 width=564)
(actual time=4.339..5.473 rows=5000 loops=1)
Sort Key: created_on DESC
Sort Method: quicksort Memory: 896kB
-> Seq Scan on post p (cost=0.00..42.18 rows=518 width=564)
(actual time=0.041..1.833 rows=5000 loops=1)
Planning time: 1.840 ms
Execution time: 6.611 ms
データベースオプティマイザは、50レコードのみをフェッチする必要があることを認識していないため、5000行すべてをスキャンする必要があると想定しています。クエリで多数のレコードをフェッチする必要がある場合、全表スキャンのコストは実際にはインデックスを使用する場合よりも低くなるため、実行プランではインデックスをまったく使用しません。
結論
setMaxRows
のように見えますが ResultSet
のサイズを制限するためのポータブルソリューションです。 、データベースサーバーオプティマイザがJDBC maxRows
を使用しない場合、SQLレベルのページ付けははるかに効率的です。 プロパティ。