Как вы используете memcached с подготовленными заявлениями? - PullRequest
2 голосов
/ 06 декабря 2009

Кэширование обычных 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-> операторов []), поскольку идентификаторы ресурсов базы данных не будут длиться долго и не может быть сохранен в файлах или чем-либо еще.

Во-вторых, перед выполнением операторов () мы ищем результаты в memcached / filecache, хэшируя sql, используемый для создания оператора (легко с PDOStatement::queryString), плюс хэши заданных параметров. Проблема в том, чтобы найти параметры в объекте оператора.

Конечно, это всего лишь одна идея, и, возможно, есть лучшие решения.

1 Ответ

1 голос
/ 06 декабря 2009

Ну, вы должны добавить значение каждого из ваших параметров в ключ кеша. Примерно так:

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, и вместо этого вы можете добавлять возможности кеширования только там, где это важно.

В любом случае, имейте в виду, что чем больше кода вы пишете, тем больше кода вам придется поддерживать, и тем больше вероятность того, что вы внесете ошибки в свое приложение. Так что будьте осторожны с анализом затрат и выгод слоя кеширования, который попытается быть слишком умным для своей выгоды:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...