Need to insert 100000 rows in mysql using hibernate in under 5 seconds
After trying all possible solutions I finally found a solution to insert 100,000 rows under 5 seconds!
Things I tried:
1) Replaced hibernate/database's AUTOINCREMENT/GENERATED id's by self generated ID's using AtomicInteger
2) Enabling batch_inserts with batch_size=50
3) Flushing cache after every 'batch_size' number of persist() calls
4) multithreading (did not attempt this one)
Finally what worked was using a native multi-insert query and inserting 1000 rows in one sql insert query instead of using persist() on every entity. For inserting 100,000 entities, I create a native query like this "INSERT into MyTable VALUES (x,x,x),(x,x,x).......(x,x,x)"
[1000 row inserts in one sql insert query]
Now it takes around 3 seconds for inserting 100,000 records! So the bottleneck was the orm itself! For bulk inserts, the only thing that seems to work is native insert queries!
You are using Spring for managing the transaction but break it by using
thread
as the current session context. When using Spring to manage your transactions don't mess around with thehibernate.current_session_context_class
property. Remove it.Don't use the
DriverManagerDataSource
use a proper connection pool like HikariCP.In your for loop you should
flush
andclear
theEntityManager
at regular intervals, preferably the same as your batch size. If you don't a single persist takes longer and longer, because when you do that Hibernate checks the first level cache for dirty objects, the more objects the more time it takes. With 10 or 100 it is acceptable but checking 10000s of objects for each persist will take its toll.
-
@Service
@Transactional
public class ServiceImpl implements MyService{
@Autowired
private MyDao dao;
@PersistenceContext
private EntityManager em;
void foo(){
int count = 0;
for(MyObject d : listOfObjects_100000){
dao.persist(d);
count++;
if ( (count % 30) == 0) {
em.flush();
em.clear();
}
}
}
For a more in depth explanation see this blog and this blog.