glassfish
  1. glassfish
  2. GLASSFISH-3251

em.getReference acts like em.find which causes performance issues

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 9.1pe
    • Fix Version/s: not determined
    • Component/s: entity-persistence
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      3,251

      Description

      I found that em.getReference acts the same way as em.find, I mean it does fetch
      entity from database. That causes great performance issues, because everywhere I
      need only a reference, TopLink is fetching entire entity which I do not really
      need.

      That issue was discussed on "users" mailing list:
      https://glassfish.dev.java.net/servlets/BrowseList?list=users&by=thread&from=843385

      Following Tom Ware's suggestion, I am entering this issue as ENHANCEMENT, but
      for me, it should be a DEFECT. Yes, I know "JPA spec." says:

      "Get an instance, whose state may be lazily fetched."

      but I believe, the JPA intention was that it may be lazily fetched only because
      that entity could have been in cache already, so there would be no reason not to
      provide initialized entity.
      As Sahoo from SUN said /in the thread mentioned above/

      "[...] I agree with you that implementing getReference() this way defeats the
      purpose of having that API. I don't know the rational behind the current
      implementation."

        Activity

        Hide
        pljosh added a comment -

        Can anyone, please, try to estimate when that issue could be fixed?
        In my team, we are trying to resolve performance problems, in many cases the
        source of all evil is the fact, that em.getReference is fetching entire object,
        with all its dependencies, look at this example:

        private void acquireLoans(BankStatement bankStatement) {
        for (BankStatementEntry entry : bankStatement.getEntries()) {
        String description = entry.getDescription();
        Matcher matcher = LOAN_CODE_PATTERN.matcher(description);
        String loanCode = matcher.find() ? matcher.group() : null;
        if (loanCode != null)

        { List loanIds = em.createQuery( "SELECT l.id FROM Loan l WHERE l.proposal.loanCode=?1") .setParameter(1, loanCode).getResultList(); if (!loanIds.isEmpty()) entry.setLoan(em.getReference(Loan.class, loanIds.get(0))); }

        }
        }

        Instead of having one simple query per entry, em.getReference is fetching ENTIRE
        Loan, Proposal and dozen of other entities, which multiplied by entires count
        gives hundreds of SQL queries produced by TopLink.

        Everyday I am considering changing the "issue type" into "DEFECT" as this is
        really against Persistence API.

        Show
        pljosh added a comment - Can anyone, please, try to estimate when that issue could be fixed? In my team, we are trying to resolve performance problems, in many cases the source of all evil is the fact, that em.getReference is fetching entire object, with all its dependencies, look at this example: private void acquireLoans(BankStatement bankStatement) { for (BankStatementEntry entry : bankStatement.getEntries()) { String description = entry.getDescription(); Matcher matcher = LOAN_CODE_PATTERN.matcher(description); String loanCode = matcher.find() ? matcher.group() : null; if (loanCode != null) { List loanIds = em.createQuery( "SELECT l.id FROM Loan l WHERE l.proposal.loanCode=?1") .setParameter(1, loanCode).getResultList(); if (!loanIds.isEmpty()) entry.setLoan(em.getReference(Loan.class, loanIds.get(0))); } } } Instead of having one simple query per entry, em.getReference is fetching ENTIRE Loan, Proposal and dozen of other entities, which multiplied by entires count gives hundreds of SQL queries produced by TopLink. Everyday I am considering changing the "issue type" into "DEFECT" as this is really against Persistence API.
        Hide
        pkrogh added a comment -

        This section of the specification was intentionally written in this way so that
        providers could implement getReference() by doing a find() or by lazily
        fetching it. This is an enhancement, that does not fit into the schedule for
        this release, but will be looked at for future releases.

        Your example usecase is one that showcases the usefulness of lazy loading
        getReference() the best, but I would argue that if performance is a concern,
        there are things that you could do with this case, that would give you a much
        bigger bang for your buck.

        • Using Lazy loading of relationships. By making your relationships load
          lazily, you will cut down on the SQL that gets generated by your getReference()
          call, and also improve performance in the other parts of your app.
        • Caching. By querying for PKs directly you are avoiding cache hits that
          could make getReference() and find() calls much faster.
        Show
        pkrogh added a comment - This section of the specification was intentionally written in this way so that providers could implement getReference() by doing a find() or by lazily fetching it. This is an enhancement, that does not fit into the schedule for this release, but will be looked at for future releases. Your example usecase is one that showcases the usefulness of lazy loading getReference() the best, but I would argue that if performance is a concern, there are things that you could do with this case, that would give you a much bigger bang for your buck. Using Lazy loading of relationships. By making your relationships load lazily, you will cut down on the SQL that gets generated by your getReference() call, and also improve performance in the other parts of your app. Caching. By querying for PKs directly you are avoiding cache hits that could make getReference() and find() calls much faster.
        Hide
        Tom Mueller added a comment -

        Bulk change to set fix version to "not determined" where the issue is open but the value is for a released version.

        Show
        Tom Mueller added a comment - Bulk change to set fix version to "not determined" where the issue is open but the value is for a released version.

          People

          • Assignee:
            tware
            Reporter:
            pljosh
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: