Problem/Motivation

On admin user the frontpage has a couple of entity queries: (~100ms is the entire request in that example.)

Function Name Calls Calls% Incl. Wall Time
(microsec)
IWall% Incl.
MemUse
(bytes)
IMemUse% Incl.
PeakMemUse
(bytes)
IPeakMemUse%
Current Function
Drupal\Core\Entity\Query\Sql\Query::execute 3 12.0% 10,008 9.2% 2,209,344 12.4% 2,242,776 12.5%
Exclusive Metrics for Current Function 23 0.2% 4,352 0.2% 1,072 0.0%
Parent functions
Drupal\comment\CommentManager::getCountNewComments 2 66.7% 5,076 50.7% 724,328 32.8% 735,008 32.8%
Drupal\Core\Entity\EntityStorageBase::loadByProperties 1 33.3% 4,932 49.3% 1,485,016 67.2% 1,507,768 67.2%
Child functions
Drupal\Core\Entity\Query\Sql\Query::compile 3 20.0% 8,177 81.7% 2,113,360 95.7% 2,212,448 98.6%
Drupal\Core\Entity\Query\Sql\Query::result 3 20.0% 1,573 15.7% 49,184 2.2% 8,040 0.4%
Drupal\Core\Entity\Query\Sql\Query::prepare 3 20.0% 183 1.8% 29,704 1.3% 21,216 0.9%
Drupal\Core\Entity\Query\Sql\Query::finish 3 20.0% 30 0.3% 8,928 0.4% 0 0.0%
Drupal\Core\Entity\Query\Sql\Query::addSort 3 20.0% 22 0.2% 3,816 0.2% 0 0.0%

which are not necessarily cheap to execute.

One part of the chain of functions is

Function Name Calls Calls% Incl. Wall Time
(microsec)
IWall% Incl.
MemUse
(bytes)
IMemUse% Incl.
PeakMemUse
(bytes)
IPeakMemUse%
Current Function
Drupal\Core\Entity\Query\Sql\Tables::getTableMapping 20 18.7% 5,063 4.7% 1,688,928 9.5% 1,643,440 9.1%
Exclusive Metrics for Current Function 87 1.7% 3,096 0.2% 2,096 0.1%
Parent function
Drupal\Core\Entity\Query\Sql\Tables::addField 20 100.0% 5,063 100.0% 1,688,928 100.0% 1,643,440 100.0%
Child functions
Drupal\Core\Entity\Sql\DefaultTableMapping::getAllColumns 20 25.0% 4,941 97.6% 1,648,800 97.6% 1,634,096 99.4%
Drupal\Core\Entity\EntityManager::getStorage 20 25.0% 20 0.4% 696 0.0% 624 0.0%
array_flip 20 25.0% 15 0.3% 35,624 2.1% 6,080 0.4%
Drupal\Core\Entity\Sql\SqlContentEntityStorage::getTableMapping 20 25.0% 0 0.0% 712 0.0% 544 0.0%

which you can see, is not really cheap, but if you think about it, could be actually cached. The table mapping of an entity type should really not change between requests.

Proposed resolution

Maybe think about better ideas how to optimize it.

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

Issue summary: View changes
Issue tags: +entity storage

Adding the plach tag.

Berdir’s picture

The loadByProperties() is the block repository, right?

We have #2479459: BlockRepository::getVisibleBlocksPerRegion() does an uncached entity query on every request for that.

And the comment count is because node links are a placeholder and need to be rebuilt on every page.

I started testing to remove that on #2530846: Fix and improve comment cache tag usage, will possibly open a separate issue for that part instead.

So I think we can avoid those specific queries on cached pages but yes, we can definitely look into improving the queries themself too. I also noticed that the query we actually build seems to join the same table for some conditions, which also makes the actual query slower.

dawehner’s picture

The loadByProperties() is the block repository, right?

No its not, these are the entity query run by shortcut.module and comment manager. The slowness I want to show here is Drupal\Core\Entity\Query\Sql\Tables::getTableMapping, an inclusive walltime of 4.7% just for that.

claudiu.cristea’s picture

Status: Active » Needs review
FileSize
12.47 KB

Let's see. The biggest part here is cache invalidation.

@dawehner, can you benchmark this?

Status: Needs review » Needs work

The last submitted patch, 4: 2531932-4.patch, failed testing.

claudiu.cristea’s picture

Status: Needs work » Needs review
FileSize
3.75 KB
13.5 KB

Checking now if the cache.default service exists in the container because \Drupal\Core\Database\Driver\mysql\Schema & friends are called also during the install process when there's no full container. But, in that moment there's also no cache to clear so we can avoid the cache clear for that cases.

+++ b/core/lib/Drupal/Core/Database/Schema.php
@@ -47,6 +55,12 @@
   public function __construct($connection) {
     $this->uniqueIdentifier = uniqid('', TRUE);
     $this->connection = $connection;
+    try {
+      $this->cacheBin = \Drupal::cache();
+    }
+    // During the installation there's only a minimal container in place.
+    catch (InvalidArgumentException $e) { }
+    catch (ContainerNotInitializedException $e) { }
   }

@dawehner, I tried first to test this with \Drupal::hasService('cache.default') but \Drupal::hasService('cache.default') always returns TRUE, even when installing. Is this a bug?

Status: Needs review » Needs work

The last submitted patch, 6: 2531932-6.patch, failed testing.

Status: Needs work » Needs review

claudiu.cristea queued 6: 2531932-6.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 6: 2531932-6.patch, failed testing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev
larowlan’s picture

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Arti Anil Pattewar’s picture

Rerolled patch #6 against D9.3.x as suggested in #20.

Akram Khan’s picture

Fixed some syntax and statement that are unused and Fixed CCF #22

Akram Khan’s picture

Status: Needs work » Needs review
Medha Kumari’s picture

Version: 9.4.x-dev » 9.5.x-dev
Issue tags: -Needs reroll
FileSize
3.93 KB
9.24 KB

Rerolled the patch #23 in Drupal 9.5.x.

Spokje’s picture

Status: Needs review » Needs work

Needs some PHPCS fixes.

Akram Khan’s picture

Address #26 and Fixed CCF #25

Akram Khan’s picture

Status: Needs work » Needs review
joachim’s picture

Needs an IS update. The problem needs to be explained a bit better, and the proposed resolution explained.

phenaproxima’s picture

  1. +++ b/core/lib/Drupal/Core/Database/Schema.php
    @@ -46,6 +55,16 @@
    +    // During the installation there's only a minimal container in place.
    +    catch (InvalidArgumentException $e) {
    +
    +    }
    +    catch (ContainerNotInitializedException $e) {
    +
    +    }
    

    PHP 7.1 allows us to catch multiple exception types at once, and PHP 8 allows for non-capturing catches. So, assuming this won't be backported to Drupal 9, this could be:

    catch (InvalidArgumentException|ContainerNotInitializedException) {}
    

    If this will be backported, then:

    catch (InvalidArgumentException|ContainerNotInitializedException $e) {}
    
  2. +++ b/core/lib/Drupal/Core/Database/Schema.php
    @@ -288,7 +307,9 @@ public function fieldExists($table, $column) {
    -  abstract public function renameTable($table, $new_name);
    +  public function renameTable($table, $new_name) {
    +    $this->clearTableMappingCache($table);
    +  }
    

    This seems a bit dangerous, because it writes a license for subclasses to NOT implement this method, under the mistaken assumption that it will be handled by the parent class.

    I would suggest something like this instead:

    public function renameTable($table, $new_name) {
      $this->doTableRename($table, $new_name);
      $this->clearTableMappingCache($table);
    }
    
    abstract protected function doTableRename($table, $new_name);
    

    Although that would be a backwards compatibility break, so...I guess dunno what to do here, exactly.

catch’s picture

Status: Needs review » Needs work

The reroll in #27 is missing hunks of the patch that actually add the caching. #6 seems to be the last version of the patch with those changes.

Gunjan Rao Naik’s picture

FileSize
3.94 KB

Added patch against #27 in 10.1.x version

Gunjan Rao Naik’s picture

catch’s picture

#27 is an incomplete patch, any further work here needs to start with a re-roll of #6 and ignore all the patches in-between.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.