繁体   English   中英

将表修剪到JPQL中的500条记录

[英]Prune table to 500 records in JPQL

我使用某种类型的缓存,有时需要根据last_access_date (仅保留最近访问的500行)将表修剪为500条记录。

使用“普通” SQL,可以通过以下方式完成:

DELETE FROM records WHERE id not in 
    (SELECT id FROM records ORDER BY last_access_date DESC LIMIT 500)

现在,由于在JPQL中没有LIMIT或类似ROWNUM的内容,所以我发现的唯一解决方案是在本机SQL中,它是次优的,因为我们在多个DBMS(至少是Oracle和MSSQL)上运行。

另外, setMaxResults() (JPQLs版本的LIMIT )对于DELETE语句似乎无效。

JPQL真的没有办法做到这一点吗?

您可以这样做:

String sql = "SELECT x.id FROM records x ORDER BY x.last_access_date DESC";
TypedQuery<Long> query = em.createQuery(sql, Long.class);

List<Long> ids = query.setMaxResults(500).getResultList();

String delete = "DELETE FROM records x where x.id not in :ids";
em.createQuery(delete).setParameter("ids", ids).executeUpdate();

我不记得删除查询的确切语法,因此您可能必须将:ids放在括号之间,例如:

String delete = "DELETE FROM records x where x.id not in (:ids)";

编辑: dkb提出了一种关于注释的更快的解决方案(取决于唯一日期以确保剩余行数的完美准确性):

String sql = "SELECT x.last_access_date FROM records x ORDER BY x.last_access_date DESC";

//If you're not using calendar, change to your specific date class
TypedQuery<Calendar> query = em.createQuery(sql, Calendar.class);

Calendar lastDate = query.setFirstResult(499).setMaxResults(1).getSingleResult();

String delete = "DELETE FROM records x where x.last_access_date < :lastDate";
em.createQuery(delete).setParameter("lastDate", lastDate, TemporalType.DATE).executeUpdate();

出于性能原因,必须不要仅加载500个ID值然后再次将其发送到服务器来执行其他客户端往返。 相反,我建议使用以下两种方法之一:

使用供应商特定的SQL

您目前仅支持2个RDBMS。 编写两个单独的SQL语句应该是可管理的。 在这种情况下,由于仅使用Oracle和SQL Server,因此实际上可以使用标准SQL来实现:

DELETE FROM records 
WHERE id NOT IN ( 
  SELECT id 
  FROM records 
  ORDER BY last_access_date DESC 
  OFFSET 0 ROWS -- SQL Server needs this
  FETCH FIRST 500 ROWS ONLY
)

如果您不经常这样做,并且可以忍受暂时的不一致,那么您甚至可以实现更快的解决方案:

甲骨文

CREATE TABLE temp AS 
SELECT * 
FROM records 
ORDER BY last_access_date DESC
FETCH FIRST 500 ROWS ONLY;

TRUNCATE TABLE records;

INSERT INTO records 
SELECT * FROM temp;

DROP TABLE temp;

SQL服务器

SELECT TOP 500 *
INTO temp
FROM records
ORDER BY last_access_date DESC;

TRUNCATE TABLE records;

INSERT INTO records
SELECT * FROM temp;

DROP TABLE temp;

使用SQL构建器

对于更复杂的与供应商无关的SQL,您可能需要研究使用诸如jOOQ之类的SQL构建器。 可能存在其他替代方案。

免责声明:我为供应商工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM