弹簧规范冗余连接

时间:2018-12-11 23:10:03

标签: spring spring-data-jpa specifications

我正在使用spring规范与数据库进行交互,但是我可以看到,在生成的sql查询中,存在多余的联接,这使得查询非常慢,这里是代码:

Subquery < Mission > usersAccessSubquery = query.subquery(Mission.class);
Root < Mission > usersAccessSubqueryRoot = usersAccessSubquery.from(Mission.class);
usersAccessSubquery.select(usersAccessSubqueryRoot);

Subquery < Mission > groupesAccessSubquery = query.subquery(Mission.class);
Root < Mission > groupesAccessSubqueryRoot = groupesAccessSubquery.from(Mission.class);
groupesAccessSubquery.select(groupesAccessSubqueryRoot);

Subquery < Mission > groupesAccessSubqueryAdmin = query.subquery(Mission.class);
Root < Mission > groupesAccessSubqueryRootAdmin = groupesAccessSubqueryAdmin.from(Mission.class);
groupesAccessSubqueryAdmin.select(groupesAccessSubqueryRootAdmin);

Predicate usersAccessPredicate = cb.equal(cb.lower(usersAccessSubqueryRoot.join("usersAccess").join("userRef").get("email")), authUserMail.toLowerCase());
Predicate groupesAccessPredicate = cb.equal(cb.lower(groupesAccessSubqueryRoot.join("groupesAccess").join("users").join("userRef").get("email")), authUserMail.toLowerCase());
Predicate groupesAccessPredicateAdmin = cb.equal(cb.lower(groupesAccessSubqueryRootAdmin.join("groupe").get("label")), groupe.getLabel().toLowerCase());

Predicate rootPredicate = cb.conjunction();

usersAccessSubquery.where(usersAccessPredicate);
groupesAccessSubquery.where(groupesAccessPredicate);
groupesAccessSubqueryAdmin.where(groupesAccessPredicateAdmin);

query.where(cb.and(
    cb.or(
        cb.equal(cb.lower(cb.trim(root.get("createdBy"))), authUserMail.toLowerCase().trim()),
        cb.in(root.join("mission").get("id")).value(usersAccessSubquery),
        cb.in(root.join("mission").get("id")).value(groupesAccessSubquery),
        cb.in(root.join("mission").get("id")).value(groupesAccessSubqueryAdmin)
    ),
    rootPredicate
));

和生成的sql查询:

SELECT DISTINCT user0_.id            AS id1_25_, 
                user0_.created_by    AS created_2_25_, 
                user0_.creation_date AS creation3_25_, 
                user0_.groupe_id     AS groupe_i6_25_, 
                user0_.role_id       AS role_id7_25_, 
                user0_.update_date   AS update_d4_25_, 
                user0_.updated_by    AS updated_5_25_, 
                user0_.user_ref_id   AS user_ref8_25_ 
FROM   users user0_ 
       INNER JOIN user_ref userref1_ 
               ON user0_.user_ref_id = userref1_.id 
       INNER JOIN user_ref userref2_ 
               ON user0_.user_ref_id = userref2_.id 
       INNER JOIN user_ref userref3_ 
               ON user0_.user_ref_id = userref3_.id 
       INNER JOIN groupes groupe4_ 
               ON user0_.groupe_id = groupe4_.id 
       INNER JOIN mission missions5_ 
               ON groupe4_.id = missions5_.client_entity_id 
       INNER JOIN groupes groupe6_ 
               ON user0_.groupe_id = groupe6_.id 
       INNER JOIN mission missions7_ 
               ON groupe6_.id = missions7_.client_entity_id 
       INNER JOIN groupes groupe8_ 
               ON user0_.groupe_id = groupe8_.id 
       INNER JOIN mission missions9_ 
               ON groupe8_.id = missions9_.client_entity_id 
WHERE ( Lower(userref1_.username) LIKE 'a%' 
         OR Lower(userref2_.first_name) LIKE 'a%' 
         OR Lower(userref3_.last_name) LIKE 'a%' ) 
      AND ( missions5_.id IN (SELECT mission10_.id 
                              FROM   mission mission10_ 
                                     INNER JOIN groupes groupe11_ 
                                             ON mission10_.groupe_id = 
                                                groupe11_.id 
                              WHERE  Lower(groupe11_.label) = 
                                     'tls team') 
             OR missions7_.id IN (SELECT mission12_.id 
                                  FROM   mission mission12_ 
                                         INNER JOIN mission_users_access 
                                                    usersacces13_ 
                                                 ON mission12_.id = 
                                                    usersacces13_.mission_id 
                                         INNER JOIN users user14_ 
                                                 ON 
                                         usersacces13_.users_access_id = 
                                         user14_.id 
                                         INNER JOIN user_ref userref15_ 
                                                 ON user14_.user_ref_id = 
                                                    userref15_.id 
                                  WHERE  Lower(userref15_.departement) = 
                                         'test@test.com') 
             OR missions9_.id IN (SELECT mission16_.id 
                                  FROM   mission mission16_ 
                                         INNER JOIN mission_groupes_access 
                                                    groupesacc17_ 
                                                 ON mission16_.id = 
                                                    groupesacc17_.mission_id 
                                         INNER JOIN groupes groupe18_ 
                                                 ON 
                                         groupesacc17_.groupes_access_id = 
                                         groupe18_.id 
                                         INNER JOIN users users19_ 
                                                 ON groupe18_.id = 
                                                    users19_.groupe_id 
                                         INNER JOIN user_ref userref20_ 
                                                 ON users19_.user_ref_id = 
                                                    userref20_.id 
                                  WHERE  Lower(userref20_.departement) = 
                                         'test@test.com') ) 

这是多余的联接:

INNER JOIN user_ref userref1_ 
               ON user0_.user_ref_id = userref1_.id 
       INNER JOIN user_ref userref2_ 
               ON user0_.user_ref_id = userref2_.id 
       INNER JOIN user_ref userref3_ 
               ON user0_.user_ref_id = userref3_.id 
       INNER JOIN groupes groupe4_ 
               ON user0_.groupe_id = groupe4_.id 
       INNER JOIN mission missions5_ 
               ON groupe4_.id = missions5_.client_entity_id 
       INNER JOIN groupes groupe6_ 
               ON user0_.groupe_id = groupe6_.id 
       INNER JOIN mission missions7_ 
               ON groupe6_.id = missions7_.client_entity_id 
       INNER JOIN groupes groupe8_ 
               ON user0_.groupe_id = groupe8_.id 
       INNER JOIN mission missions9_ 
               ON groupe8_.id = missions9_.client_entity_id 

可以替换为:

INNER JOIN user_ref userref1_ 
               ON user0_.user_ref_id = userref1_.id 
       INNER JOIN groupes groupe4_ 
               ON user0_.groupe_id = groupe4_.id 
       INNER JOIN mission missions5_ 
               ON groupe4_.id = missions5_.client_entity_id 

这使得执行时间快得多,我认为代码中的请求已得到优化,而且我不知道为什么生成的查询看起来像这样,有人可以解释吗。

1 个答案:

答案 0 :(得分:2)

尝试重用路径,例如

Path<?> path = root.join("mission").get("id"));
query.where(cb.and(
    cb.or(
        cb.equal(cb.lower(cb.trim(root.get("createdBy"))), authUserMail.toLowerCase().trim()),
        cb.in(path).value(usersAccessSubquery),
        cb.in(path).value(groupesAccessSubquery),
        cb.in(path).value(groupesAccessSubqueryAdmin)
    ),