Hi guys,
We recently upgraded to Hibernate 3.0 to be able to use filters for a multitenant application, the idea is to filter the database information based on the user's profile and the application being accessed.
However initial testing of the infrastructure has slowed down our performance test cases to run twice as slow. This is by just enabling a filter for all sessions, but not filtering data just yet.
I checked that the SQL being generated is the same for our app, and profiling reveals that the same time is being spend on the MySQL Drivers code with or without filters. however hibernate and antlr time goes up.
This performance hit of course is not good as it guarantees the application will run at least twice as slow for no apparent reason.
I am definitely expecting a performance hit when filtering most of the queries, but certainly I was expecting no change in performance by just enabling a non-used filter.
So the question is any pointers, recommendations, hints or ideas on how to solve this problem ?
Below a sample program that shows and confirms this behaviour
The results I got here are:
Time no filter = 922
Time with filter = 2797
Hibernate version: 3.0
Mapping documents:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping >
<!--
create table testdata (id bigint not null, name varchar(200), level varchar(200));
create unique index nameidx on testdata (name);
create table hibernate_unique_key (next_hi INTEGER);
insert into hibernate_unique_key values (1);
-->
<class name="rg.test.TestBean" table="testdata">
<id name="id" type="long" column="id" unsaved-value="0">
<generator class="hilo"/>
</id>
<property name="name" column="name"/>
<property name="level" column="level"/>
</class>
<filter-def name="levelFilter">
<filter-param name="currentLevel" type="string"/>
</filter-def>
</hibernate-mapping>
Test Program and Bean:Code:
package rg.test;
public class TestBean {
public TestBean(String name, String level) {
this.name = name;
this.level = level;
}
private long id;
private String name;
private String level;
public String getLevel() {
return level;
}
public String getName() {
return name;
}
public void setId(long id) {
this.id = id;
}
public void setLevel(String level) {
this.level = level;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public TestBean() {}
}
Code:
package rg.test;
import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import java.util.Properties;
import org.hibernate.cfg.Environment;
import org.hibernate.Transaction;
import java.util.List;
import java.util.Iterator;
import org.hibernate.Query;
public class FilterTest {
public static void main(String[] arg) {
FilterTest ft = new FilterTest();
ft.executeTest();
}
public FilterTest() {
}
public void executeTest() {
initHibernate();
createTestData();
runTestWithoutFilter();
runTestWithFilter();
closeHibernate();
}
SessionFactory sessions;
long NUM_QUERIES = 1000;
private void initHibernate() {
Properties properties = new Properties ();
properties.setProperty (Environment.DRIVER, "org.gjt.mm.mysql.Driver" );
properties.setProperty (Environment.URL, "jdbc:mysql://localhost/rgtest");
properties.setProperty (Environment.USER, "root");
properties.setProperty (Environment.PASS, "");
properties.setProperty (Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");
Configuration cfg = new Configuration();
cfg.addProperties(properties);
cfg.addClass(TestBean.class);
sessions = cfg.buildSessionFactory();
}
private void closeHibernate() {
sessions.close();
}
private void createTestData(){
Session session = sessions.openSession();
Transaction tx = session.beginTransaction();
Iterator iter = session.createQuery("from TestBean").iterate();
while (iter.hasNext()) {
session.delete(iter.next());
}
tx.commit();
tx = session.beginTransaction();
for (int i=0; i < NUM_QUERIES; i++) {
TestBean t = new TestBean("Name " + i, "Level-" + (i / 10));
session.persist(t);
}
tx.commit();
session.close();
}
private void runTestWithoutFilter() {
long st = System.currentTimeMillis();
for (int i=0; i < NUM_QUERIES; i++) {
Session session = sessions.openSession();
Query q = session.createQuery("from TestBean where name = ?");
String name = "Name " + i;
q.setParameter(0, name);
List l = q.list();
TestBean tb = (TestBean)l.get(0);
session.close();
}
System.out.println("Time no filter = " + (System.currentTimeMillis() - st));
}
private void runTestWithFilter(){
long st = System.currentTimeMillis();
for (int i=0; i < NUM_QUERIES; i++) {
Session session = sessions.openSession();
session.enableFilter("levelFilter").setParameter("currentLevel", "Level-" + (i / 10));
Query q = session.createQuery("from TestBean where name = ?");
String name = "Name " + i;
q.setParameter(0, name);
List l = q.list();
TestBean tb = (TestBean)l.get(0);
session.close();
}
System.out.println("Time with filter = " + (System.currentTimeMillis() - st));
}
}
Name and version of the database you are using: MySQL: 4.0.23