你如何在准备好的陈述中使用memcached?

时间:2009-12-06 20:00:01

标签: php memcached prepared-statement

缓存常规SQL查询非常简单。

public function query($sql) {

    if( $result = cache::get(sha1($sql)) ) {
        return $result;
    }

    $result = $this->connection->query($sql);
    cache::set(sha1($sql), $result);
    return $result;
}

但是如何使用预处理语句缓存查询,因为在语句准备好后数据被绑定之前,您不知道查询将是什么?

$sth = $dbh->prepare('SELECT * FROM table WHERE id = ?');

...later...

$sth->bindParam(1, $id);
$sth->execute();

我觉得这是一个由两部分组成的答案:首先,语句缓存在每页内存中(就像$ this-> statements []的数组一样),因为数据库资源id不会持续很长,不能存储在文件或任何东西。

其次,在执行语句之前()我们在memcached / filecache中查看结果,方法是散列用于创建语句的sql(使用PDOStatement::queryString轻松)以及给定的params的哈希值。麻烦的是在语句对象中找到params。

当然,这只是一个想法,可能有更好的解决方案。

1 个答案:

答案 0 :(得分:1)

好吧,你必须将每个参数的值添加到缓存键中。像这样:

public function stmt($sql, $params) {

    $cache_key = sha1($sql . serialize($params));

    if( $result = cache::get($cache_key) ) {
        return $result;
    }

    $sth = $this->connection->prepare($sql);

    $i = 0;
    foreach ($params as &$param)
    {
        $sth->bindParam(++$i, $param);
        $sth->execute();
    }
    unset($param)

    // fetch all the rows into $result

    cache::set($cache_key, $result);
    return $result;
}

$obj->stmt('SELECT * FROM table WHERE id = ?', array(&$id));

我会留给你根据你的需要调整它。你必须获取行并将它们存储在一个数组中。


这是你必须使用的那种包装器:

class stmt
{
    protected $sth, $sql, $cache, $params = array();

    public function __construct($dbh, $sql)
    {
        $this->sth = $dbh->prepare($sql);
        $this->sql = $sql;
    }

    public function bindParam($param, &$var)
    {
        $this->params[$param] =& $var;
        return $this->sth->bindParam($param, $var);

        // or, if you want to support all the args
        $args = func_get_args();
        $args[1] =& $var;

        return call_user_func_array(array($this->sth, 'bindParam'), $args);
    }

    public function execute(array $params = null)
    {
        $str = serialize(isset($params) ? $params : $this->params);
        $cache_key = sha1($this->sql . $str);

        // insert cache logic here...

        if (isset($params))
        {
            $this->stmt->execute($params);
        }
        else
        {
            $this->stmt->execute();
        }

        $this->cache = $this->stmt->fetchAll();

        // save cache here
    }

    public function fetch()
    {
        return array_shift($this->cache);
    }
}

您必须匹配您计划使用的每个PDOStatement方法。 PDO :: FETCH_INTO也很难实现。我的建议:专注于你自己的用法。也许您甚至不必在dbh级别实现缓存,而只能在其重要的位置添加缓存功能。

无论如何,请记住,您编写的代码越多,您需要维护的代码就越多,您在应用程序中引入错误的可能性就越大。因此,请谨慎对待缓存层的成本/收益分析,该缓存层会为了自己的利益而过于聪明:)