Thursday, July 16, 2015

Choose ORM carefully

Introduction

We have recently migrated source code from Hibernate ORM to JDBC (Spring JDBC template) based implementation. Performance has been improved 10 times. This post describes the use-case, bench-marking and the migration steps. 

Use case

A tree structure in database is getting populated from a deep file system (directory structure) having around 75000 nodes. Each node (directory) contains text files, which get parsed based on business rules and then populate the database ( BRANCHs representing a node,  tables referring to branch, tree_nodes).  The database tables was well mapped to Hibernate JPA entries and on saving Branch object, its relevant entities were automatically getting saved. Whole operation was performed in recursive manner by traversing over directory tree. Each table’s primary key is auto generated from a separate sequence.
As per development level performance testing, it was estimated that initial tree will take 30 hours to load whole tree. This was not acceptable, as UAT cannot be started without this migration. (Env : Oracle 11g, JBoss 6, JDK 6, Hibernate, Spring 3)

Bench-marking: Hibernate vs Spring JDBC

Data model

Create table and sequence

CREATE SEQUENCE customer_ID_SEQ START WITH 1 INCREMENT BY 1;
create table customer (id bigint not null, name varchar(200), primary key (id));

Model

@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE,
  generator = "CUSTOMER_ID_SEQ")
  @SequenceGenerator(name =  "CUSTOMER_ID_SEQ",
  sequenceName =  "CUSTOMER_ID_SEQ", allocationSize = 1)
  private long id;
  private String name; // application assigned

  @Column(name = "NAME")
  …
  …

Approaches

1.      Approach 1 : Existing

@Transactional
  public void bulkPersist(List<Customer> entities) {
    for (Customer entity : entities) {
      em.persist(entity);
    }
 }

2.      Approach 2 : Batch size - Set hibernate batch-size property and flushing after  a batch same.

@Transactional
  public void bulkPersist(List<Customer> entities) {
    int i = 0;
    for (Customer entity : entities) {
      em.persist(entity);
      i++;

      if (i % batchSize == 0) {
        flush();
        clear();
      }
    }
}
3.      Approach 3 : JDBC template

@Transactional
 public void bulkPersist (final List<Customer> entities) {
 template.batchUpdate("insert into customer (id, name) values (CUSTOMER_ID_SEQ.nextval, ?)", new    
       BatchPreparedStatementSetter() {
       
        @Override
        public void setValues(PreparedStatement ps, int i) throws SQLException {
                  ps.setString(1, entities.get(i).getName());
         
        }
       
        @Override
        public int getBatchSize() {
                return entities.size();
        }
        });
 }

Result

Approach 3 is coming out 10 time faster than that of Approach 1. Approach 2 has also improved the performance but lessor then that of Approach 3;

Migration

As per benchmarking, Spring JDBC template’s ‘batchUpdate’ is the fastest as compared to hibernate based approaches. Now while migrating code base from hibernate to JDBC, biggest issue was to resolve the generated ID referred in other queries. 

Since ID is getting generated by a sequence and Spring JDBC template’s ‘batchUpdate’ do not have provision to fetch generated IDs. Hibernate was doing this automatically by updating ID field of the entity object.

 So solve this, we had fetched bulk ids from the sequence, in a single query:
List<Integer> ids = template.queryForList("select customer_id_seq.nextval from (select level from dual connect by LEVEL <="
                                                                    entities.size() +")", Integer.class);
     
Set ids in entity object while iterating BatchPreparedStatementSetter.setValues method
    public void setValues(PreparedStatement ps, int i) throws SQLException {
              Customer customer = entities.get(i);
               customer.setId(ids.get(i));
              ps.setInt(1, customer.getId());
              ps.setString(2, customer.getName());
    }

This way entity object get populated in the same way as it is done in hibernate, without any special iteration/processing. Once entity object is populated, all the dependent batches can be fired so that entity.getId returns the correct value.

We were able to migrate Hibernate based codebase to Spring JDBC with minimal changes in source code. To save JVM memory, we have also implemented batching over it. Processed only 2000 nodes at a time.

After porting codebase to Spring JDBC Template, we measured performance for the tree load, on local database and it was coming out around 3 hrs. We run the same on UAT environment, and the whole tree get loaded in 1 hour.


Friday, June 22, 2012

Client Vs Server Side Validation


I am writing this post in reply to the questions asked in an Technical  Workshop presented by me, “What is best way of validation, client side or server side or both?”, “Why to duplicate the validations at client and server side?”.

What is validation?
Come on, I am sure you know this.

Ok what is Client-side Validation?
Simple, the validations which are done at client side. Usually done by java scripts.

And Server-side Validation?
Obliviously, the validation which are done at server side are the server-side validations. Server side code do this.

Which one should I use? - Server-side Validation Or Client-side Validation Or Both
Yes this the topic of discussion. I think, it does not matter which one is best or which one is worst, the server-side validations are must. Client side validation are in the scope of client, he can disable the javascripts or bypass them by seeing the javascript code ( most of the browser now come with javascript debugging support with watches or so).

Ok it means server side validation is best, so we should not use client-side validation?
Well, I haven’t said this. You should consider having client-side validation as well. It is useful to increase the usability of the web application, improve the user experience by speeding up the interaction, instead of waiting for the server side validation and seeing the error only after filling up so many information.

So I think both should be used, first perform client side validation to improve user experience and then once a form is submitted to server, validate there as well to check the correctness of the input.


Nowadays, AJAX based validation is also used to provide better user experience with the power of server-side validation, but I still say server side validation is must even after this.

Monday, May 28, 2012

Software Effectiveness Vs Software Efficiency


I define software effectiveness as, doing the objective effectively, I mean correctly. Efficiency can be defined as, using the resources optimally where resources could be memory, CPU, time, files, connections, databases etc.

From my experience, in most(should I call many) of the software projects, efficiency/performance is not much accentuated during the system design and earlier phases(requirement and estimation) as compared to the emphasis given in later phases, coding and testing and mostly in maintenance.
Stressing on efficiency, during the early SDLC phases, can eliminate lot of problems. If we consider the efficiency late say in coding phase, then we probably able to develop an optimal system in which 90% of the code using just 1% of CPU time in peak load, but 10% of code is using 99% of CPU. If we worry about the performance only after the system is built then we are in the worst situation, we probably could not reach 90% optimal code level.

Coming back to effectiveness, usually this is the most emphasized topic in all the SDLC phases, we always try to make the system understandable, testable, and maintainable.
Note that, efficiency is generally against the code quality measures that were considered to improve effectiveness, more efficient code is usually more difficult to understand, hard to maintain, sometime very hard to test.

So based on project, we should benchmark/strengthen the SDLC process to balance-out the efficiency and effectiveness in each phases. Keep it in mind that there are always some modules where efficiency is more concerned than the understandability, maintainability. We may change our mind setup when understanding a highly efficient module that this will require more effort to understand, maintain and test.

This post is not meant to allow the developer writing less effective code, saying that you are writing efficient code so; it will be less understandable, not testable and not maintainable. Use better design pattern, prepare approach and discuss it, design the efficient module very carefully.