我想为给定查询选择前 10 条记录。因此,我可以使用以下选项之一:
- 使用 JDBC
Statement.setMaxRows()
方法 - 在 SQL 查询中使用 LIMIT 和 OFFSET
这两种选择的优缺点是什么?
最佳答案
SQL 级 LIMIT
要限制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 语句最大行数
If the limit is exceeded, the excess rows are silently dropped.
这不是很令人放心!
因此,如果我们在 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 行。如果一个查询需要获取大量记录,全表扫描的成本实际上比使用索引要低,因此执行计划根本不会使用索引。
I ran this test on Oracle, SQL Server, PostgreSQL, and MySQL, and it looks like the Oracle and PostgreSQL optimizers don't use the
maxRows
setting when generating the execution plan.However, on SQL Server and MySQL, the
maxRows
JDBC setting is taken into consideration, and the execution plan is equivalent to an SQL query that usesTOP
orLIMIT
. You can run the tests for yourself, as they are available in my High-Performance Java Persistence GitHub repository.
结论
虽然看起来 setMaxRows
是限制 ResultSet
大小的可移植解决方案,但如果数据库服务器优化器不这样做,则 SQL 级分页会更有效不要使用 JDBC maxRows
属性。
关于java - SQL LIMIT 与 JDBC 语句 setMaxRows。哪一个更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32707682/