Add static cache for loadEntityByUuid function to store uuid-id pairs in memory

Created on 9 September 2022, about 2 years ago
Updated 3 September 2024, 26 days ago

Problem/Motivation

The function Drupal\Core\Entity\EntityRepository::loadEntityByUuid() is used very often in Drupal Core and contrib modules.

Although it looks like a lightweight function that loads the Entity directly by UUID, actually it performs a separate search of the Entity Id by UUID, using a separate SQL query, and only after this - loads the Entity by id. Here is the code:

  public function loadEntityByUuid($entity_type_id, $uuid) {
    $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);

    if (!$uuid_key = $entity_type->getKey('uuid')) {
      throw new EntityStorageException("Entity type $entity_type_id does not support UUIDs.");
    }

    $entities = $this->entityTypeManager->getStorage($entity_type_id)->loadByProperties([$uuid_key => $uuid]);

    return ($entities) ? reset($entities) : NULL;
  }

So the line:

    $entities = $this->entityTypeManager->getStorage($entity_type_id)->loadByProperties([$uuid_key => $uuid]);

actually composes the full EntityQuery that searches id by uuid via a separate SQL query.
And only then - loads the entity by id, using loadMultiple(), that already uses the Drupal build-in static caching.

As result, we have an additional SQL query, that executes always on each function call.

Steps to reproduce

1. Try to call the function Drupal\Core\Entity\EntityRepository::loadEntityByUuid() 10 times with the same entity type and uuid.

2. Lookup the SQL queries log - you will see the same SQL query executed 10 times.

Proposed resolution

Good solution to increase the performance of the function EntityRepository::loadEntityByUuid() can be using a static cache, that will store "uuid <=> id" pairs in memory cache, and check it before making a new SQL query.

This type of static caching is already used in function Drupal\Core\Entity\EntityStorageBase::loadMultiple, so we can reuse the same behavior for the EntityRepository::loadEntityByUuid() too!

Or maybe we can somehow share the static cache from EntityStorageBase::loadMultiple to use together with EntityRepository::loadEntityByUuid()?

Seems in EntityStorageBase::loadMultiple we can additionally fill the static cache of loading entities also by uuid, additionally to id, and reuse it in the EntityRepository::loadEntityByUuid().

Something like this (a quick trick):

    protected function setStaticCache(array $entities) {
      if ($this->entityType->isStaticallyCacheable()) {
        foreach ($entities as $entity) {
          $this->memoryCache->set($this->buildCacheId($entity->id()), $entity, MemoryCacheInterface::CACHE_PERMANENT, [$this->memoryCacheTag]);
+         $this->memoryCache->set($this->buildCacheId('id-by-uuid:' . $entity->uuid()), $entity->id(), MemoryCacheInterface::CACHE_PERMANENT, [$this->memoryCacheTag]);
        }
      }
    }

Remaining tasks

If the overall idea is ok, I can create a patch with the implementation of this solution.

User interface changes

API changes

Data model changes

Release notes snippet

Feature request
Status

Active

Version

11.0 🔥

Component
Entity 

Last updated about 7 hours ago

Created by

🇦🇲Armenia murz Yerevan, Armenia

Live updates comments and jobs are added and updated live.
  • Performance

    It affects performance. It is often combined with the Needs profiling tag.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024