Skip to content

caching

Alexey Borzov edited this page Nov 29, 2021 · 2 revisions

Caching options

Parsing and building of queries is not a fast operation so it is highly recommended to use cache in production. Package classes like Node and NativeStatement are designed with serialization in mind and implement the magic __sleep() and __wakeup() methods.

Caching of parsing results

Parser can automatically cache AST of everything that goes through its parseSomething() methods (these are overloaded via __call() that contains caching code). You only need to provide an instance of class implementing CacheItemPoolInterface from PSR-6 to Parser constructor

$parser = new Parser(new Lexer(), new CacheImplementation());

ASTs will be stored in cache under keys having parsetree- prefix.

Caching of complete queries

You can also cache the results of query building process represented by NativeStatement. This should be done manually along the following lines

// You need to know the structure of query beforehand to create a cache key
$queryParts = [
    'base' => 'baseQueryId'
    'foo'  => '...',
    'bar'  => '...'
];

$cacheKey   = 'query-' . md5(serialize($queryParts));
$cacheItem  = $cache->getItem($cacheKey);
if ($cacheItem->isHit()) {
    $query = $cacheItem->get();

} else {
    $ast = createBaseQuery($queryParts['base']);
    if (!empty($queryParts['foo'])) {
        $ast->list[] = 'foo.*'
        $ast->from[0]->join('foo')->using = ['foo_id'];
    }
    if (!empty($queryParts['bar'])) {
        // ...
    }
    // ...

    $query = $factory->createFromAST($ast);
    $cache->save($cacheItem->set($query);
}

Note: caching of whole statements makes sense if you use parameters. If you just build query with constants caching won't help much

// This is OK:
$ast->where->and('foo_id = any(:id::integer[])');
// ...sometime later...
$query->executeParams($connection, ['id' => $id]);


// This is not OK:
$ast->where->and('foo_id in (' . implode(', ', $id) . ')');