从数据库中获取最后一条记录的有效方法

Efficient way to get last record from the database

我有一个具有以下 table 结构的数据库:

id | entry | log_type  | user_id | created_on   |
------------------------------------------------|
1  |a      | error     | 1       | 1433752884000|
2  |b      | warn      | 2       | 1433752884001|
3  |c      | error     | 2       | 1433752884002|
4  |d      | warn      | 4       | 1433752884003|

我想根据created_on字段从table获取最后一条记录,目前我正在使用以下查询获取结果列表并使用[=获取其上的最后一条记录38=]:

select * from log_table l where l.user_id=2 and l.log_type = 'error' order by l.created_on desc;

我正在使用 JPA,我在 Query 界面上使用 .getResultList() 执行查询。一旦我得到结果列表,我就会执行 get(0) 以获得所需的最后一条记录。

我有一个很大的 table 数据太多,上面的查询执行时间太长,导致应用程序停止。我现在不能在现有数据上添加额外的索引。除了在数据上添加索引之外,还有一种替代方法可以避免此查询停止。

我正在考虑执行以下查询,

select * from log_table l where l.user_id=2 and l.log_type = 'error' order by l.created_on desc limit 1;

目前我无法在数据库上执行我的第二个查询,因为它可能会导致我的应用程序停止。第二个查询的执行会比第一个查询快吗?

我没有足够大的数据集来重现本地系统上的停顿问题,因此 .我尝试在本地数据库上执行查询,但由于缺少可用的大型数据集,无法确定在返回的查询中添加“limit”后第二个查询是否会更快。

如果上面的第二个查询不能提供更好的结果,我应该采用什么方法来获得优化的查询。

如果第二个查询应该足够好以避免停顿,是否是因为数据库只获取一条记录而不是整组记录的原因?与 looking/fetching 太多记录(如在第一个查询中)相比,数据库对单个记录的处理方式是否不同 looking/fetching 以改善查询时间。

在您 query.getResultList() 之前,您需要 query.setMaxResults(1)。这相当于 LIMIT 1.

但请注意,如果您的实体在查询中有一个关联的子对象集合,实体管理器可能仍然需要执行无限制的 select 来获取它需要的所有数据构建第一个实体。有关详细信息,请参阅 this question and answer

在您的情况下,因为您只需要一个实体,所以我建议您在完成初始查询后延迟加载任何附加的实体。

性能取决于...

ORDER BY x LIMIT 1

是一个常见的模式。它可能非常有效也可能不是很有效 -- 这取决于查询和索引。

你的情况:

where l.user_id=2 and l.log_type = 'error' order by l.created_on desc

这将是最佳的:

INDEX(user_id, log_type, created_on)

使用该索引,它基本上会进行一次探测以找到您需要的行。如果没有该索引,它将扫描大部分或全部 table,将其降序排序 (ORDER BY .. DESC) 并提供第一行 (LIMIT 1)