caching.txt 7.45 KB
Newer Older
phuson's avatar
phuson committed
1 2 3 4 5 6 7 8 9
++ Introduction
{{Doctrine_Cache}} offers an intuitive and easy-to-use query caching solution. It provides the following things:

* Multiple cache backends to choose from (including Memcached, APC and Sqlite)
* Advanced options for fine-tuning. {{Doctrine_Cache}} has many options for fine-tuning performance.

Initializing a new cache driver instance:

<code type="php">
10
$cacheDriver = new Doctrine_Cache_Memcache($options);
phuson's avatar
phuson committed
11 12 13 14 15 16 17 18 19 20 21 22
</code>

++ Drivers
+++ Memcache
Memcache driver stores cache records into a memcached server. Memcached is a high-performance, distributed memory object caching system. In order to use this backend, you need a memcached daemon and the memcache PECL extension.

<code type="php">
// memcache allows multiple servers
$servers = array('host' => 'localhost',
                 'port' => 11211,
                 'persistent' => true);

23
$cacheDriver = new Doctrine_Cache_Memcache(array('servers' => $servers,
phuson's avatar
phuson committed
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
                                           'compression' => false));
</code>

Available options for Memcache driver:

||~ Option ||~ Data Type ||~ Default Value ||~ Description  ||
|| servers || array  || array(array('host' => 'localhost','port' => 11211, 'persistent' => true)) || An array of memcached servers ; each memcached server is described by an associative array : 'host' => (string) : the name of the memcached server, 'port' => (int) : the port of the memcached server, 'persistent' => (bool) : use or not persistent connections to this memcached server  ||
|| compression || boolean || false || true if you want to use on-the-fly compression  ||

+++ APC
The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. It was conceived of to provide a free, open, and robust framework for caching and optimizing PHP intermediate code. 

The APC cache driver of Doctrine stores cache records in shared memory.

<code type="php">
39
$cacheDriver = new Doctrine_Cache_Apc();
phuson's avatar
phuson committed
40 41 42 43 44 45 46 47 48 49 50 51
</code>


+++ Db

Db caching backend stores cache records into given database. Usually some fast flat-file based database is used (such as sqlite).

Initializing sqlite cache driver can be done as above:

<code type="php">
$conn  = Doctrine_Manager::connection(new PDO('sqlite::memory:'));

52
$cacheDriver = new Doctrine_Cache_Sqlite(array('connection' => $conn));
phuson's avatar
phuson committed
53 54
</code>

romanb's avatar
romanb committed
55 56
++ Query Cache & Result Cache

phuson's avatar
phuson committed
57 58
+++ Introduction

romanb's avatar
romanb committed
59
Doctrine provides means for caching the results of the DQL parsing process, as well as the end results of DQL queries (the data). These two caching mechanisms can greatly increase performance. Consider the standard workflow of DQL query execution:
phuson's avatar
phuson committed
60 61 62 63 64 65 66 67 68 69

# Init new DQL query
# Parse DQL query
# Build database specific SQL query
# Execute the SQL query
# Build the result set
# Return the result set

Now these phases can be very time consuming, especially phase 4 which sends the query to your database server. When Doctrine query cache is being used only the following phases occur:
# Init new DQL query
romanb's avatar
romanb committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
# Execute the SQL query (grabbed from the cache)
# Build the result set
# Return the result set
If a DQL query has a valid cache entry the cached SQL query is used, otherwise the phases 2-3 are executed normally and the result of these steps is then stored in the cache.
The query cache has no disadvantages, since you always get a fresh query result. You should therefore always use it in a production environment. That said, you can easily use it during development, too. Whenever you change a DQL query and execute it the first time Doctrine sees that is has been modified and will therefore create a new cache entry, so you dont even need to invalidate the cache. It's worth noting that the effectiveness of the query cache greatly relies on the usage of prepared staments (which are used by Doctrine by default anyway). You should not directly embed dynamic query parts and always use placeholders instead.

When using a result cache things get even better. Then your query process looks as follows (assuming a valid cache entry is found):
# Init new DQL query
# Return the result set
As you can see, the result cache implies the query cache shown previously.
You should always consider using a result cache if the data returned by the query does not need to be up-to-date at any time.

+++ Query Cache

++++ Using the query cache

You can set a connection or manager level query cache driver by using Doctrine::ATTR_QUERY_CACHE. Setting a connection level cache driver means that all queries executed with this connection use the specified cache driver whereas setting a manager level cache driver means that all connections (unless overridden at connection level) will use the given cache driver.

Setting a manager level query cache driver:
<code type="php">
$manager = Doctrine_Manager::getInstance();

$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);
</code>

Setting a connection level cache driver:
<code type="php">
$manager = Doctrine_Manager::getInstance();
$conn    = $manager->openConnection('pgsql://user:pass@localhost/test');

$conn->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);
</code>

++++ Fine-tuning

In the previous chapter we used global caching attributes. These attributes can be overriden at the query level. You can override the cache driver by calling useQueryCache with a valid cacheDriver. This rarely makes sense for the query cache but is possible:

<code type="php">
$query = new Doctrine_Query();

$query->useQueryCache(new Doctrine_Cache_Apc());
</code>
phuson's avatar
phuson committed
112

romanb's avatar
romanb committed
113
+++ Result Cache
phuson's avatar
phuson committed
114

romanb's avatar
romanb committed
115
++++ Using the result cache
phuson's avatar
phuson committed
116

romanb's avatar
romanb committed
117
You can set a connection or manager level result cache driver by using Doctrine::ATTR_RESULT_CACHE. Setting a connection level cache driver means that all queries executed with this connection use the specified cache driver whereas setting a manager level cache driver means that all connections (unless overridden at connection level) will use the given cache driver.
phuson's avatar
phuson committed
118 119 120 121 122

Setting a manager level cache driver:
<code type="php">
$manager = Doctrine_Manager::getInstance();

romanb's avatar
romanb committed
123
$manager->setAttribute(Doctrine::ATTR_RESULT_CACHE, $cacheDriver);
phuson's avatar
phuson committed
124 125 126 127 128 129 130
</code>

Setting a connection level cache driver:
<code type="php">
$manager = Doctrine_Manager::getInstance();
$conn    = $manager->openConnection('pgsql://user:pass@localhost/test');

romanb's avatar
romanb committed
131
$conn->setAttribute(Doctrine::ATTR_RESULT_CACHE, $cacheDriver);
phuson's avatar
phuson committed
132 133
</code>

romanb's avatar
romanb committed
134
Usually the cache entries are valid for only some time. You can set global value for how long the cache entries should be considered valid by using Doctrine::ATTR_RESULT_CACHE_LIFESPAN.
phuson's avatar
phuson committed
135 136 137 138
<code type="php">
$manager = Doctrine_Manager::getInstance();

// set the lifespan as one hour (60 seconds * 60 minutes = 1 hour = 3600 secs)
romanb's avatar
romanb committed
139
$manager->setAttribute(Doctrine::ATTR_RESULT_CACHE_LIFESPAN, 3600);
phuson's avatar
phuson committed
140 141 142 143 144 145 146 147 148 149
</code>
Now as we have set a cache driver for use we can make a DQL query to use it:
<code type="php">
$query = new Doctrine_Query();

// fetch blog titles and the number of comments
$query->select('b.title, COUNT(c.id) count')
      ->from('Blog b')
      ->leftJoin('b.Comments c')
      ->limit(10)
romanb's avatar
romanb committed
150
      ->useResultCache(true);
phuson's avatar
phuson committed
151 152 153 154
      
$entries = $query->execute();
</code>

romanb's avatar
romanb committed
155
++++ Fine-tuning
phuson's avatar
phuson committed
156 157 158 159 160 161

In the previous chapter we used global caching attributes. These attributes can be overriden at the query level. You can override the cache driver by calling useCache with a valid cacheDriver:

<code type="php">
$query = new Doctrine_Query();

romanb's avatar
romanb committed
162
$query->useResultCache(new Doctrine_Cache_Apc());
phuson's avatar
phuson committed
163 164
</code>

romanb's avatar
romanb committed
165
Also you can override the lifespan attribute by calling setResultCacheLifeSpan():
phuson's avatar
phuson committed
166 167 168 169 170

<code type="php">
$query = new Doctrine_Query();

// set the lifespan as half an hour
romanb's avatar
romanb committed
171
$query->setResultCacheLifeSpan(60 * 30);
phuson's avatar
phuson committed
172 173 174 175
</code>