我想选择给定查询的前10条记录。因此,我可以使用以下选项之一:
Statement.setMaxRows()
方法这两种选择的优缺点是什么?
最佳答案
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或PostgreSQL 8.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根据
setMaxRows
Javadoc:这不是很让人放心!
因此,如果我们在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级别的分页会更加有效。