Сократить таблицу до 500 записей в JPQL - PullRequest
0 голосов
/ 12 февраля 2019

Я работаю над каким-то кешем, и время от времени нам нужно сокращать таблицу до 500 записей, основываясь на last_access_date (сохраняю только 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, который является неоптимальным,потому что мы работаем на нескольких СУБД (по крайней мере, Oracle и MSSQL).

Кроме того, setMaxResults() (JPQL-версия LIMIT) не представляется действительной для операторов DELETE.

Неужели нет способа сделать это с помощью JPQL?

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

По соображениям производительности крайне важно не выполнять дополнительную клиентскую поездку в оба конца, просто загрузить 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
)

Если вы не делаете это слишком часто и можете жить свременное несоответствие, вы можете даже реализовать гораздо более быстрое решение:

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

Для более сложных SQL, не зависящих от поставщика, вы можете захотеть использовать построитель SQL, например jOOQ .Могут существовать и другие альтернативы.

Отказ от ответственности: я работаю на поставщика.

0 голосов
/ 12 февраля 2019

Вы можете сделать это:

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)";

Редактировать: ДКБ предложил более быстрое решение для комментариев (зависит от уникальных дат для идеальной точности на количестве оставшихся строк):

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...