diff --git a/src/main/java/org/caosdb/server/query/Query.java b/src/main/java/org/caosdb/server/query/Query.java
index 07a165a352ba9a07a345018e7d287cd961f4a00b..2697b77c316defc085a95be664e5d77f597f2824 100644
--- a/src/main/java/org/caosdb/server/query/Query.java
+++ b/src/main/java/org/caosdb/server/query/Query.java
@@ -33,9 +33,9 @@ import java.sql.Statement;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -694,8 +694,6 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
       this.cached = true;
     }
 
-    this.resultSet = filterEntitiesWithoutRetrievePermission(this.resultSet);
-
     // Fill resulting entities into container
     if (this.container != null && this.type == Type.FIND) {
       for (final IdVersionPair p : this.resultSet) {
@@ -749,7 +747,10 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
 
   protected void executeNoCache(final Access access) {
     try {
-      this.resultSet = getResultSet(executeStrategy(this.versioned), this.versioned);
+      final String tabname = executeStrategy(this.versioned);
+      filterEntitiesWithoutRetrievePermission(tabname);
+
+      this.resultSet = getResultSet(tabname, this.versioned);
     } finally {
       cleanUp();
     }
@@ -793,66 +794,61 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
    * @throws SQLException
    * @throws TransactionException
    */
-  public void filterEntitiesWithoutRetrievePermission(final String resultSet)
-      throws SQLException, TransactionException {
+  public void filterEntitiesWithoutRetrievePermission(final String resultSet) {
     if (!filterEntitiesWithoutRetrievePermisions) {
       return;
     }
     cachable = false;
-    try (final Statement stmt = this.getConnection().createStatement()) {
-      final ResultSet rs = stmt.executeQuery("SELECT id from `" + resultSet + "`");
-      final List<Integer> toBeDeleted = new LinkedList<Integer>();
-      while (rs.next()) {
-        final long t1 = System.currentTimeMillis();
-        final Integer id = rs.getInt("id");
-        if (id > 99
-            && !execute(new RetrieveSparseEntity(id, null), this.getAccess())
-                .getEntity()
-                .getEntityACL()
-                .isPermitted(this.getUser(), EntityPermission.RETRIEVE_ENTITY)) {
-          toBeDeleted.add(id);
-        }
-        final long t2 = System.currentTimeMillis();
-        this.addBenchmark("filterEntitiesWithoutRetrievePermission", t2 - t1);
-      }
-      rs.close();
-      for (final Integer id : toBeDeleted) {
-        stmt.execute("DELETE FROM `" + resultSet + "` WHERE id = " + id);
+
+    /*
+      * The following creates a table with the columns (entity ID, acl) from
+      * a given table with entity IDs. Here, acl is the string representation
+      * of the acl.
+      *
+      * TODO:In future, one might want to retrieve only a distinct set of acl
+      * with (acl_id, acl) and a table with (entity_id, acl_id) to reduce the
+      * amount of data being transfered.
+      */
+    final Statement stmt = this.getConnection().createStatement()
+    final String query =
+        ("SELECT entity_n_acl.id, entity_acl.acl from "
+          + "(select entities.id, entities.acl from entities "
+          + "inner join `" + resultSet + " as rs on entities.id=rs.id`) "
+          + "as entity_n_acl "
+          + "left join entity_acl on entity_n_acl.acl=entity_acl.id;");
+    final ResultSet entities_with_acl = stmt.executeQuery(query);
+
+    final HashMap<String, Boolean> acl_cache = new HashMap<String, Boolean>();
+    final List<Integer> toBeDeleted = new LinkedList<Integer>();
+
+    // @todo here, we must operate on sql site. only retrieve different permissions
+    while (entities_with_acl.next()) {
+      final long t1 = System.currentTimeMillis();
+      final Integer id = entities_with_acl.getInt("id");
+      if (id <= 99) {
+        continue;
       }
-    }
-  }
 
-  /**
-   * Filter out all entities which may not be retrieved by this user due to a missing RETRIEVE
-   * permission. This one is for the filtering of the final result set and not for the filtering of
-   * any intermediate results.
-   *
-   * @param entities
-   * @throws TransactionException
-   * @return the filtered list.
-   */
-  private List<IdVersionPair> filterEntitiesWithoutRetrievePermission(
-      final List<IdVersionPair> entities) throws TransactionException {
-    if (!filterEntitiesWithoutRetrievePermisions) {
-      return entities;
-    }
+      final String acl_str = bytes2UTF8(entities_with_acl.getBytes("ACL"));
+      if (!acl_cache.containsKey(acl_str)) {
+        acl_cache.put(
+            acl_str,
+            EntityACL.deserialize(acl_str)
+                .isPermitted(this.getUser(), EntityPermission.RETRIEVE_ENTITY));
+      }
 
-    final List<IdVersionPair> result = new ArrayList<>();
-    final Iterator<IdVersionPair> iterator = entities.iterator();
-    while (iterator.hasNext()) {
-      final long t1 = System.currentTimeMillis();
-      final IdVersionPair next = iterator.next();
-      if (next.id > 99
-          && execute(new RetrieveSparseEntity(next.id, next.version), getAccess())
-              .getEntity()
-              .getEntityACL()
-              .isPermitted(getUser(), EntityPermission.RETRIEVE_ENTITY)) {
-        result.add(next);
+      if (!acl_cache.get(acl_str)) {
+        toBeDeleted.add(id);
       }
+
       final long t2 = System.currentTimeMillis();
-      addBenchmark("filterEntitiesWithoutRetrievePermission", t2 - t1);
+      this.addBenchmark("filterEntitiesWithoutRetrievePermission", t2 - t1);
+    }
+    entities_with_acl.close();
+    // TODO is there a better way than the following?
+    for (final Integer id : toBeDeleted) {
+      stmt.execute("DELETE FROM `" + resultSet + "` WHERE id = " + id);
     }
-    return result;
   }
 
   @Override