Task #89058

PageRouter::matchRequest could use a cache

Added by Andreas Fernandez 3 months ago. Updated 28 days 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%

TYPO3 Version:
10
PHP Version:
Tags:
Complexity:
Sprint Focus:

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.

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

History

#1 Updated by Benni Mack 3 months 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 2 months ago

  • Category set to Link Handling, Site Handling & Routing

#3 Updated by Benni Mack about 1 month ago

  • Status changed from New to Needs Feedback

#4 Updated by Carlos Meyer about 1 month 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();

#5 Updated by Carlos Meyer 29 days ago

Also available in: Atom PDF