- 🇳🇴Norway steinmb
Tagging to make it easier for persons like @catch to spot it.
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.
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.
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]);
}
}
}
If the overall idea is ok, I can create a patch with the implementation of this solution.
Active
11.0 🔥
It affects performance. It is often combined with the Needs profiling tag.
Not all content is available!
It's likely this issue predates Contrib.social: some issue and comment data are missing.
Tagging to make it easier for persons like @catch to spot it.