Cake PHP 3 - запрос кеширования с ключом полного оператора SQL - PullRequest
0 голосов
/ 11 июля 2020

Используя этот ответ Я попытался добавить кеширование в запрос, который является особенно медленным.

Этот запрос имеет фиксированные выбранные поля и ограничения, но три компонента могут различаться у разных пользователей: where выражение в самой таблице, on фильтрует объединенную таблицу и on фильтрует вторую объединенную таблицу. Поэтому я фильтрую данные в основной таблице и двух соединенных.

Чтобы кеширование работало, мне нужно включить отфильтрованные условия в ключ кеширования. Как я могу извлечь для этой цели все фильтры поиска, в том числе на объединениях?

Если я использую $q->clause('where'), как в связанном предложении, я получаю фильтр только на основном таблица, а не соединения. И $q->clause('join') пусто.

$query = $this->Regions->find('veryComplicatedFinder')
    ->cache(function (\Cake\ORM\Query $q)
            {
                debug($q->clause('where'));
                return 'test123';
            }, 'queries');

Я решил, что могу просто использовать весь оператор SQL. Тем не менее, $q->sql() приводит к чему-то вроде:

'SELECT ... FROM region Regions INNER JOIN chain Chains ON (Chains.id in (: c0,: c1,: c2) AND Chains. id = (Regions.chain_id)) ЛЕВОЕ СОЕДИНЕНИЕ сохраняет магазины ВКЛЮЧЕНЫ (Stores.type в (: c388) И Stores.type в (: c389) И Regions.id = (Stores.region_id)) ЛЕВОЕ СОЕДИНЕНИЕ продажи Продажи ON Stores.id = (Sales.store_id) WHERE (Regions.shape && ST_MakeEnvelope (51.5,5,52,5.5,4326)) GROUP BY Regions.id LIMIT 2000 '

Кажется, параметры привязки не включены .

1 Ответ

2 голосов
/ 11 июля 2020

Соединения для сдерживания создаются лениво

Если предложение join пусто, то вы, вероятно, используете ie контейнеры contain(), *joinWith(), matching() и / или notMatching() методы.

Объединения включений будут добавлены в предложение join объекта запроса только при компиляции запроса, до тех пор они живут в нетерпеливом загрузчике, а их обратные вызовы построителя запросов еще не оценен. Итак, хотя вы можете получить их так:

// contain()
$contain = $query->getEagerLoader()->getContain();

// *joinWith()/matching()/notMatching()
$matching = $query->getEagerLoader()->getMatching();

, условия еще нигде не применялись.

Получение привязок

При этом, если вы хотите хотел оценить весь запрос, тогда вы могли бы получить доступ к связанным значениям через связыватель значений, например:

$sql = $query->sql();
$bindings = $query->getValueBinder()->bindings();

Создание ключей кеша в средствах поиска

Один из подходов, который вы, возможно, захотите рассмотреть, - частичное смещение ответственности за ключ кеша на средство поиска, ie создание ключей кеша в средствах поиска, где у вас есть вся необходимая информация под рукой, и установка их в объекте запроса для оценки / использования в других местах.

Это могло бы выглядеть примерно так:

public function findVeryComplicatedFinder(\Cake\ORM\Query $query)
{
    $cacheKey = '';

    if ($abc) {
        $cacheKey .= 'abc';
        $query->leftJoinWith('Abc', function () {
            // ...
        });
    }

    if ($xyz) {
        $cacheKey .= 'xyz';
        $query->innerJoinWith('Xyz', function () {
            // ...
        });
    }
    
    // ...

    $query->applyOptions([
        'veryComplicatedFinderCacheKey' => $cacheKey
    ]);
    
    return $query;
}

В обратном вызове cache() вашего основного объекта запроса вы могли затем прочитать эту опцию и использовать ее для создания окончательного ключа кеша, что-то вроде этого:

$query = $this->Regions
    ->find('veryComplicatedFinder')
    ->cache(
        function (\Cake\ORM\Query $query) {
            $options = $query->getOptions();

            $cacheKey = 
                'mainQueryCachKeyBasedOnWhateverYouRequire' .
                $options['veryComplicatedFinderCacheKey'];

            return $cacheKey;
        },
        'queries'
    );
...