diff --git a/src/EntityUsageTrackBase.php b/src/EntityUsageTrackBase.php
index 8b4b31894198d7447bfd676911392692d9c937e5..2d9167209e5bba3dcd753d5ba3686f27e5b52e24 100644
--- a/src/EntityUsageTrackBase.php
+++ b/src/EntityUsageTrackBase.php
@@ -483,4 +483,32 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra
     return $this->enabledTargetEntityTypes === NULL || in_array($entity_type_id, $this->enabledTargetEntityTypes, TRUE);
   }
 
+  /**
+   * Prepare target entity values to be in the correct format.
+   *
+   * @param string $entityTypeId
+   *   The entity type ID.
+   * @param array $ids
+   *   An array of entity IDs, can be revision or UUIDs as well.
+   * @param string $idField
+   *   The ID field; 'uuid', 'revision' or 'id'.
+   *
+   * @return array
+   *   An array of the corresponding entity IDs from the IDs passed in,
+   *   each prefixed with the string "$entityTypeId|". Non-loadable entities
+   *   will be filtered out.
+   */
+  protected function checkAndPrepareEntityIds(string $entityTypeId, array $ids, string $idField) {
+    if (empty($ids) || !$this->isEntityTypeTracked($entityTypeId)) {
+      return [];
+    }
+    $storage = $this->entityTypeManager->getStorage($entityTypeId);
+    $ids = $storage->getQuery()
+      ->accessCheck(FALSE)
+      ->condition($storage->getEntityType()->getKey($idField), $ids, 'IN')
+      ->execute();
+
+    return array_map(fn ($id) => $entityTypeId . '|' . $id, $ids);
+  }
+
 }
diff --git a/src/EntityUsageTrackInterface.php b/src/EntityUsageTrackInterface.php
index 35eeb61777209b2fc2d627d68fc9bc2f08f37991..b3b4c56cc195c67669361ddfc915c7ceb2a50475 100644
--- a/src/EntityUsageTrackInterface.php
+++ b/src/EntityUsageTrackInterface.php
@@ -15,6 +15,27 @@ use Drupal\Core\Field\FieldItemInterface;
  * - Entities related through an entity_reference field are tracked using the
  *   "entity_reference" method.
  * - Entities embedded into other entities are tracked using the "embed" method.
+ *
+ * Note that plugins extending this interface have to be performant.
+ * Constructing the entity_usage table for large sites can take a long time and
+ * involve millions of calls to ::getTargetEntities(). Best practice is to:
+ * - Use entity queries over entity loading to check existence. For example, use
+ *   the \Drupal\entity_usage\EntityUsageTrackBase::checkAndPrepareEntityIds()
+ *   helper method to do this.
+ * - If the field you are tracking supports multiple entities then check the
+ *   existence for all entities are the same time. For example, use
+ *   the \Drupal\entity_usage\EntityUsageTrackBase::checkAndPrepareEntityIds()
+ *   helper method to do this.
+ * - Before doing any entity queries or entity loading check that the entity
+ *   type is being tracked. The helper method
+ *   \Drupal\entity_usage\EntityUsageTrackBase::isEntityTypeTracked() can do
+ *   this.
+ * - If the plugin can be coded to process multiple cardinality fields
+ *   efficiently, implement
+ *   \Drupal\entity_usage\EntityUsageTrackMultipleLoadInterface to process all
+ *   field values together. See
+ *   \Drupal\entity_usage\Plugin\EntityUsage\Track\EntityReference as an
+ *   example.
  */
 interface EntityUsageTrackInterface extends PluginInspectionInterface {
 
diff --git a/src/Plugin/EntityUsage/Track/DynamicEntityReference.php b/src/Plugin/EntityUsage/Track/DynamicEntityReference.php
index 7f79730ebc564389e40a6283dc624797437e9621..6c8854791450370f5703273bbf919997e0cc96ff 100644
--- a/src/Plugin/EntityUsage/Track/DynamicEntityReference.php
+++ b/src/Plugin/EntityUsage/Track/DynamicEntityReference.php
@@ -3,7 +3,9 @@
 namespace Drupal\entity_usage\Plugin\EntityUsage\Track;
 
 use Drupal\Core\Field\FieldItemInterface;
+use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\entity_usage\EntityUsageTrackBase;
+use Drupal\entity_usage\EntityUsageTrackMultipleLoadInterface;
 
 /**
  * Tracks usage of entities related in dynamic_entity_reference fields.
@@ -15,31 +17,60 @@ use Drupal\entity_usage\EntityUsageTrackBase;
  *   field_types = {"dynamic_entity_reference"},
  * )
  */
-class DynamicEntityReference extends EntityUsageTrackBase {
+class DynamicEntityReference extends EntityUsageTrackBase implements EntityUsageTrackMultipleLoadInterface {
 
   /**
    * {@inheritdoc}
    */
   public function getTargetEntities(FieldItemInterface $item) {
-    /** @var \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem $item */
-    $target_id = $item->get('target_id')->getValue();
-    $target_type_id = $item->get('target_type')->getValue();
-    if (empty($target_id) || empty($target_type_id)) {
-      return [];
+    /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item */
+    return $this->doGetTargetEntities($item->getParent(), $item);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTargetEntitiesFromField(FieldItemListInterface $field): array {
+    return $this->doGetTargetEntities($field);
+  }
+
+  /**
+   * Retrieve the target entity(ies) from a field.
+   *
+   * @param \Drupal\Core\Field\FieldItemListInterface $field
+   *   The field to get the target entity(ies) from.
+   * @param \Drupal\Core\Field\FieldItemInterface|null $field_item
+   *   (optional) The field item to get the target entity(ies) from.
+   *
+   * @return string[]
+   *   An indexed array of strings where each target entity type and ID are
+   *   concatenated with a "|" character. Will return an empty array if no
+   *   target entity could be retrieved from the received field item value.
+   */
+  private function doGetTargetEntities(FieldItemListInterface $field, ?FieldItemInterface $field_item = NULL): array {
+    $entity_ids = [];
+    if ($field_item instanceof FieldItemInterface) {
+      $iterable = [$field_item];
     }
-    // Check if target entity type is enabled, all entity types are enabled by
-    // default.
-    if (!$this->isEntityTypeTracked($target_type_id)) {
-      return [];
+    else {
+      $iterable = &$field;
+    }
+
+    foreach ($iterable as $item) {
+      /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item */
+      $item_value = $item->get('target_id')->getValue();
+      $target_type_id = $item->get('target_type')->getValue();
+
+      if (!empty($item_value)) {
+        $entity_ids[$target_type_id][] = $item_value;
+      }
+    }
+
+    $return = [];
+    foreach ($entity_ids as $target_type_id => $entity_id_values) {
+      $return = array_merge($return, $this->checkAndPrepareEntityIds($target_type_id, $entity_id_values, 'id'));
     }
-    $target_type = $this->entityTypeManager->getDefinition($target_type_id);
-    // Only return a valid result if the target entity exists.
-    $query = $this->entityTypeManager->getStorage($target_type_id)
-      ->getQuery()
-      ->accessCheck(FALSE)
-      ->condition($target_type->getKey('id'), $target_id)
-      ->count();
-    return $query->execute() > 0 ? [$target_type_id . '|' . $target_id] : [];
+    return $return;
   }
 
 }
diff --git a/src/Plugin/EntityUsage/Track/EntityReference.php b/src/Plugin/EntityUsage/Track/EntityReference.php
index 1075f60bcb3c703efb2652d23a51c8043049a537..6b47a3c853299d56359e667e1c6c3f1f5ed2fcfc 100644
--- a/src/Plugin/EntityUsage/Track/EntityReference.php
+++ b/src/Plugin/EntityUsage/Track/EntityReference.php
@@ -79,17 +79,7 @@ class EntityReference extends EntityUsageTrackBase implements EntityUsageTrackMu
       }
     }
 
-    if (empty($entity_ids)) {
-      return [];
-    }
-
-    $target_type = $this->entityTypeManager->getDefinition($target_type_id);
-    // Only return a valid result if the target entity exists.
-    $query = $this->entityTypeManager->getStorage($target_type_id)
-      ->getQuery()
-      ->accessCheck(FALSE)
-      ->condition($target_type->getKey('id'), $entity_ids, 'IN');
-    return array_values(array_map(fn ($id) => $target_type_id . '|' . $id, $query->execute()));
+    return $this->checkAndPrepareEntityIds($target_type_id, $entity_ids, 'id');
   }
 
 }
diff --git a/src/Plugin/EntityUsage/Track/LayoutBuilder.php b/src/Plugin/EntityUsage/Track/LayoutBuilder.php
index 50ab2598577a71244768b7770ac415c497bf70c4..03e1045510a2492874aba917323eb94a098a63fb 100644
--- a/src/Plugin/EntityUsage/Track/LayoutBuilder.php
+++ b/src/Plugin/EntityUsage/Track/LayoutBuilder.php
@@ -147,10 +147,10 @@ class LayoutBuilder extends EntityUsageTrackBase {
 
     $target_entities = [];
     if (count($blockContentRevisionIds) > 0) {
-      $target_entities = $this->prepareEntityIds('block_content', $blockContentRevisionIds, 'revision');
+      $target_entities = $this->checkAndPrepareEntityIds('block_content', $blockContentRevisionIds, 'revision');
     }
     if (count($blockContentUuids) > 0) {
-      $target_entities = array_merge($target_entities, $this->prepareEntityIds('block_content', $blockContentUuids, 'uuid'));
+      $target_entities = array_merge($target_entities, $this->checkAndPrepareEntityIds('block_content', $blockContentUuids, 'uuid'));
     }
     if (count($ebbContentIds) > 0) {
       $target_entities = array_merge($target_entities, $this->prepareEntityBrowserBlockIds($ebbContentIds));
@@ -162,36 +162,6 @@ class LayoutBuilder extends EntityUsageTrackBase {
 
   }
 
-  /**
-   * Prepare target entity values to be in the correct format.
-   *
-   * @param string $entityTypeId
-   *   The entity type ID.
-   * @param array $ids
-   *   An array of entity IDs, can be revision or UUIDs as well.
-   * @param string $idField
-   *   The ID field; UUID or revision or id.
-   *
-   * @return array
-   *   An array of the corresponding entity IDs from the IDs passed in,
-   *   each prefixed with the string "$entityTypeId|". Non-loadable entities
-   *   will be filtered out.
-   */
-  private function prepareEntityIds(string $entityTypeId, array $ids, string $idField) {
-    if (!$this->isEntityTypeTracked($entityTypeId)) {
-      return [];
-    }
-    $storage = $this->entityTypeManager->getStorage($entityTypeId);
-
-    /** @var \Drupal\block_content\BlockContentInterface[] $blockContent */
-    $ids = $storage->getQuery()
-      ->accessCheck(FALSE)
-      ->condition($storage->getEntityType()->getKey($idField), $ids, 'IN')
-      ->execute();
-
-    return array_map(fn ($id) => $entityTypeId . '|' . $id, $ids);
-  }
-
   /**
    * Prepare Entity Browser Block IDs to be in the correct format.
    *
@@ -219,7 +189,7 @@ class LayoutBuilder extends EntityUsageTrackBase {
       // Return items in the expected format, separating type and id with a "|".
       $return = array_merge(
         $return,
-        $this->prepareEntityIds($entity_type_id, $entity_ids, 'id')
+        $this->checkAndPrepareEntityIds($entity_type_id, $entity_ids, 'id')
       );
     }
 
@@ -255,7 +225,7 @@ class LayoutBuilder extends EntityUsageTrackBase {
     foreach ($ids as $entity_type_id => $entity_uuids) {
       $return = array_merge(
         $return,
-        $this->prepareEntityIds($entity_type_id, $entity_uuids, 'uuid')
+        $this->checkAndPrepareEntityIds($entity_type_id, $entity_uuids, 'uuid')
       );
     }