JPA Container Performance

Hello!

I have a performance issue with the JPA Container. I have configured Hibernate to output the SQL queries it does. It seems that JPA Container first fetches all IDs of the rows to display sequentially and then the row data of each id it found out also sequentially. This is really slow on MySQL if you have large tables. MySQLs LIMIT keyword get’s slower if the tables grow. It would be much faster to do a single query with a LIMIT to do the lazy fetching. Is there a special reason why it’s not implemented that way?

Regards
Ralph

I also wonder on this. Is there a way to change the fetch settings of the JPA container. Fetching one item at a time sequentially doesn’t seem so effective.

Thanks.

I want to get my two cents in on this too.

I’ve just started experimenting with JPAContainer and I had assumed that I just couldn’t find the right setting to make it fetch all visible rows with one query.

Is there such a setting? Or another alternative?

Thanks,

J

Hi!

I’m having the same issue with MSSQL. I might not be able to use this addon in a production environment.
Does anyone have a solution for this?
Maybe I’m not configuring it right…

Thank you!

I have the same problem and I haven’t found any documentation on this.

The amount of queries that is makes for a table with dozens of records is difficult to justify

Is it poor implementation or some setting ?

If I don’t find a workaround I will have to use other container or implement my own…
Thanks,
BM.

Hello,

I’ve seen that using CachingLocalProvider instead LocalProvider ( mutable or not ), the container does not execute a large amount of sql queries and the table loading time is very fast.

Hope this can help you

Hello all, i’m resuming this post 'cause i’m experiencing the same issue.

I read in some other thread that 2.0 version of JPAContainer would address this, but it seems to work in the same one-query-per-row way…

Any news?

Thanks
Andrea

I’d be interested in hearing updates on this issue as well, we’re experiencing the same.

Well, that makes sense, since it is caching them :slight_smile: Yet, even for the caching version it generates 1 select per row until the cache is filled up. However, in the real world, the cache doesn’t stay populated for very long, since the CachingSupport behind CachingLocalProvider is implemented so that the complete cache is invalidated once a single entity is updated/added/removed

Hi,

Looking at the code it looks like it is making a query for each row. There is also a comment in the code that suggest to consider some better approach. Luckily lookups by id are fast on all databases (or then you don’t have indexed id column!!). The more expensive queries that fetch the order of items fetch only identifiers and those queries are quite well optimized (intelligent batches so that next api call most likely hits cache). Jonatan (with help of Florian Pirschner) tested the performance with some huge tables and found the performance to be good with the caching provider as where the non-caching provider became unacceptably slow.

If this really becomes a performance issue for somebody we could make it work like in HbnContainer. There whole items are always fetched, even when Vaadin asks for just items. This way JPA implementation caches the entity on the same query. To get wheels rolling on fast on this frontier, I’d suggest to create
an enhancement ticket
,
go for Pro
and vote for the feature (or buy expert hours specifically for this enhancement).

BWT. On my debug console there isn’t that many queries though. Either jpa implementation caches entities or same query is “flattened” on the debug output. Dunno for sure without further investigation.

cheers,
matti

Since this has not been resolved yet with Vaadin 7.1.5 (and 2013 being almost over!!), I tried a hack to solve this by getting the EntityManager to preload the batch of entities just before the JPAContainer looks for them.

It was tricky, but I found that the EntityProvider’s “doGetEntityCount()” method is invoked just before the N queries begin. The result from this method is cached if your JPAContainer uses CachingLocalEntityProvider which means that doGetEntityCount() is only actually invoked once per “table refresh”.

So what I did was intercept this method to add some code to get the EntityManager to preload the entities, which then happen to be in the cache later when the JPAContainer looks for them and thus the “1 query per entity” is avoided.

This works by extending CachingLocalEntityProvider, like this:

public class MyCachingLocalEntityProvider extends CachingLocalEntityProvider
{
    @Override
    protected int doGetEntityCount(EntityContainer container, Container.Filter filter)
    {
        try
        {
            String entityIdPropertyName = getEntityClassMetadata()
                    .getIdentifierProperty().getName();

            CriteriaBuilder cb = doGetEntityManager().getCriteriaBuilder();
            CriteriaQuery<Long> query = cb.createQuery(getEntityClassMetadata().getMappedClass());
            Root root = query.from(getEntityClassMetadata().getMappedClass());

            List<Predicate> predicates = new ArrayList<Predicate>();
            if (filter != null)
            {
                predicates.add(FilterConverter.convertFilter(filter, cb, root));
            }
            if (!predicates.isEmpty())
            {
                query.where(CollectionUtil.toArray(Predicate.class, predicates));
            }
            int prefetchSize = 150;
            TypedQuery<Long> tq = doGetEntityManager().createQuery(query).setMaxResults(prefetchSize);
            List resultList = tq.getResultList();
        }
        catch (Exception e)
        {
          e.printStackTrace(); //just to be sure no disruption is caused
        }
        return super.doGetEntityCount(container, filter);
    }
}

To use this special provider you need to create your JPAContainer manually, like:

EntityManager em = .... //get it from the Factory.
container = new JPAContainer(clazz);
container.setEntityProvider(new MyCachingLocalEntityProvider(clazz, em));

For me this solved the “N+1” queries caused by the way the algorithm of fetching IDs first and then the row data.

I had an iadditional issue of N+1 queries and EclipseLink, but it was due to eager loading of @OneToOne relationships. If you run into it, make sure to mark the non owning side of the relationship as Lazy fetched:

@OneToOne(mappedBy = "fieldName",fetch = FetchType.LAZY ) @BatchFetch(BatchFetchType.IN)

… it doesnt hurt to add @BatchFetch(BatchFetchType.IN) to the owning side too.

Anyway, I tried this with Vaadin 7.1.5 and JPAContainer 3.1.0 and it worked like a charm, now I only get 3 queries total for my JPAContainer-powered Table.