diff --git a/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php b/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php
index edb39afc6..e8f9801cc 100644
--- a/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php
+++ b/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php
@@ -66,7 +66,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
         $sql         = $this->getSQLTableAlias($class->name, $tableAlias) . '.'
                             . $this->quoteStrategy->getColumnName($field, $class, $this->platform);
 
-        $this->rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
+        $this->cachedPersisterContexts['noLimits']->rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
 
         if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
             $type   = Type::getType($class->getTypeOfField($field));
@@ -88,7 +88,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
     {
         $columnAlias = $this->getSQLColumnAlias($joinColumnName);
 
-        $this->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type);
+        $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type);
 
         return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
     }
diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php
index c53e817c1..303825811 100644
--- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php
+++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php
@@ -134,15 +134,6 @@ class BasicEntityPersister implements EntityPersister
      */
     protected $queuedInserts = array();
 
-    /**
-     * ResultSetMapping that is used for all queries. Is generated lazily once per request.
-     *
-     * TODO: Evaluate Caching in combination with the other cached SQL snippets.
-     *
-     * @var Query\ResultSetMapping
-     */
-    protected $rsm;
-
     /**
      * The map of column names to DBAL mapping types of all prepared columns used
      * when INSERTing or UPDATEing an entity.
@@ -216,6 +207,11 @@ class BasicEntityPersister implements EntityPersister
      */
     private $identifierFlattener;
 
+    /**
+     * @var CachedPersisterContext[]
+     */
+    protected $cachedPersisterContexts = [];
+
     /**
      * Initializes a new <tt>BasicEntityPersister</tt> that uses the given EntityManager
      * and persists instances of the class described by the given ClassMetadata descriptor.
@@ -231,6 +227,10 @@ class BasicEntityPersister implements EntityPersister
         $this->platform            = $this->conn->getDatabasePlatform();
         $this->quoteStrategy       = $em->getConfiguration()->getQuoteStrategy();
         $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory());
+        $this->cachedPersisterContexts['noLimits'] = new CachedPersisterContext(
+            $class,
+            new Query\ResultSetMapping()
+        );
     }
 
     /**
@@ -246,7 +246,7 @@ class BasicEntityPersister implements EntityPersister
      */
     public function getResultSetMapping()
     {
-        return $this->rsm;
+        return $this->cachedPersisterContexts['noLimits']->rsm;
     }
 
     /**
@@ -720,7 +720,7 @@ class BasicEntityPersister implements EntityPersister
         }
 
         $hydrator = $this->em->newHydrator($this->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
-        $entities = $hydrator->hydrateAll($stmt, $this->rsm, $hints);
+        $entities = $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, $hints);
 
         return $entities ? $entities[0] : null;
     }
@@ -809,7 +809,7 @@ class BasicEntityPersister implements EntityPersister
         $stmt = $this->conn->executeQuery($sql, $params, $types);
 
         $hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT);
-        $hydrator->hydrateAll($stmt, $this->rsm, array(Query::HINT_REFRESH => true));
+        $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(Query::HINT_REFRESH => true));
     }
 
     /**
@@ -841,7 +841,7 @@ class BasicEntityPersister implements EntityPersister
         $stmt       = $this->conn->executeQuery($query, $params, $types);
         $hydrator   = $this->em->newHydrator(($this->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
 
-        return $hydrator->hydrateAll($stmt, $this->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
+        return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
     }
 
     /**
@@ -886,7 +886,7 @@ class BasicEntityPersister implements EntityPersister
 
         $hydrator = $this->em->newHydrator(($this->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
 
-        return $hydrator->hydrateAll($stmt, $this->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
+        return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true));
     }
 
     /**
@@ -909,11 +909,11 @@ class BasicEntityPersister implements EntityPersister
      */
     private function loadArrayFromStatement($assoc, $stmt)
     {
-        $rsm    = $this->rsm;
+        $rsm    = $this->cachedPersisterContexts['noLimits']->rsm;
         $hints  = array(UnitOfWork::HINT_DEFEREAGERLOAD => true);
 
         if (isset($assoc['indexBy'])) {
-            $rsm = clone ($this->rsm); // this is necessary because the "default rsm" should be changed.
+            $rsm = clone ($this->cachedPersisterContexts['noLimits']->rsm); // this is necessary because the "default rsm" should be changed.
             $rsm->addIndexBy('r', $assoc['indexBy']);
         }
 
@@ -931,14 +931,14 @@ class BasicEntityPersister implements EntityPersister
      */
     private function loadCollectionFromStatement($assoc, $stmt, $coll)
     {
-        $rsm   = $this->rsm;
+        $rsm   = $this->cachedPersisterContexts['noLimits']->rsm;
         $hints = array(
             UnitOfWork::HINT_DEFEREAGERLOAD => true,
             'collection' => $coll
         );
 
         if (isset($assoc['indexBy'])) {
-            $rsm = clone ($this->rsm); // this is necessary because the "default rsm" should be changed.
+            $rsm = clone ($this->cachedPersisterContexts['noLimits']->rsm); // this is necessary because the "default rsm" should be changed.
             $rsm->addIndexBy('r', $assoc['indexBy']);
         }
 
@@ -1062,7 +1062,7 @@ class BasicEntityPersister implements EntityPersister
                 break;
         }
 
-        $columnList = $this->getSelectColumnsSQL();
+        $columnList = $this->getSelectColumnsSQL(null !== $limit);
         $tableAlias = $this->getSQLTableAlias($this->class->name);
         $filterSql  = $this->generateFilterConditionSQL($this->class, $tableAlias);
         $tableName  = $this->quoteStrategy->getTableName($this->class, $this->platform);
@@ -1180,17 +1180,19 @@ class BasicEntityPersister implements EntityPersister
      * the resulting SQL fragment is generated only once and cached in {@link selectColumnListSql}.
      * Subclasses may or may not do the same.
      *
+     * @param bool $hasLimitClause
+     *
      * @return string The SQL fragment.
      */
-    protected function getSelectColumnsSQL()
+    protected function getSelectColumnsSQL(/*$hasLimitClause = false*/)
     {
+        //if ( ! $hasLimitClause && $this->selectColumnListSql !== null) {
         if ($this->selectColumnListSql !== null) {
             return $this->selectColumnListSql;
         }
 
         $columnList = array();
-        $this->rsm  = new Query\ResultSetMapping();
-        $this->rsm->addEntityResult($this->class->name, 'r'); // r for root
+        $this->cachedPersisterContexts['noLimits']->rsm->addEntityResult($this->class->name, 'r'); // r for root
 
         // Add regular columns to select list
         foreach ($this->class->fieldNames as $field) {
@@ -1210,6 +1212,7 @@ class BasicEntityPersister implements EntityPersister
             $isAssocToOneInverseSide = $assoc['type'] & ClassMetadata::TO_ONE && ! $assoc['isOwningSide'];
             $isAssocFromOneEager     = $assoc['type'] !== ClassMetadata::MANY_TO_MANY && $assoc['fetch'] === ClassMetadata::FETCH_EAGER;
 
+            //if ($hasLimitClause || ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) {
             if ( ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) {
                 continue;
             }
@@ -1221,7 +1224,7 @@ class BasicEntityPersister implements EntityPersister
             }
 
             $assocAlias = 'e' . ($eagerAliasCounter++);
-            $this->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField);
+            $this->cachedPersisterContexts['noLimits']->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField);
 
             foreach ($eagerEntity->fieldNames as $field) {
                 $columnList[] = $this->getSelectColumnSQL($field, $eagerEntity, $assocAlias);
@@ -1241,7 +1244,7 @@ class BasicEntityPersister implements EntityPersister
             $joinCondition  = array();
 
             if (isset($assoc['indexBy'])) {
-                $this->rsm->addIndexBy($assocAlias, $assoc['indexBy']);
+                $this->cachedPersisterContexts['noLimits']->rsm->addIndexBy($assocAlias, $assoc['indexBy']);
             }
 
             if ( ! $assoc['isOwningSide']) {
@@ -1318,7 +1321,7 @@ class BasicEntityPersister implements EntityPersister
                                 . '.' . $quotedColumn . ' AS ' . $resultColumnName;
             $type             = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em);
 
-            $this->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type);
+            $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type);
         }
 
         return implode(', ', $columnList);
@@ -1456,7 +1459,7 @@ class BasicEntityPersister implements EntityPersister
         $sql            = $tableAlias . '.' . $columnName;
         $columnAlias    = $this->getSQLColumnAlias($class->columnNames[$field]);
 
-        $this->rsm->addFieldResult($alias, $columnAlias, $field);
+        $this->cachedPersisterContexts['noLimits']->rsm->addFieldResult($alias, $columnAlias, $field);
 
         if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
             $type   = Type::getType($class->getTypeOfField($field));
diff --git a/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php
new file mode 100644
index 000000000..a148a54dd
--- /dev/null
+++ b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php
@@ -0,0 +1,121 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\ORM\Persisters\Entity;
+use Doctrine\Common\Persistence\Mapping\ClassMetadata;
+use Doctrine\ORM\Query\ResultSetMapping;
+
+/**
+ * A swappable persister context to use as a container for the current
+ * generated query/resultSetMapping/type binding information.
+ *
+ * This class is a utility class to be used only by the persister API
+ *
+ * This object is highly mutable due to performance reasons. Same reasoning
+ * behind its properties being public.
+ *
+ * @author Marco Pivetta <ocramius@gmail.com>
+ */
+class CachedPersisterContext
+{
+    /**
+     * Metadata object that describes the mapping of the mapped entity class.
+     *
+     * @var \Doctrine\ORM\Mapping\ClassMetadata
+     */
+    public $class;
+
+    /**
+     * ResultSetMapping that is used for all queries. Is generated lazily once per request.
+     *
+     * @var \Doctrine\ORM\Query\ResultSetMapping
+     */
+    public $rsm;
+
+    /**
+     * The map of column names to DBAL mapping types of all prepared columns used
+     * when INSERTing or UPDATEing an entity.
+     *
+     * @var array
+     *
+     * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareInsertData($entity)
+     * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareUpdateData($entity)
+     */
+    public $columnTypes = array();
+
+    /**
+     * The map of quoted column names.
+     *
+     * @var array
+     *
+     * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareInsertData($entity)
+     * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareUpdateData($entity)
+     */
+    public $quotedColumns = array();
+
+    /**
+     * The INSERT SQL statement used for entities handled by this persister.
+     * This SQL is only generated once per request, if at all.
+     *
+     * @var string
+     */
+    public $insertSql = '';
+
+    /**
+     * The SELECT column list SQL fragment used for querying entities by this persister.
+     * This SQL fragment is only generated once per request, if at all.
+     *
+     * @var string
+     */
+    public $selectColumnListSql;
+
+    /**
+     * The JOIN SQL fragment used to eagerly load all many-to-one and one-to-one
+     * associations configured as FETCH_EAGER, as well as all inverse one-to-one associations.
+     *
+     * @var string
+     */
+    public $selectJoinSql;
+
+    /**
+     * Counter for creating unique SQL table and column aliases.
+     *
+     * @var integer
+     */
+    public $sqlAliasCounter = 0;
+
+    /**
+     * Map from class names (FQCN) to the corresponding generated SQL table aliases.
+     *
+     * @var array
+     */
+    public $sqlTableAliases = array();
+
+    /**
+     * @param ClassMetadata    $class
+     * @param ResultSetMapping $rsm
+     */
+    public function __construct(
+        ClassMetadata $class,
+        ResultSetMapping $rsm
+    ) {
+        $this->class = $class;
+        $this->rsm   = $rsm;
+    }
+}
diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php
index 019d987d5..3ec9afc30 100644
--- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php
+++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php
@@ -425,14 +425,14 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
         }
 
         $columnList         = array();
-        $this->rsm          = new ResultSetMapping();
+        //$this->cachedPersisterContexts['noLimits']->rsm          = new ResultSetMapping();
         $discrColumn        = $this->class->discriminatorColumn['name'];
         $baseTableAlias     = $this->getSQLTableAlias($this->class->name);
         $resultColumnName   = $this->platform->getSQLResultCasing($discrColumn);
 
-        $this->rsm->addEntityResult($this->class->name, 'r');
-        $this->rsm->setDiscriminatorColumn('r', $resultColumnName);
-        $this->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
+        $this->cachedPersisterContexts['noLimits']->rsm->addEntityResult($this->class->name, 'r');
+        $this->cachedPersisterContexts['noLimits']->rsm->setDiscriminatorColumn('r', $resultColumnName);
+        $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
 
         // Add regular columns
         foreach ($this->class->fieldMappings as $fieldName => $mapping) {
diff --git a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php
index 23ebdf2d2..b93c2afc9 100644
--- a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php
+++ b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php
@@ -63,8 +63,8 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
 
         $resultColumnName = $this->platform->getSQLResultCasing($discrColumn);
 
-        $this->rsm->setDiscriminatorColumn('r', $resultColumnName);
-        $this->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
+        $this->cachedPersisterContexts['noLimits']->rsm->setDiscriminatorColumn('r', $resultColumnName);
+        $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
 
         // Append subclass columns
         foreach ($this->class->subClasses as $subClassName) {