Task #89058

PageRouter::matchRequest could use a cache

Added by Andreas Fernandez about 2 years ago. Updated over 1 year ago.

Status:
Needs Feedback
Priority:
Should have
Assignee:
-
Category:
Link Handling, Site Handling & Routing
Target version:
-
Start date:
2019-09-02
Due date:
% Done:

0%

Estimated time:
TYPO3 Version:
10
PHP Version:
Tags:
Complexity:
Sprint Focus:
On Location Sprint

Description

Currently, on every request PageRouter::matchRequest collects all slug candidates and chooses the best candidate. Depending on the amount of records in the database, this may lead to a lot of queries.

For a route that has been resolved previously, the result might get cached for faster resolving. This needs a proper concept in terms of cache invalidation.


Files

PageRouter.patch (1.71 KB) PageRouter.patch Carlos Meyer, 2019-11-12 16:24
#1

Updated by Benni Mack about 2 years ago

Hey Andy,

where exactly are the multiple DB queries located?

AFAIK getPagesFromDatabaseForCandidates() does only one query per language. If workspaces are enabled, we have more, of course.

#2

Updated by Christian Eßl almost 2 years ago

  • Category set to Link Handling, Site Handling & Routing
#3

Updated by Benni Mack almost 2 years ago

  • Status changed from New to Needs Feedback
#4

Updated by Carlos Meyer almost 2 years ago

We have the performance problem currently in an installation with 1600 domains too. In our case we fixed it by extending the query in the getPagesFromDatabaseForCandidates, so that only the pages of the current rootline are returned. But I'm not sure if there could be problems with mountpoints?

Changes in PageRouter.php line 334 and below

  /**
     * Get all uids below given page uid
     *
     * @param $pageUID
     * @return string
     */

    private function getRecursivePageUIDs($pageUID)
    {
        $depth = 999999;
        $queryGenerator = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\QueryGenerator');
        $rGetTreeList = $queryGenerator->getTreeList($pageUID, $depth, 0, 1);
        //Will be a string
        return explode(',', $rGetTreeList);

    }

    /**
     * Check for records in the database which matches one of the slug candidates.
     *
     * @param array $slugCandidates
     * @param int $languageId
     * @return array
     */
    protected function getPagesFromDatabaseForCandidates(array $slugCandidates, int $languageId): array
    {
        $context = GeneralUtility::makeInstance(Context::class);
        $searchLiveRecordsOnly = $context->getPropertyFromAspect('workspace', 'isLive');
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
            ->getQueryBuilderForTable('pages');
        $queryBuilder
            ->getRestrictions()
            ->removeAll()
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
            ->add(GeneralUtility::makeInstance(FrontendWorkspaceRestriction::class, null, null, $searchLiveRecordsOnly));
        //restrict query to sites in rootline
        $uids = $this->getRecursivePageUIDs($this->site->getRootPageId());
        $statement = $queryBuilder
            ->select('uid', 'l10n_parent', 'pid', 'slug')
            ->from('pages')
            ->where(
                $queryBuilder->expr()->in('uid',$uids),
                $queryBuilder->expr()->eq(
                    'sys_language_uid',
                    $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
                ),
                $queryBuilder->expr()->in(
                    'slug',
                    $queryBuilder->createNamedParameter(
                        $slugCandidates,
                        Connection::PARAM_STR_ARRAY
                    )
                )
            )
            // Exact match will be first, that's important
            ->orderBy('slug', 'desc')
            ->execute();
#7

Updated by Susanne Moog over 1 year ago

  • Sprint Focus set to On Location Sprint
#8

Updated by Yohann CERDAN over 1 year ago

Same problem here, we have a large website with 100+ domains and some mountpoints.
The method getPagesFromDatabaseForCandidates() iterate a lot of non necessary pages (/home/about-us/offices/,/home/about-us/,/home/,/ for each site) and call a lot of methods for each.
For examples, in my case, i will iterate overs 500+ pages to find the slug that appear in the first row of the query. This result in a big performance issue.

So, even if we find a page wich are on the same site, we iterate all the others pages.
If we have the good site ID and the exact same slug, maybe we could stop iteration here?

Also available in: Atom PDF