我正在使用某种类型的缓存,因此有时需要根据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()
(LIMIT
的JPQL版本)对于DELETE
语句似乎无效。
使用JPQL真的没有办法做到这一点吗?
答案 0 :(得分:3)
您可以这样做:
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();
答案 1 :(得分:2)
出于性能原因,必须不要仅加载500个ID值然后再次将其发送到服务器来执行其他客户端往返。相反,我建议使用以下两种方法之一:
您当前仅支持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
)
如果您不经常这样做,并且可以忍受暂时的不一致,那么您甚至可以实现更快的解决方案:
Oracle
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 Server
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,您可能需要考虑使用jOOQ之类的SQL构建器。其他选择也可能存在。
免责声明:我为供应商工作。