java - SQL LIMIT 与 JDBC 语句 setMaxRows。哪一个更好?

标签 java sql postgresql jdbc limit

我想为给定查询选择前 10 条记录。因此,我可以使用以下选项之一:

这两种选择的优缺点是什么?

最佳答案

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 语句最大行数

根据setMaxRows Javadoc :

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 uses TOP or LIMIT. 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/

相关文章:

java - 有没有类似于队列的数据结构,可以对不同的线程进行多播?

java - 使用java在png图像中元数据信息(热点点信息)

java - 正则表达式模式允许长度至少为 8 的字符串,但不允许长度为 16

postgresql - pgadmin 4(或db visualiser)实体关系图

php - 在 WAMP 上集成 postgreSQL

java - OpenNLP 中术语 "Feature"是什么意思?或者在一般的 NLP 中。外行术语会很好

java - ResultSet 从查询转换为 int

mysql - 计算每个唯一元素在 `select` 查询中出现的次数

sql - rails : Custom function in where block

python - 在 SQLAlchemy 中按空值过滤 postgres JSON 列