Browse Source

AMBARI-25632: Verify custom queries with "IN" clause for ORA-01795 issue (#3585)

Zhiguo Wu 3 years ago
parent
commit
1ccc503865

+ 0 - 20
ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java

@@ -2480,16 +2480,6 @@ public class Configuration {
   public static final ConfigurationProperty<Integer> METRIC_RETRIEVAL_SERVICE_REQUEST_TTL = new ConfigurationProperty<>(
       "metrics.retrieval-service.request.ttl", 5);
 
-  /**
-   * The number of tasks that can be queried from the database at once In the
-   * case of more tasks, multiple queries are issued
-   *
-   * @return
-   */
-  @Markdown(description = "The maximum number of tasks which can be queried by ID from the database.")
-  public static final ConfigurationProperty<Integer> TASK_ID_LIST_LIMIT = new ConfigurationProperty<>(
-      "task.query.parameterlist.size", 999);
-
   /**
    * Indicates whether the current ambari server instance is the active instance.
    * If this property is missing, the value will be considered to be true.
@@ -5546,16 +5536,6 @@ public class Configuration {
     return Boolean.parseBoolean(getProperty(METRIC_RETRIEVAL_SERVICE_REQUEST_TTL_ENABLED));
   }
 
-  /**
-   * Returns the number of tasks that can be queried from the database at once
-   * In the case of more tasks, multiple queries are issued
-   *
-   * @return
-   */
-  public int getTaskIdListLimit() {
-    return Integer.parseInt(getProperty(TASK_ID_LIST_LIMIT));
-  }
-
   /**
    * Get whether the current ambari server instance the active instance
    *

+ 15 - 7
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/GroupDAO.java

@@ -17,8 +17,8 @@
  */
 package org.apache.ambari.server.orm.dao;
 
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -30,8 +30,11 @@ import javax.persistence.TypedQuery;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.GroupEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
+import org.apache.ambari.server.orm.helpers.SQLConstants;
+import org.apache.ambari.server.orm.helpers.SQLOperations;
 import org.apache.ambari.server.security.authorization.GroupType;
 
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -89,12 +92,17 @@ public class GroupDAO {
    */
   @RequiresSession
   public List<GroupEntity> findGroupsByPrincipal(List<PrincipalEntity> principalList) {
-    if (principalList == null || principalList.isEmpty()) {
-      return Collections.emptyList();
-    }
-    TypedQuery<GroupEntity> query = entityManagerProvider.get().createQuery("SELECT grp FROM GroupEntity grp WHERE grp.principal IN :principalList", GroupEntity.class);
-    query.setParameter("principalList", principalList);
-    return daoUtils.selectList(query);
+    TypedQuery<GroupEntity> query = entityManagerProvider.get().createQuery(
+        "SELECT grp FROM GroupEntity grp WHERE grp.principal IN :principalList", GroupEntity.class);
+
+    List<GroupEntity> result = new ArrayList<>();
+    SQLOperations.batch(principalList, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      query.setParameter("principalList", chunk);
+      result.addAll(daoUtils.selectList(query));
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   /**

+ 0 - 5
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java

@@ -20,7 +20,6 @@ package org.apache.ambari.server.orm.dao;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -32,7 +31,6 @@ import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.helpers.SQLConstants;
 import org.apache.ambari.server.orm.helpers.SQLOperations;
-import org.apache.commons.collections.CollectionUtils;
 
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
@@ -130,9 +128,6 @@ public class HostComponentDesiredStateDAO {
 
   @RequiresSession
   public List<HostComponentDesiredStateEntity> findByHostsAndCluster(Collection<Long> hostIds, Long clusterId) {
-    if (CollectionUtils.isEmpty(hostIds)) {
-      return Collections.<HostComponentDesiredStateEntity>emptyList();
-    }
     final EntityManager entityManager = entityManagerProvider.get();
     final TypedQuery<HostComponentDesiredStateEntity> query = entityManager.
         createNamedQuery("HostComponentDesiredStateEntity.findByHostsAndCluster", HostComponentDesiredStateEntity.class);

+ 79 - 27
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostRoleCommandDAO.java

@@ -29,6 +29,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReadWriteLock;
+import java.util.stream.Collectors;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
@@ -62,6 +63,9 @@ import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
 import org.apache.ambari.server.orm.entities.HostRoleCommandEntity_;
 import org.apache.ambari.server.orm.entities.StageEntity;
+import org.apache.ambari.server.orm.helpers.SQLConstants;
+import org.apache.ambari.server.orm.helpers.SQLOperations;
+import org.apache.commons.collections.CollectionUtils;
 import org.eclipse.persistence.config.HintValues;
 import org.eclipse.persistence.config.QueryHints;
 import org.slf4j.Logger;
@@ -289,27 +293,48 @@ public class HostRoleCommandDAO {
 
   @RequiresSession
   public List<HostRoleCommandEntity> findByPKs(Collection<Long> taskIds) {
-    if (taskIds == null || taskIds.isEmpty()) {
-      return Collections.emptyList();
-    }
-
     TypedQuery<HostRoleCommandEntity> query = entityManagerProvider.get().createQuery(
       "SELECT task FROM HostRoleCommandEntity task WHERE task.taskId IN ?1 " +
         "ORDER BY task.taskId",
       HostRoleCommandEntity.class);
 
-    if (taskIds.size() > configuration.getTaskIdListLimit()) {
-      List<HostRoleCommandEntity> result = new ArrayList<>();
-
-      List<List<Long>> lists = Lists.partition(new ArrayList<>(taskIds), configuration.getTaskIdListLimit());
-      for (List<Long> list : lists) {
-        result.addAll(daoUtils.selectList(query, list));
-      }
+    List<HostRoleCommandEntity> result = new ArrayList<>();
+    SQLOperations.batch(taskIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      result.addAll(daoUtils.selectList(query, chunk));
+      return 0;
+    });
 
-      return result;
-    }
+    return Lists.newArrayList(result);
+  }
 
-    return daoUtils.selectList(query, taskIds);
+  /**
+   * Retrieves minimal host role command columns which are required to calculate stare state.
+   * @param taskIds collection of host role commands to process.
+   * @return minimized host role command entities.
+   */
+  @RequiresSession
+  public List<HostRoleCommandEntity> findStatusRolesByPKs(Collection<Long> taskIds) {
+    TypedQuery<Object[]> query = entityManagerProvider.get().createQuery(
+      "SELECT task.taskId, task.status, task.role FROM HostRoleCommandEntity task WHERE task.taskId IN ?1 " +
+        "ORDER BY task.taskId",
+        Object[].class);
+
+    List<HostRoleCommandEntity> result = new ArrayList<>();
+    SQLOperations.batch(taskIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      List<Object[]> queryResult = daoUtils.selectList(query, chunk);
+      result.addAll(queryResult.stream().map(
+          o -> {
+            HostRoleCommandEntity e = new HostRoleCommandEntity();
+            e.setTaskId((Long) o[0]);
+            e.setStatus(HostRoleStatus.valueOf(o[1].toString()));
+            e.setRole(Role.valueOf(o[2].toString()));
+            return e;
+          }).collect(Collectors.toList()));
+
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   @RequiresSession
@@ -328,7 +353,14 @@ public class HostRoleCommandDAO {
         "SELECT task FROM HostRoleCommandEntity task " +
             "WHERE task.requestId IN ?1 " +
             "ORDER BY task.taskId", HostRoleCommandEntity.class);
-    return daoUtils.selectList(query, requestIds);
+
+    List<HostRoleCommandEntity> result = new ArrayList<>();
+    SQLOperations.batch(requestIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      result.addAll(daoUtils.selectList(query, chunk));
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   @RequiresSession
@@ -347,38 +379,58 @@ public class HostRoleCommandDAO {
         "SELECT task.taskId FROM HostRoleCommandEntity task " +
             "WHERE task.requestId IN ?1 " +
             "ORDER BY task.taskId", Long.class);
-    return daoUtils.selectList(query, requestIds);
+
+    List<Long> result = new ArrayList<>();
+    SQLOperations.batch(requestIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      result.addAll(daoUtils.selectList(query, chunk));
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   @RequiresSession
   public List<HostRoleCommandEntity> findByRequestAndTaskIds(Collection<Long> requestIds, Collection<Long> taskIds) {
+    if (CollectionUtils.isEmpty(requestIds) || CollectionUtils.isEmpty(taskIds)) {
+      return Collections.<HostRoleCommandEntity>emptyList();
+    }
+
     TypedQuery<HostRoleCommandEntity> query = entityManagerProvider.get().createQuery(
         "SELECT DISTINCT task FROM HostRoleCommandEntity task " +
             "WHERE task.requestId IN ?1 AND task.taskId IN ?2 " +
             "ORDER BY task.taskId", HostRoleCommandEntity.class
     );
-    return daoUtils.selectList(query, requestIds, taskIds);
+
+    return runQueryForVastRequestsAndTaskIds(query, requestIds, taskIds);
   }
 
   @RequiresSession
   public List<Long> findTaskIdsByRequestAndTaskIds(Collection<Long> requestIds, Collection<Long> taskIds) {
+    if (CollectionUtils.isEmpty(requestIds) || CollectionUtils.isEmpty(taskIds)) {
+      return Collections.<Long>emptyList();
+    }
+
     TypedQuery<Long> query = entityManagerProvider.get().createQuery(
         "SELECT DISTINCT task.taskId FROM HostRoleCommandEntity task " +
             "WHERE task.requestId IN ?1 AND task.taskId IN ?2 " +
             "ORDER BY task.taskId", Long.class
     );
 
-    if (taskIds.size() > configuration.getTaskIdListLimit()) {
-      List<Long> result = new ArrayList<>();
-
-      List<List<Long>> lists = Lists.partition(new ArrayList<>(taskIds), configuration.getTaskIdListLimit());
-      for (List<Long> taskIdList : lists) {
-        result.addAll(daoUtils.selectList(query, requestIds, taskIdList));
-      }
+    return runQueryForVastRequestsAndTaskIds(query, requestIds, taskIds);
+  }
 
-      return result;
-    }
-    return daoUtils.selectList(query, requestIds, taskIds);
+  private <T> List<T> runQueryForVastRequestsAndTaskIds(TypedQuery<T> query, Collection<Long> requestIds, Collection<Long> taskIds) {
+    final int batchSize = SQLConstants.IN_ARGUMENT_MAX_SIZE;
+    final List<T> result = new ArrayList<>();
+    SQLOperations.batch(taskIds, batchSize, (taskChunk, currentTaskBatch, totalTaskBatches, totalTaskSize) -> {
+      SQLOperations.batch(requestIds, batchSize, (requestChunk, currentRequestBatch, totalRequestBatches, totalRequestSize) -> {
+        result.addAll(daoUtils.selectList(query, requestChunk, taskChunk));
+        return 0;
+      });
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   @RequiresSession

+ 13 - 10
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java

@@ -227,17 +227,20 @@ public class KerberosKeytabPrincipalDAO {
         }
       }
 
-      Predicate hostIDPredicate = (hostIds.isEmpty()) ? null : root.get("hostId").in(hostIds);
-      Predicate hostNullIDPredicate = (hasNull) ? root.get("hostId").isNull() : null;
+      //split hostIDs into batches and combine them using OR
+      if (CollectionUtils.isNotEmpty(hostIds)) {
+        List<Predicate> hostPredicates = new ArrayList<>();
+        SQLOperations.batch(hostIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+          hostPredicates.add(root.get("hostId").in(chunk));
+          return 0;
+        });
 
-      if (hostIDPredicate != null) {
-        if (hostNullIDPredicate != null) {
-          predicates.add(cb.or(hostIDPredicate, hostNullIDPredicate));
-        } else {
-          predicates.add(hostIDPredicate);
-        }
-      } else if (hostNullIDPredicate != null) {
-        predicates.add(hostNullIDPredicate);
+        Predicate hostCombinedPredicate = cb.or(hostPredicates.toArray(new Predicate[hostPredicates.size()]));
+        predicates.add(hostCombinedPredicate);
+      }
+
+      if (hasNull) {
+        predicates.add(root.get("hostId").isNull());
       }
     }
 

+ 12 - 6
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PermissionDAO.java

@@ -18,7 +18,7 @@
 
 package org.apache.ambari.server.orm.dao;
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -28,7 +28,10 @@ import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
+import org.apache.ambari.server.orm.helpers.SQLConstants;
+import org.apache.ambari.server.orm.helpers.SQLOperations;
 
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -104,12 +107,15 @@ public class PermissionDAO {
    */
   @RequiresSession
   public List<PermissionEntity> findPermissionsByPrincipal(List<PrincipalEntity> principalList) {
-    if (principalList == null || principalList.isEmpty()) {
-      return Collections.emptyList();
-    }
     TypedQuery<PermissionEntity> query = entityManagerProvider.get().createNamedQuery("PermissionEntity.findByPrincipals", PermissionEntity.class);
-    query.setParameter("principalList", principalList);
-    return daoUtils.selectList(query);
+
+    List<PermissionEntity> result = new ArrayList<>();
+    SQLOperations.batch(principalList, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      query.setParameter("principalList", chunk);
+      result.addAll(daoUtils.selectList(query));
+      return 0;
+    });
+    return Lists.newArrayList(result);
   }
 
   /**

+ 15 - 7
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/PrivilegeDAO.java

@@ -18,7 +18,7 @@
 
 package org.apache.ambari.server.orm.dao;
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -29,7 +29,10 @@ import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
+import org.apache.ambari.server.orm.helpers.SQLConstants;
+import org.apache.ambari.server.orm.helpers.SQLOperations;
 
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -127,12 +130,17 @@ public class PrivilegeDAO {
    */
   @RequiresSession
   public List<PrivilegeEntity> findAllByPrincipal(List<PrincipalEntity> principalList) {
-    if (principalList == null || principalList.isEmpty()) {
-      return Collections.emptyList();
-    }
-    TypedQuery<PrivilegeEntity> query = entityManagerProvider.get().createQuery("SELECT privilege FROM PrivilegeEntity privilege WHERE privilege.principal IN :principalList", PrivilegeEntity.class);
-    query.setParameter("principalList", principalList);
-    return daoUtils.selectList(query);
+    TypedQuery<PrivilegeEntity> query = entityManagerProvider.get().createQuery(
+        "SELECT privilege FROM PrivilegeEntity privilege WHERE privilege.principal IN :principalList", PrivilegeEntity.class);
+
+    List<PrivilegeEntity> result = new ArrayList<>();
+    SQLOperations.batch(principalList, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      query.setParameter("principalList", chunk);
+      result.addAll(daoUtils.selectList(query));
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   /**

+ 12 - 8
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RequestDAO.java

@@ -19,8 +19,8 @@
 package org.apache.ambari.server.orm.dao;
 
 import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -48,11 +48,13 @@ import org.apache.ambari.server.orm.entities.TopologyLogicalTaskEntity;
 import org.apache.ambari.server.orm.helpers.SQLConstants;
 import org.apache.ambari.server.orm.helpers.SQLOperations;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.commons.collections.CollectionUtils;
 import org.eclipse.persistence.config.HintValues;
 import org.eclipse.persistence.config.QueryHints;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -122,10 +124,6 @@ public class RequestDAO implements Cleanable {
    */
   @RequiresSession
   public List<RequestEntity> findByPks(Collection<Long> requestIds, boolean refreshHint) {
-    if (null == requestIds || 0 == requestIds.size()) {
-      return Collections.emptyList();
-    }
-
     TypedQuery<RequestEntity> query = entityManagerProvider.get().createQuery("SELECT request FROM RequestEntity request " +
         "WHERE request.requestId IN ?1", RequestEntity.class);
 
@@ -135,7 +133,13 @@ public class RequestDAO implements Cleanable {
       query.setHint(QueryHints.REFRESH, HintValues.TRUE);
     }
 
-    return daoUtils.selectList(query, requestIds);
+    List<RequestEntity> result = new ArrayList<>();
+    SQLOperations.batch(requestIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      result.addAll(daoUtils.selectList(query, chunk));
+      return 0;
+    });
+
+    return Lists.newArrayList(result);
   }
 
   @RequiresSession
@@ -309,7 +313,7 @@ public class RequestDAO implements Cleanable {
                                   String entityQuery, Class<T> type) {
     LOG.info(String.format("Purging %s entity records before date %s", entityName, new Date(beforeDateMillis)));
 
-    if (ids == null || ids.isEmpty()) {
+    if (CollectionUtils.isEmpty(ids)) {
       return 0;
     }
 
@@ -342,7 +346,7 @@ public class RequestDAO implements Cleanable {
                                   String entityQuery, Class<T> type) {
     LOG.info(String.format("Purging %s entity records before date %s", entityName, new Date(beforeDateMillis)));
 
-    if (ids == null || ids.isEmpty()) {
+    if (CollectionUtils.isEmpty(ids)) {
       return 0;
     }
 

+ 13 - 6
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/StageDAO.java

@@ -44,7 +44,10 @@ import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
 import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.orm.entities.StageEntityPK;
 import org.apache.ambari.server.orm.entities.StageEntity_;
+import org.apache.ambari.server.orm.helpers.SQLConstants;
+import org.apache.ambari.server.orm.helpers.SQLOperations;
 import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.collections.CollectionUtils;
 import org.eclipse.persistence.config.HintValues;
 import org.eclipse.persistence.config.QueryHints;
 
@@ -173,16 +176,20 @@ public class StageDAO {
   @RequiresSession
   public Map<Long, String> findRequestContext(List<Long> requestIds) {
     Map<Long, String> resultMap = new HashMap<>();
-    if (requestIds != null && !requestIds.isEmpty()) {
+    if (CollectionUtils.isNotEmpty(requestIds)) {
       TypedQuery<StageEntity> query = entityManagerProvider.get()
         .createQuery("SELECT stage FROM StageEntity stage WHERE " +
           "stage.requestId IN (SELECT DISTINCT s.requestId FROM StageEntity s " +
           "WHERE s.requestId IN ?1)", StageEntity.class);
-      List<StageEntity> result = daoUtils.selectList(query, requestIds);
-      if (result != null && !result.isEmpty()) {
-        for (StageEntity entity : result) {
-          resultMap.put(entity.getRequestId(), entity.getRequestContext());
-        }
+
+      List<StageEntity> result = new ArrayList<>();
+      SQLOperations.batch(requestIds, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+        result.addAll(daoUtils.selectList(query, chunk));
+        return 0;
+      });
+
+      for (StageEntity entity : result) {
+        resultMap.put(entity.getRequestId(), entity.getRequestContext());
       }
     }
     return resultMap;

+ 14 - 6
ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UserDAO.java

@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.orm.dao;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -29,7 +30,10 @@ import javax.persistence.TypedQuery;
 import org.apache.ambari.server.orm.RequiresSession;
 import org.apache.ambari.server.orm.entities.PrincipalEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.orm.helpers.SQLConstants;
+import org.apache.ambari.server.orm.helpers.SQLOperations;
 
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -73,12 +77,16 @@ public class UserDAO {
    */
   @RequiresSession
   public List<UserEntity> findUsersByPrincipal(List<PrincipalEntity> principalList) {
-    if (principalList == null || principalList.isEmpty()) {
-      return Collections.emptyList();
-    }
-    TypedQuery<UserEntity> query = entityManagerProvider.get().createQuery("SELECT user_entity FROM UserEntity user_entity WHERE user_entity.principal IN :principalList", UserEntity.class);
-    query.setParameter("principalList", principalList);
-    return daoUtils.selectList(query);
+    TypedQuery<UserEntity> query = entityManagerProvider.get().createQuery(
+        "SELECT user_entity FROM UserEntity user_entity WHERE user_entity.principal IN :principalList", UserEntity.class);
+
+    List<UserEntity> result = new ArrayList<>();
+    SQLOperations.batch(principalList, SQLConstants.IN_ARGUMENT_MAX_SIZE, (chunk, currentBatch, totalBatches, totalSize) -> {
+      query.setParameter("principalList", chunk);
+      result.addAll(daoUtils.selectList(query));
+      return 0;
+    });
+    return Lists.newArrayList(result);
   }
 
   /**