All streams
Search
Write a publication
Pull to refresh

Comments 16

Что-то странная статья. На сколько я помню в Hibernate есть Batch Insert. Судя по статье это именно то что вам нужно.

UFO landed and left these words here
Абсолютно верно! Есть batch, его размер задается через проперти. У спринга чуть по другому называется.
Есть проблема над решением которой дествительно можно было бы написать статью:
При вставке новых больших данных с id!=null, хибер сначала лезет в БД и узнает есть ли уже такая запись, если нет, делает insert иначе update. Получается на 20К вставок идет 20К select.
Тут варианты:
— либо писать ручками — и довольно много ручного труда
— либо сущность наследовать от Interface Persistable переоперделять метод isNew [не самый безопасный вариант, ломается логика save, delete и возможно еще каких-либо]
Я предпочел ручной вариант хоть и с postgreSql при этом приходится повозится, т.к. если нужно чтобы запись при вставке уже существующего id обновлялась, приходится все колонки дублировать.
>Тут варианты:
>— либо писать ручками — и довольно много ручного труда
Ну вообще у MS SQL есть merge, и труда там не так уж и много. Нестандартно, необычно — может быть, но не более.
Ну да, вручную. Я про это и говорю — что этого ручного труда не так и много, как может показаться.

>И про MS SQL речи не было.
У автора как раз все про него. У других есть аналоги, merge не самый удобный.
Можете попробовать, если у вас uuid. Ну или с другими генераторами поэкспериментировать.

@GeneratedValue(generator = "UUID")
 @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator")
Почему бы не написать сторед-процедуру, которой в качестве параметра передать сериализованный в строку XML? Разве это не лучше, чем лапшекод на новом гиперуровне, когда сначала мы объявляем свободу от конкретики RDBMS, а затем делаем трудночитаемые и непроверяемые inline-вставки на ассемблере T-SQL?

Уж лучше такое иметь в контролируемом в design-time (пусть даже в database-design-time ;) ) модуле, чем в виде непроверяемой многострочной лапши с опасностью SQL-инъекции через недоэкранированные литералы
не впечатляет. 500к записей в секунду и выше — вот это будет близко к пределу средненького сервера
500к/sec — это не показатель. Совсем.
500к может быть в записи на 2 int поля с 1 primary key,
а может 800+ полей, 50+ ссылок на др. таблицы и дочерними записями (т.е. каждый insert нужно заворачивать в explicit transaction).
А зачем отдельная таблица? Если вы создаете xml то его можно напрямую использовать в native query.
И еслу уж вобще придираться, возможен вариант с native query и массивом как параметр, тогда вообще xml не нужен.
Вместо включения batch в хибере или переходом на что-то более легковесное (jooq, например), добавим еще xml, чтобы точно на все деньги было.
Вы подняли ворох проблем, который утопил нашего Enterprise Architect из-за неверного вектора решения. :)
Итак, проблемы:
1. Действительно, Hibernate генерит массу отдельных insert запросов. Можно оптимизировать on-prem, но в облаке небольшой network latency на 500,000 добавлений вываливается в панику клиентов.
Однако, есть еще и серверная сторона:
2. Чем больше индексов в OLTP базе, тем дольше идет перестройка после каждого insert
3. Чем больше RI, тем дольше верификация
4. При наличии дочерних таблиц (что в статье не было учтено), транзакция утяжеляется.

Наше решение:
— валидация данных перед bulk insert
— bulk insert
— перестройка индексов по окончании добавления данных

Проблема решения: при невалидных данных или ошибке, откатывается весь импорт.
Плюс: максимально-возможная скорость т.к. иморт данных идет с закрытыми глазами, без проверок на каждой записи.
А что если между «валидация данных перед bulk insert» и «bulk insert» другая сессия изменит данные и они станут не валидными при нашем «bulk insert»? Блокировать всю таблицу предлагаете?
П.С. а если есть внешние ключи, то и все связанные таблицы тоже

Об этом и написано в конце комментария: в случае невалидных данных/ошибки весь импорт будет откачен, т. к. выполняется одной транзакцией. Но обычно, когда такие вещи делаются, позволять кому-то ещё менять таблицу и/или связанные таблицы не очень хорошая идея и имеет смысл выставить блокировку. Хотя есть и исключения. Логи те же самые. Как вы понимаете, в этом случае крайне маловероятно, что какая-либо сессия так изменит данные, что пакетная вставка окажется невалидной. А вот каждую запись в транзакцию оборачивать в высоконагруженной системе — сервер БД может и не потянуть.

тогда абсолютно с вами согласен, максимальной производительности, консистентности данных и простоты можно добиться использую проверки на уровне БД (UNIQUE, CHECK, FK, ASSERTION), обернув bulk insert в одну транзакцию
Sign up to leave a comment.

Articles