CakePHP 3 - 由完整 SQL 语句键入的缓存查询

CakePHP 3 - Cache query keyed by full SQL statement

使用 我尝试将缓存添加到一个特别慢的查询中。

此查询具有固定的选定字段和限制,但三个组件可能因不同的用户而异:table 本身的 where 语句,加入的 [=36] 上的 on 过滤器=] 和 on 过滤第二个加入的 table.
所以我过滤主要 table 和两个连接的数据。

为了缓存工作,我需要将过滤条件合并到缓存键中。 为此目的,我如何提取所有查找过滤器(包括连接)?

如果我使用 $q->clause('where'),就像在链接的建议中一样,我只会在主 table 上获得过滤器,而不是连接。 $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 regions Regions INNER JOIN chains Chains ON (Chains.id in (:c0,:c1,:c2) AND Chains.id = (Regions.chain_id)) LEFT JOIN stores Stores ON (Stores.type in (:c388) AND Stores.type in (:c389) AND Regions.id = (Stores.region_id)) LEFT JOIN sales Sales ON Stores.id = (Sales.store_id) WHERE (Regions.shape && ST_MakeEnvelope(51.5,5,52,5.5,4326)) GROUP BY Regions.id LIMIT 2000'

好像没有包含绑定参数。

包含的连接是延迟构建的

如果 join 子句为空,那么您可能使用了包含,即 contain()*joinWith()matching()、and/or notMatching() 方法。

包含连接只会在查询被编译时添加到查询对象的 join 子句中,直到那时它们都存在于预加载器中,它们的查询构建器回调尚未被评估。因此,虽然您可以这样获得它们:

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

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

条件尚未在任何地方应用。

获取绑定

也就是说,如果您想评估整个查询,那么您可以通过值绑定器访问绑定值,如下所示:

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

在查找器中构建缓存键

您可能要考虑的一种方法是将缓存键的责任部分转移到查找器中,即在您手边拥有所有必需信息的查找器中构建缓存键,并将它们设置在查询对象上 evaluate/use在其他地方。

它可能看起来像这样:

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'
    );