Я хочу создать пакетное удаление, например: УДАЛИТЬ t ГДЕ t.my_attribute = ?
Первая попытка была:
private void deleteRecord( ) {
//loop
final MyRecord myRecord = new MyRecord();
myRecord.setMyAttribute(1234);
getDslContext().batchDelete(myRecord) .execute();
}
Но здесь SQL всегда содержит pk вместо моего атрибута.
Вторая попытка состояла в том, чтобы создать оператор удаления со значением привязки, но здесь я не нашел решения, как я могу создать предложение where с помощью?
//loop
getDslContext().delete( MY_RECORD ).where( ???)
.bind( 12234 );
Может ли кто-нибудь помочь мне дальше?
DELETE
Просто добавьте свой предикат сравнения, как в SQL:
getDslContext()
.delete(T)
.where(T.MY_ATTRIBUTE.eq(12234))
.execute();
Предполагается, что вы используете генератор кода, поэтому вы можете статически импортировать ссылку на таблицу com.example.generated.Tables.T
.
У вас есть два варианта группирования таких операторов в jOOQ:
1. Использование явного пакетного API
Как объяснено здесь, создайте запрос с фиктивным значением привязки, как показано выше, но не выполняйте его напрямую, вместо этого используйте Batch
API:
// Assuming these are your input attributes
List<Integer> attributes = ...
Query query = getDslContext().delete(T).where(T.MY_ATTRIBUTE.eq(0));
getDSLContext()
.batch(query)
.bind(attributes
.stream().map(a -> new Object[] { a }).toArray(Object[][]::new)
).execute();
2. Собирать отдельные исполнения в пакетном соединении
Вы всегда можете использовать удобный групповая коллекция в jOOQ, чтобы прозрачно собирать выполняемый SQL и откладывать его в пакет:
getDslContext().batched(c -> {
for (Integer attribute : attributes)
c.dsl().getDslContext()
.delete(T)
.where(T.MY_ATTRIBUTE.eq(attribute)
.execute(); // Doesn't execute the query yet
}); // Now the entire batch is executed
В последнем случае строка SQL может генерироваться повторно для каждого отдельного выполнения, поэтому первый вариант, вероятно, лучше подходит для простых пакетов.
Однако зачем выполнять пакет, если можно выполнить один запрос? Просто сделать это, может быть?
getDslContext()
.delete(T)
.where(T.MY_ATTRIBUTE.in(attributes))
.execute();
Большое спасибо за подробный ответ. 1. Вот как я это реализовал. Я просто не был уверен, что фиктивное значение было правильным. 2. Посмотрю, может поможет. 3. Я недостаточно знаю JOOQ, но как JOOQ решает проблему, когда в предложении IN слишком много параметров? И действительно ли один запрос с большим предложением «IN» > 1000 элементов быстрее?
@MelleD: Да, jOOQ решает обе эти проблемы, см. jooq.org/doc/latest/manual/sql-building/dsl-context/…, а также jooq.org/doc/latest/manual/sql-building/dsl-context/…, если вам нужно беспокоиться о конфликте кэша курсора (например, в Oracle). Будет ли это быстрее, вы должны измерить себя, например. используя эта эталонная техника. Вы также можете использовать массивы в некоторых СУБД: blog.jooq.org/….
@MelleD: имейте в виду, что одним из факторов, который сильно повлияет на производительность, является размер транзакции. Если вы используете базу данных MVCC, удаление 1 млн записей в одной транзакции может создать массу параллелизма в других сеансах, обращающихся к этой таблице. Серебряной пули нет...
Я использую SQL Server. Так что, если я правильно понял статью, разве ПАКЕТ не должен вызывать меньше проблем?
@MelleD: я не могу сделать общее заявление о том, какой подход будет для вас лучшим в целом.
ок надо тестить. Как JOOQ справляется с проблемой параметра 2100 в SQL Server? Разделяются ли выборки, потому что не более 2100 параметров идут напрямую в один выбор "IN"
@MelleD: Вы проверили ссылки, которые я предоставил? Ответ на это в этом: jooq.org/doc/latest/manual/sql-building/dsl-context/…
да, конечно «По умолчанию jOOQ автоматически встроит все переменные связывания в любой оператор SQL, как только эти пороговые значения будут достигнуты», и что тогда произойдет? Насколько я знаю, для SQL Server нет никакой разницы, если вы привязываете 2100 '?' или используйте 2100 встроенных значений. Если вы используете более 2100 параметров в IN, вам придется сделать несколько выборок. Или у вас был другой опыт?
@MelleD: Наши интеграционные тесты говорят об обратном, но почему бы вам просто не попробовать это с jOOQ и посмотреть, что получится. Вы можете включить ведение журнала отладки, чтобы увидеть, что генерирует SQL jOOQ: jooq.org/doc/latest/manual/sql-execution/регистрация
Ах, я нашел проблему. Я думал, что это автоматически устанавливается из диалекта. Спасибо, хорошая подсказка, тогда мы не справились с этим сами :)
@MelleD: Да, это часть философии jOOQ. Вам не нужно разбираться со всеми этими скучными низкоуровневыми деталями различных диалектов SQL. :)
Очень хорошая философия от jOOQ :). Кривая обучения будет продолжать расти, когда мы отойдем от JPA. Я был / я только испорчен весенней загрузкой, что такие диалектные вещи устанавливаются напрямую, но только что протестированные работают отлично. Дополнительные снова узнали, что встроенный идет прямо хорошо знать. Еще раз спасибо Лукасу за очень хороший и подробный ответ.
Я думаю, что Spring Boot может автоматически настраивать только версию jOOQ с открытым исходным кодом? Как вы думаете, почему кривая обучения повысится?
Мне все еще нужно протестировать весеннюю загрузку с вариантом без открытого исходного кода. Это вводило в заблуждение, что моя кривая обучения увеличится;)
Да, но тогда у меня нет пакетного удаления, верно? Мне нужно пакетное удаление