Cari di MySQL 
    MySQL Manual
Daftar Isi
(Sebelumnya) 22.9.4. MySQL Functions (PDO_M ...22.9.8. Mysqlnd user handler p ... (Berikutnya)

22.9.7. Mysqlnd query result cache plugin (mysqlnd_qc)

Copyright 1997-2012 the PHP Documentation Group.

The mysqlnd query result cache plugin adds easy to use client-side query caching to all PHP MySQL extensions using mysqlnd.

As of version PHP 5.3.3 the MySQL native driver for PHP ( mysqlnd) features an internal plugin C API. C plugins, such as the query cache plugin, can extend the functionality of mysqlnd.

Mysqlnd plugins such as the query cache plugin operate transparent from a user perspective. The cache plugin supports all PHP applications and all PHP MySQL extensions ( mysqli, mysql, PDO_MYSQL). It does not change existing APIs.

No significant application changes are required to cache a query. The cache has two operation modes. It will either cache all queries (not recommended) or only those queries marked with a certain SQL hint (recommended).

22.9.7.1. Key Features

Copyright 1997-2012 the PHP Documentation Group.

  • Transparent and therefore easy to use

    • supports all PHP MySQL extensions

    • no API changes

    • very little application changes required

  • Flexible invalidation strategy

    • Time-to-Live (TTL)

    • user-defined

  • Storage with different scope and life-span

    • Default (Hash, process memory)

    • APC

    • MEMCACHE

    • sqlite

    • user-defined

  • Built-in slam defense to prevent cache stampeding.

22.9.7.2. Limitations

Copyright 1997-2012 the PHP Documentation Group.

The current 1.0.1 release of PECL mysqlnd_qc does not support PHP 5.4. Version 1.1.0-alpha lifts this limitation.

Prepared statements and unbuffered queries are fully supported. Thus, the plugin is capable of caching all statements issued with mysqli or PDO_MySQL, which are the only two PHP MySQL APIs to offer prepared statement support.

22.9.7.3. On the name

Copyright 1997-2012 the PHP Documentation Group.

The shortcut mysqlnd_qc stands for mysqlnd query cache plugin. The name was chosen for a quick-and-dirty proof-of-concept. In the beginning the developers did not expect to continue using the code base. Sometimes PECL/mysqlnd_qc has also been called client-side query result set cache.

22.9.7.4. Quickstart and Examples

Copyright 1997-2012 the PHP Documentation Group.

The mysqlnd query cache plugin is easy to use. This quickstart will demo typical use-cases, and provide practical advice on getting started.

It is strongly recommended to read the reference sections in addition to the quickstart. It is safe to begin with the quickstart. However, before using the plugin in mission critical environments we urge you to read additionally the background information from the reference sections.

Most of the examples use the mysqli extension because it is the most feature complete PHP MySQL extension. However, the plugin can be used with any PHP MySQL extension that is using the mysqlnd library.

22.9.7.4.1. Architecture and Concepts

Copyright 1997-2012 the PHP Documentation Group.

The query cache plugin is implemented as a PHP extension. It is written in C and operates under the hood of PHP. During the startup of the PHP interpreter, it gets registered as a mysqlnd plugin to replace selected mysqlnd C methods. Hereby, it can change the behaviour of any PHP MySQL extension (mysqli, PDO_MYSQL, mysql) compiled to use the mysqlnd library without changing the extensions API. This makes the plugin compatible with each and every PHP MySQL application. Because existing APIs are not changed, it is almost transparent to use. Please, see the mysqlnd plugin API description for a discussion of the advantages of the plugin architecture and a comparison with proxy based solutions.

Transparent to use

At PHP run time PECL/mysqlnd_qc can proxy queries send from PHP (mysqlnd) to the MySQL server. It then inspects the statement string to find whether it shall cache its results. If so, result set is cached using a storage handler and further executions of the statement are served from the cache for a user-defined period. The Time to Live (TTL) of the cache entry can either be set globally or on a per statement basis.

A statement is either cached if the plugin is instructed to cache all statements globally using a or, if the query string starts with the SQL hint (/*qc=on*/). The plugin is capable of caching any query issued by calling appropriate API calls of any of the existing PHP MySQL extensions.

Flexible storage: various storage handler

Various storage handler are supported to offer different scopes for cache entries. Different scopes allow for different degrees in sharing cache entries among clients.

  • default (built-in): process memory, scope: process, one or more web requests depending on PHP deployment model used

  • APC: shared memory, scope: single server, multiple web requests

  • SQLite: memory or file, scope: single server, multiple web requests

  • MEMCACHE: main memory, scope: single or multiple server, multiple web requests

  • user (built-in): user-defined - any, scope: user-defined - any

Support for the APC, SQLite and MEMCACHE storage handler has to be enabled at compile time. The default and user handler are built-in. It is possible to switch between compiled-in storage handlers on a per query basis at run time. However, it is recommended to pick one storage handler and use it for all cache entries.

Built-in slam defense to avoid overloading

To avoid overload situations the cache plugin has a built-in slam defense mechanism. If a popular cache entries expires many clients using the cache entries will try to refresh the cache entry. For the duration of the refresh many clients may access the database server concurrently. In the worst case, the database server becomes overloaded and it takes more and more time to refresh the cache entry, which in turn lets more and more clients try to refresh the cache entry. To prevent this from happening the plugin has a slam defense mechanism. If slam defense is enabled and the plugin detects an expired cache entry it extends the life time of the cache entry before it refreshes the cache entry. This way other concurrent accesses to the expired cache entry are still served from the cache for a certain time. The other concurrent accesses to not trigger a concurrent refresh. Ideally, the cache entry gets refreshed by the client which extended the cache entries lifespan before other clients try to refresh the cache and potentially cause an overload situation.

Unique approach to caching

PECL/mysqlnd_qc has a unique approach to caching result sets that is superior to application based cache solutions. Application based solutions first fetch a result set into PHP variables. Then, the PHP variables are serialized for storage in a persistent cache, and then unserialized when fetching. The mysqlnd query cache stores the raw wire protocol data sent from MySQL to PHP in its cache and replays it, if still valid, on a cache hit. This way, it saves an extra serialization step for a cache put that all application based solutions have to do. It can store the raw wire protocol data in the cache without having to serialize into a PHP variable first and deserializing the PHP variable for storing in the cache again.

22.9.7.4.2. Setup

Copyright 1997-2012 the PHP Documentation Group.

The plugin is implemented as a PHP extension. See also the installation instructions to install the PECL/mysqlnd_qc extension.

Compile or configure the PHP MySQL extension (mysqli, PDO_MYSQL, mysql) that you plan to use with support for the mysqlnd library. PECL/mysqlnd_qc is a plugin for the mysqlnd library. To use the plugin with any of the existing PHP MySQL extensions (APIs), the extension has to use the mysqlnd library.

Then, load the extension into PHP and activate the plugin in the PHP configuration file using the PHP configuration directive named mysqlnd_qc.enable_qc.

Example 22.291. Enabling the plugin (php.ini)

mysqlnd_qc.enable_qc=1
22.9.7.4.3. Caching queries

Copyright 1997-2012 the PHP Documentation Group.

There are four ways to trigger caching of a query.

Use of SQL hints and mysqlnd_qc.cache_by_default = 1 are explained below. Please, refer to the function reference on mysqlnd_qc_is_select for a description of using a callback and, mysqlnd_qc_set_cache_condition on how to set rules for automatic caching.

A SQL hint is a SQL standards compliant comment. As a SQL comment it is ignored by the database. A statement is considered eligible for caching if it either begins with the SQL hint enabling caching or it is a SELECT statement.

An individual query which shall be cached must begin with the SQL hint /*qc=on*/. It is recommended to use the PHP constant MYSQLND_QC_ENABLE_SWITCH instead of using the string value.

  • not eligible for caching and not cached: INSERT INTO test(id) VALUES (1)

  • not eligible for caching and not cached: SHOW ENGINES

  • eligible for caching but uncached: SELECT id FROM test

  • eligible for caching and cached: /*qc=on*/SELECT id FROM test

The examples SELECT statement string is prefixed with the MYSQLND_QC_ENABLE_SWITCH SQL hint to enable caching of the statement. The SQL hint must be given at the very beginning of the statement string to enable caching.

Example 22.292. Using the MYSQLND_QC_ENABLE_SWITCH SQL hint

mysqlnd_qc.enable_qc=1 
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");/* Will be cached because of the SQL hint */$start = microtime(true);$res   = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();printf("Total time uncached query: %.6fs\n", microtime(true) - $start);/* Cache hit */$start = microtime(true);$res   = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();printf("Total time cached query: %.6fs\n", microtime(true) - $start);?> 

The above examples will output something similar to:

array(1) {  ["id"]=>  string(1) "1"}Total time uncached query: 0.000740sarray(1) {  ["id"]=>  string(1) "1"}Total time cached query: 0.000098s

If nothing else is configured, as it is the case in the quickstart example, the plugin will use the built-in default storage handler. The default storage handler uses process memory to hold a cache entry. Depending on the PHP deployment model, a PHP process may serve one or more web requests. Please, consult the web server manual for details. Details make no difference for the examples given in the quickstart.

The query cache plugin will cache all queries regardless if the query string begins with the SQL hint which enables caching or not, if the PHP configuration directive mysqlnd_qc.cache_by_default is set to 1. The setting mysqlnd_qc.cache_by_default is evaluated by the core of the query cache plugins. Neither the built-in nor user-defined storage handler can overrule the setting.

The SQL hint /*qc=off*/ can be used to disable caching of individual queries if mysqlnd_qc.cache_by_default = 1 It is recommended to use the PHP constant MYSQLND_QC_DISABLE_SWITCH instead of using the string value.

Example 22.293. Using the MYSQLND_QC_DISABLE_SWITCH SQL hint

mysqlnd_qc.enable_qc=1mysqlnd_qc.cache_by_default=1 
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");/* Will be cached although no SQL hint is present because of mysqlnd_qc.cache_by_default = 1*/$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();$mysqli->query("DELETE FROM test WHERE id = 1");/* Cache hit - no automatic invalidation and still valid! */$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();/* Cache miss - query must not be cached because of the SQL hint */$res = $mysqli->query("/*" . MYSQLND_QC_DISABLE_SWITCH . "*/SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();?> 

The above examples will output:

array(1) {  ["id"]=>  string(1) "1"}array(1) {  ["id"]=>  string(1) "1"}NULL

PECL/mysqlnd_qc forbids caching of statements for which at least one column from the statements result set shows no table name in its meta data by default. This is usually the case for columns originating from SQL functions such as NOW() or LAST_INSERT_ID(). The policy aims to prevent pitfalls if caching by default is used.

Example 22.294. Example showing which type of statements are not cached

mysqlnd_qc.enable_qc=1mysqlnd_qc.cache_by_default=1 
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1)");for ($i = 0; $i < 3; $i++) { $start = microtime(true); /* Note: statement will not be cached because of NOW() use */ $res = $mysqli->query("SELECT id, NOW() AS _time FROM test"); $row = $res->fetch_assoc(); /* dump results */ var_dump($row); printf("Total time: %.6fs\n", microtime(true) - $start); /* pause one second */ sleep(1);}?> 

The above examples will output something similar to:

array(2) {  ["id"]=>  string(1) "1"  ["_time"]=>  string(19) "2012-01-11 15:43:10"}Total time: 0.000540sarray(2) {  ["id"]=>  string(1) "1"  ["_time"]=>  string(19) "2012-01-11 15:43:11"}Total time: 0.000555sarray(2) {  ["id"]=>  string(1) "1"  ["_time"]=>  string(19) "2012-01-11 15:43:12"}Total time: 0.000549s

It is possible to enable caching for all statements including those which has columns in their result set for which MySQL reports no table, such as the statement from the example. Set mysqlnd_qc.cache_no_table = 1 to enable caching of such statements. Please, note the difference in the measured times for the above and below examples.

Example 22.295. Enabling caching for all statements using themysqlnd_qc.cache_no_table ini setting

mysqlnd_qc.enable_qc=1mysqlnd_qc.cache_by_default=1mysqlnd_qc.cache_no_table=1 
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1)");for ($i = 0; $i < 3; $i++) { $start = microtime(true); /* Note: statement will not be cached because of NOW() use */ $res = $mysqli->query("SELECT id, NOW() AS _time FROM test"); $row = $res->fetch_assoc(); /* dump results */ var_dump($row); printf("Total time: %.6fs\n", microtime(true) - $start); /* pause one second */ sleep(1);}?> 

The above examples will output something similar to:

array(2) {  ["id"]=>  string(1) "1"  ["_time"]=>  string(19) "2012-01-11 15:47:45"}Total time: 0.000546sarray(2) {  ["id"]=>  string(1) "1"  ["_time"]=>  string(19) "2012-01-11 15:47:45"}Total time: 0.000187sarray(2) {  ["id"]=>  string(1) "1"  ["_time"]=>  string(19) "2012-01-11 15:47:45"}Total time: 0.000167s
Note

Although mysqlnd_qc.cache_no_table = 1 has been created for use with mysqlnd_qc.cache_by_default = 1 it is bound it. The plugin will evaluate the mysqlnd_qc.cache_no_table whenever a query is to be cached, no matter whether caching has been enabled using a SQL hint or any other measure.

22.9.7.4.4. Setting the TTL

Copyright 1997-2012 the PHP Documentation Group.

The default invalidation strategy of the query cache plugin is Time to Live (TTL). The built-in storage handlers will use the default TTL defined by the PHP configuration value mysqlnd_qc.ttl unless the query string contains a hint for setting a different TTL. The TTL is specified in seconds. By default cache entries expire after 30 seconds

The example sets mysqlnd_qc.ttl=3 to cache statements for three seconds by default. Every second it updates a database table record to hold the current time and executes a SELECT statement to fetch the record from the database. The SELECT statement is cached for three seconds because it is prefixed with the SQL hint enabling caching. The output verifies that the query results are taken from the cache for the duration of three seconds before they are refreshed.

Example 22.296. Setting the TTL with the mysqlnd_qc.ttl ini setting

mysqlnd_qc.enable_qc=1mysqlnd_qc.ttl=3 
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id VARCHAR(255))");for ($i = 0; $i < 7; $i++) { /* update DB row  */ if (!$mysqli->query("DELETE FROM test") || !$mysqli->query("INSERT INTO test(id) VALUES (NOW())"))  /* Of course, a real-life script should do better error handling */  die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); /* select latest row but cache results */ $query  = "/*" . MYSQLND_QC_ENABLE_SWITCH . "*/"; $query .= "SELECT id AS _time FROM test"; if (!($res = $mysqli->query($query)) || !($row = $res->fetch_assoc())) {  printf("[%d] %s\n", $mysqli->errno, $mysqli->error); } $res->free(); printf("Wall time %s - DB row time %s\n", date("H:i:s"), $row['_time']); /* pause one second */ sleep(1);}?> 

The above examples will output something similar to:

Wall time 14:55:59 - DB row time 2012-01-11 14:55:59Wall time 14:56:00 - DB row time 2012-01-11 14:55:59Wall time 14:56:01 - DB row time 2012-01-11 14:55:59Wall time 14:56:02 - DB row time 2012-01-11 14:56:02Wall time 14:56:03 - DB row time 2012-01-11 14:56:02Wall time 14:56:04 - DB row time 2012-01-11 14:56:02Wall time 14:56:05 - DB row time 2012-01-11 14:56:05

As can be seen from the example, any TTL based cache can serve stale data. Cache entries are not automatically invalidated, if underlying data changes. Applications using the default TTL invalidation strategy must be able to work correctly with stale data.

A user-defined cache storage handler can implement any invalidation strategy to work around this limitation.

The default TTL can be overruled using the SQL hint /*qc_tt=seconds*/. The SQL hint must be appear immediately after the SQL hint which enables caching. It is recommended to use the PHP constant MYSQLND_QC_TTL_SWITCH instead of using the string value.

Example 22.297. Setting TTL with SQL hints

<?php$start = microtime(true);/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");printf("Default TTL\t: %d seconds\n", ini_get("mysqlnd_qc.ttl"));/* Will be cached for 2 seconds */$sql = sprintf("/*%s*//*%s%d*/SELECT id FROM test WHERE id = 1", MYSQLND_QC_ENABLE_SWITCH, MYSQLND_QC_TTL_SWITCH, 2);$res = $mysqli->query($sql);var_dump($res->fetch_assoc());$res->free();$mysqli->query("DELETE FROM test WHERE id = 1");sleep(1);/* Cache hit - no automatic invalidation and still valid! */$res = $mysqli->query($sql);var_dump($res->fetch_assoc());$res->free();sleep(2);/* Cache miss - cache entry has expired */$res = $mysqli->query($sql);var_dump($res->fetch_assoc());$res->free();printf("Script runtime\t: %d seconds\n", microtime(true) - $start);?> 

The above examples will output something similar to:

Default TTL : 30 secondsarray(1) {  ["id"]=>  string(1) "1"}array(1) {  ["id"]=>  string(1) "1"}NULLScript runtime  : 3 seconds
22.9.7.4.5. Pattern based caching

Copyright 1997-2012 the PHP Documentation Group.

An application has three options for telling PECL/mysqlnd_qc whether a particular statement shall be used. The most basic approach is to cache all statements by setting mysqlnd_qc.cache_by_default = 1. This approach is often of little practical value. But it enables users to make a quick estimation about the maximum performance gains from caching. An application designed to use a cache may be able to prefix selected statements with the appropriate SQL hints. However, altering an applications source code may not always be possible or desired, for example, to avoid problems with software updates. Therefore, PECL/mysqlnd_qc allows setting a callback which decides if a query is to be cached.

The callback is installed with the mysqlnd_qc_set_is_select function. The callback is given the statement string of every statement inspected by the plugin. Then, the callback can decide whether to cache the function. The callback is supposed to return FALSE if the statement shall not be cached. A return value of TRUE makes the plugin try to add the statement into the cache. The cache entry will be given the default TTL ( mysqlnd_qc.ttl). If the callback returns a numerical value it is used as the TTL instead of the global default.

Example 22.298. Setting a callback withmysqlnd_qc_set_is_select

mysqlnd_qc.enable_qc=1mysqlnd_qc.collect_statistics=1 
<?php/* callback which decides if query is cached */function is_select($query) { static $patterns = array(  /* true - use default from mysqlnd_qc.ttl */  "@SELECT\s+.*\s+FROM\s+test@ismU" => true,  /* 3 - use TTL = 3 seconds */  "@SELECT\s+.*\s+FROM\s+news@ismU" => 3 ); /* check if query does match pattern */ foreach ($patterns as $pattern => $ttl) { if (preg_match($pattern, $query)) { printf("is_select(%45s): cache\n", $query); return $ttl; } } printf("is_select(%45s): do not cache\n", $query); return false;}/* install callback */mysqlnd_qc_set_is_select("is_select");/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");/* cache put */$mysqli->query("SELECT id FROM test WHERE id = 1");/* cache hit */$mysqli->query("SELECT id FROM test WHERE id = 1");/* cache put */$mysqli->query("SELECT * FROM test");$stats = mysqlnd_qc_get_core_stats();printf("Cache put: %d\n", $stats['cache_put']);printf("Cache hit: %d\n", $stats['cache_hit']);?> 

The above examples will output something similar to:

is_select( DROP TABLE IF EXISTS test): do not cacheis_select( CREATE TABLE test(id INT)): do not cacheis_select( INSERT INTO test(id) VALUES (1), (2), (3)): do not cacheis_select( SELECT id FROM test WHERE id = 1): cacheis_select( SELECT id FROM test WHERE id = 1): cacheis_select(   SELECT * FROM test): cacheCache put: 2Cache hit: 1

The examples callback tests if a statement string matches a pattern. If this is the case, it either returns TRUE to cache the statement using the global default TTL or an alternative TTL.

To minimize application changes the callback can put into and registered in an auto prepend file.

22.9.7.4.6. Slam defense

Copyright 1997-2012 the PHP Documentation Group.

A badly designed cache can do more harm than good. In the worst case a cache can increase database server load instead of minimizing it. An overload situation can occur if a highly shared cache entry expires (cache stampeding).

Cache entries are shared and reused to a different degree depending on the storage used. The default storage handler stores cache entries in process memory. Thus, a cache entry can be reused for the life-span of a process. Other PHP processes cannot access it. If Memcache is used, a cache entry can be shared among multiple PHP processes and even among multiple machines, depending on the set up being used.

If a highly shared cache entry stored, for example, in Memcache expires, many clients gets a cache miss. Many client requests can no longer be served from the cache but try to run the underlying query on the database server. Until the cache entry is refreshed, more and more clients contact the database server. In the worst case, a total lost of service is the result.

The overload can be avoided using a storage handler which limits the reuse of cache entries to few clients. Then, at the average, its likely that only a limited number of clients will try to refresh a cache entry concurrently.

Additionally, the built-in slam defense mechanism can and should be used. If slam defense is activated an expired cache entry is given an extended life time. The first client getting a cache miss for the expired cache entry tries to refresh the cache entry within the extended life time. All other clients requesting the cache entry are temporarily served from the cache although the original TTL of the cache entry has expired. The other clients will not experience a cache miss before the extended life time is over.

Example 22.299. Enabling the slam defense mechanism

mysqlnd_qc.slam_defense=1mysqlnd_qc.slam_defense_ttl=1

The slam defense mechanism is enabled with the PHP configuration directive mysqlnd_qc.slam_defense. The extended life time of a cache entry is set with mysqlnd_qc.slam_defense_ttl.

The function mysqlnd_qc_get_core_stats returns an array of statistics. The statistics slam_stale_refresh and slam_stale_hit are incremented if slam defense takes place.

It is not possible to give a one-fits-all recommendation on the slam defense configuration. Users are advised to monitor and test their setup and derive settings accordingly.

22.9.7.4.7. Finding cache candidates

Copyright 1997-2012 the PHP Documentation Group.

A statement should be considered for caching if it is executed often and has a long run time. Cache candidates are found by creating a list of statements sorted by the product of the number of executions multiplied by the statements run time. The function mysqlnd_qc_get_query_trace_log returns a query log which help with the task.

Collecting a query trace is a slow operation. Thus, it is disabled by default. The PHP configuration directive mysqlnd_qc.collect_query_trace is used to enable it. The functions trace contains one entry for every query issued before the function is called.

Example 22.300. Collecting a query trace

mysqlnd_qc.enable_qc=1mysqlnd_qc.collect_query_trace=1 
<?php/* connect to MySQL */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");/* dummy queries to fill the query trace */for ($i = 0; $i < 2; $i++) { $res = $mysqli->query("SELECT 1 AS _one FROM DUAL"); $res->free();}/* dump trace */var_dump(mysqlnd_qc_get_query_trace_log());?> 

The above examples will output:

array(2) {  [0]=>  array(8) { ["query"]=> string(26) "SELECT 1 AS _one FROM DUAL" ["origin"]=> string(102) "#0 qc.php(7): mysqli->query('SELECT 1 AS _on...')#1 {main}" ["run_time"]=> int(0) ["store_time"]=> int(25) ["eligible_for_caching"]=> bool(false) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(false)  }  [1]=>  array(8) { ["query"]=> string(26) "SELECT 1 AS _one FROM DUAL" ["origin"]=> string(102) "#0 qc.php(7): mysqli->query('SELECT 1 AS _on...')#1 {main}" ["run_time"]=> int(0) ["store_time"]=> int(8) ["eligible_for_caching"]=> bool(false) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(false)  }}

Assorted information is given in the trace. Among them timings and the origin of the query call. The origin property holds a code backtrace to identify the source of the query. The depth of the backtrace can be limited with the PHP configuration directive mysqlnd_qc.query_trace_bt_depth. The default depth is 3.

Example 22.301. Setting the backtrace depth with the mysqlnd_qc.query_trace_bt_depth inisetting

mysqlnd_qc.enable_qc=1mysqlnd_qc.collect_query_trace=1 
<?php/* connect to MySQL */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");/* dummy queries to fill the query trace */for ($i = 0; $i < 3; $i++) { $res = $mysqli->query("SELECT id FROM test WHERE id = " . $mysqli->real_escape_string($i)); $res->free();}$trace = mysqlnd_qc_get_query_trace_log();$summary = array();foreach ($trace as $entry) { if (!isset($summary[$entry['query']])) { $summary[$entry['query']] = array( "executions" => 1, "time"   => $entry['run_time'] + $entry['store_time'], ); } else { $summary[$entry['query']]['executions']++; $summary[$entry['query']]['time'] += $entry['run_time'] + $entry['store_time']; }}foreach ($summary as $query => $details) { printf("%45s: %5dms (%dx)\n", $query, $details['time'], $details['executions']);}?> 

The above examples will output something similar to:

 DROP TABLE IF EXISTS test: 0ms (1x) CREATE TABLE test(id INT): 0ms (1x) INSERT INTO test(id) VALUES (1), (2), (3): 0ms (1x) SELECT id FROM test WHERE id = 0: 25ms (1x) SELECT id FROM test WHERE id = 1: 10ms (1x) SELECT id FROM test WHERE id = 2: 9ms (1x)
22.9.7.4.8. Measuring cache efficiency

Copyright 1997-2012 the PHP Documentation Group.

PECL/mysqlnd_qc offers three ways to measure the cache efficiency. The function mysqlnd_qc_get_normalized_query_trace_log returns statistics aggregated by the normalized query string, mysqlnd_qc_get_cache_info gives storage handler specific information which includes a list of all cached items, depending on the storage handler. Additionally, the core of PECL/mysqlnd_qc collects high-level summary statistics aggregated per PHP process. The high-level statistics are returned by mysqlnd_qc_get_core_stats.

The functions mysqlnd_qc_get_normalized_query_trace_log and mysqlnd_qc_get_core_stats will not collect data unless data collection has been enabled through their corresponding PHP configuration directives. Data collection is disabled by default for performance considerations. It is configurable with the mysqlnd_qc.time_statistics option, which determines if timing information should be collected. Collection of time statistics is enabled by default but only performed if data collection as such has been enabled. Recording time statistics causes extra system calls. In most cases, the benefit of the monitoring outweighs any potential performance penalty of the additional system calls.

Example 22.302. Collecting statistics data with themysqlnd_qc.time_statistics ini setting

mysqlnd_qc.enable_qc=1mysqlnd_qc.collect_statistics=1 
<?php/* connect to MySQL */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");/* dummy queries */for ($i = 1; $i <= 4; $i++) { $query = sprintf("/*%s*/SELECT id FROM test WHERE id = %d", MYSQLND_QC_ENABLE_SWITCH, $i % 2); $res   = $mysqli->query($query); $res->free();}var_dump(mysqlnd_qc_get_core_stats());?> 

The above examples will output something similar to:

array(26) {  ["cache_hit"]=>  string(1) "2"  ["cache_miss"]=>  string(1) "2"  ["cache_put"]=>  string(1) "2"  ["query_should_cache"]=>  string(1) "4"  ["query_should_not_cache"]=>  string(1) "3"  ["query_not_cached"]=>  string(1) "3"  ["query_could_cache"]=>  string(1) "4"  ["query_found_in_cache"]=>  string(1) "2"  ["query_uncached_other"]=>  string(1) "0"  ["query_uncached_no_table"]=>  string(1) "0"  ["query_uncached_no_result"]=>  string(1) "0"  ["query_uncached_use_result"]=>  string(1) "0"  ["query_aggr_run_time_cache_hit"]=>  string(2) "28"  ["query_aggr_run_time_cache_put"]=>  string(3) "900"  ["query_aggr_run_time_total"]=>  string(3) "928"  ["query_aggr_store_time_cache_hit"]=>  string(2) "14"  ["query_aggr_store_time_cache_put"]=>  string(2) "40"  ["query_aggr_store_time_total"]=>  string(2) "54"  ["receive_bytes_recorded"]=>  string(3) "136"  ["receive_bytes_replayed"]=>  string(3) "136"  ["send_bytes_recorded"]=>  string(2) "84"  ["send_bytes_replayed"]=>  string(2) "84"  ["slam_stale_refresh"]=>  string(1) "0"  ["slam_stale_hit"]=>  string(1) "0"  ["request_counter"]=>  int(1)  ["process_hash"]=>  int(1929695233)}

For a quick overview, call mysqlnd_qc_get_core_stats. It delivers cache usage, cache timing and traffic related statistics. Values are aggregated on a per process basis for all queries issued by any PHP MySQL API call.

Some storage handler, such as the default handler, can report cache entries, statistics related to the entries and meta data for the underlying query through the mysqlnd_qc_get_cache_info function. Please note, that the information returned depends on the storage handler. Values are aggregated on a per process basis.

Example 22.303. Example mysqlnd_qc_get_cache_infousage

mysqlnd_qc.enable_qc=1 
<?php/* connect to MySQL */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");/* dummy queries to fill the query trace */for ($i = 1; $i <= 4; $i++) { $query = sprintf("/*%s*/SELECT id FROM test WHERE id = %d", MYSQLND_QC_ENABLE_SWITCH, $i % 2); $res   = $mysqli->query($query);  $res->free();}var_dump(mysqlnd_qc_get_cache_info());?> 

The above examples will output something similar to:

array(4) {  ["num_entries"]=>  int(2)  ["handler"]=>  string(7) "default"  ["handler_version"]=>  string(5) "1.0.0"  ["data"]=>  array(2) { ["Localhost via UNIX socket3306roottest|/*qc=on*/SELECT id FROM test WHERE id = 1"]=> array(2) {  ["statistics"]=>  array(11) { ["rows"]=> int(1) ["stored_size"]=> int(71) ["cache_hits"]=> int(1) ["run_time"]=> int(391) ["store_time"]=> int(27) ["min_run_time"]=> int(16) ["max_run_time"]=> int(16) ["min_store_time"]=> int(8) ["max_store_time"]=> int(8) ["avg_run_time"]=> int(8) ["avg_store_time"]=> int(4)  }  ["metadata"]=>  array(1) { [0]=> array(8) {  ["name"]=>  string(2) "id"  ["orig_name"]=>  string(2) "id"  ["table"]=>  string(4) "test"  ["orig_table"]=>  string(4) "test"  ["db"]=>  string(4) "test"  ["max_length"]=>  int(1)  ["length"]=>  int(11)  ["type"]=>  int(3) }  } } ["Localhost via UNIX socket3306roottest|/*qc=on*/SELECT id FROM test WHERE id = 0"]=> array(2) {  ["statistics"]=>  array(11) { ["rows"]=> int(0) ["stored_size"]=> int(65) ["cache_hits"]=> int(1) ["run_time"]=> int(299) ["store_time"]=> int(13) ["min_run_time"]=> int(11) ["max_run_time"]=> int(11) ["min_store_time"]=> int(6) ["max_store_time"]=> int(6) ["avg_run_time"]=> int(5) ["avg_store_time"]=> int(3)  }  ["metadata"]=>  array(1) { [0]=> array(8) {  ["name"]=>  string(2) "id"  ["orig_name"]=>  string(2) "id"  ["table"]=>  string(4) "test"  ["orig_table"]=>  string(4) "test"  ["db"]=>  string(4) "test"  ["max_length"]=>  int(0)  ["length"]=>  int(11)  ["type"]=>  int(3) }  } }  }}

It is possible to further break down the granularity of statistics to the level of the normalized statement string. The normalized statement string is the statements string with all parameters replaced with question marks. For example, the two statements SELECT id FROM test WHERE id = 0 and SELECT id FROM test WHERE id = 1 are normalized into SELECT id FROM test WHERE id = ?. Their both statistics are aggregated into one entry for SELECT id FROM test WHERE id = ?.

Example 22.304. Example mysqlnd_qc_get_normalized_query_trace_logusage

mysqlnd_qc.enable_qc=1mysqlnd_qc.collect_normalized_query_trace=1 
<?php/* connect to MySQL */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");/* dummy queries to fill the query trace */for ($i = 1; $i <= 4; $i++) { $query = sprintf("/*%s*/SELECT id FROM test WHERE id = %d", MYSQLND_QC_ENABLE_SWITCH, $i % 2); $res   = $mysqli->query($query);  $res->free();}var_dump(mysqlnd_qc_get_normalized_query_trace_log());?> 

The above examples will output something similar to:

array(4) {  [0]=>  array(9) { ["query"]=> string(25) "DROP TABLE IF EXISTS test" ["occurences"]=> int(0) ["eligible_for_caching"]=> bool(false) ["avg_run_time"]=> int(0) ["min_run_time"]=> int(0) ["max_run_time"]=> int(0) ["avg_store_time"]=> int(0) ["min_store_time"]=> int(0) ["max_store_time"]=> int(0)  }  [1]=>  array(9) { ["query"]=> string(27) "CREATE TABLE test (id INT )" ["occurences"]=> int(0) ["eligible_for_caching"]=> bool(false) ["avg_run_time"]=> int(0) ["min_run_time"]=> int(0) ["max_run_time"]=> int(0) ["avg_store_time"]=> int(0) ["min_store_time"]=> int(0) ["max_store_time"]=> int(0)  }  [2]=>  array(9) { ["query"]=> string(46) "INSERT INTO test (id ) VALUES (? ), (? ), (? )" ["occurences"]=> int(0) ["eligible_for_caching"]=> bool(false) ["avg_run_time"]=> int(0) ["min_run_time"]=> int(0) ["max_run_time"]=> int(0) ["avg_store_time"]=> int(0) ["min_store_time"]=> int(0) ["max_store_time"]=> int(0)  }  [3]=>  array(9) { ["query"]=> string(31) "SELECT id FROM test WHERE id =?" ["occurences"]=> int(4) ["eligible_for_caching"]=> bool(true) ["avg_run_time"]=> int(179) ["min_run_time"]=> int(11) ["max_run_time"]=> int(393) ["avg_store_time"]=> int(12) ["min_store_time"]=> int(7) ["max_store_time"]=> int(25)  }}

The source distribution of PECL/mysqlnd_qc contains a directory web/ in which web based monitoring scripts can be found which give an example how to write a cache monitor. Please, follow the instructions given in the source.

Since PECL/mysqlnd_qc 1.1.0 it is possible to write statistics into a log file. Please, see mysqlnd_qc.collect_statistics_log_file.

22.9.7.4.9. Beyond TTL: user-defined storage

Copyright 1997-2012 the PHP Documentation Group.

The query cache plugin supports the use of user-defined storage handler. User-defined storage handler can use arbitrarily complex invalidation algorithms and support arbitrary storage media.

All user-defined storage handlers have to provide a certain interface. The functions of the user-defined storage handler will be called by the core of the cache plugin. The necessary interface consists of seven public functions. Both procedural and object oriented user-defined storage handler must implement the same set of functions.

Example 22.305. Using a user-defined storage handler

<?php/* Enable default caching of all statements */ini_set("mysqlnd_qc.cache_by_default", 1);/* Procedural user defined storage handler functions */$__cache = array();function get_hash($host_info, $port, $user, $db, $query) { global $__cache; printf("\t%s(%d)\n", __FUNCTION__, func_num_args()); return md5(sprintf("%s%s%s%s%s", $host_info, $port, $user, $db, $query));}function find_query_in_cache($key) { global $__cache; printf("\t%s(%d)\n", __FUNCTION__, func_num_args()); if (isset($__cache[$key])) { $tmp = $__cache[$key]; if ($tmp["valid_until"] < time()) { unset($__cache[$key]); $ret = NULL; } else { $ret = $__cache[$key]["data"]; } } else { $ret = NULL; } return $ret;}function return_to_cache($key) { /* Called on cache hit after cached data has been processed, may be used for reference counting */ printf("\t%s(%d)\n", __FUNCTION__, func_num_args());}function add_query_to_cache_if_not_exists($key, $data, $ttl, $run_time, $store_time,$row_count) {global $__cache; printf("\t%s(%d)\n", __FUNCTION__, func_num_args()); $__cache[$key] = array( "data"   => $data, "row_count"  => $row_count, "valid_until" => time() + $ttl, "hits"   => 0, "run_time"   => $run_time, "store_time" => $store_time, "cached_run_times"   => array(), "cached_store_times" => array(), ); return TRUE;}function query_is_select($query) { printf("\t%s('%s'): ", __FUNCTION__, $query); $ret = FALSE; if (stristr($query, "SELECT") !== FALSE) { /* cache for 5 seconds */ $ret = 5; } printf("%s\n", (FALSE === $ret) ? "FALSE" : $ret); return $ret;}function update_query_run_time_stats($key, $run_time, $store_time) { global $__cache; printf("\t%s(%d)\n", __FUNCTION__, func_num_args()); if (isset($__cache[$key])) { $__cache[$key]['hits']++; $__cache[$key]["cached_run_times"][] = $run_time; $__cache[$key]["cached_store_times"][] = $store_time; }}function get_stats($key = NULL) { global $__cache; printf("\t%s(%d)\n", __FUNCTION__, func_num_args()); if ($key && isset($__cache[$key])) { $stats = $__cache[$key]; } else { $stats = array(); foreach ($__cache as $key => $details) { $stats[$key] = array(   'hits'  => $details['hits'],   'bytes' => strlen($details['data']),   'uncached_run_time' => $details['run_time'],   'cached_run_time'   => (count($details['cached_run_times']))  ? array_sum($details['cached_run_times']) /   count($details['cached_run_times'])  : 0, ); } } return $stats;}function clear_cache() { global $__cache; printf("\t%s(%d)\n", __FUNCTION__, func_num_args()); $__cache = array(); return TRUE;}/* Install procedural user-defined storage handler */if (!mysqlnd_qc_set_user_handlers("get_hash", "find_query_in_cache", "return_to_cache", "add_query_to_cache_if_not_exists", "query_is_select", "update_query_run_time_stats", "get_stats", "clear_cache")) {  printf("Failed to install user-defined storage handler\n");}/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");printf("\nCache put/cache miss\n");$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();/* Delete record to verify we get our data from the cache */$mysqli->query("DELETE FROM test WHERE id = 1");printf("\nCache hit\n");$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();printf("\nDisplay cache statistics\n");var_dump(mysqlnd_qc_get_cache_info());printf("\nFlushing cache, cache put/cache miss");var_dump(mysqlnd_qc_clear_cache());$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();?> 

The above examples will output something similar to:

 query_is_select('DROP TABLE IF EXISTS test'): FALSE query_is_select('CREATE TABLE test(id INT)'): FALSE query_is_select('INSERT INTO test(id) VALUES (1), (2)'): FALSECache put/cache miss query_is_select('SELECT id FROM test WHERE id = 1'): 5 get_hash(5) find_query_in_cache(1) add_query_to_cache_if_not_exists(6)array(1) {  ["id"]=>  string(1) "1"} query_is_select('DELETE FROM test WHERE id = 1'): FALSECache hit query_is_select('SELECT id FROM test WHERE id = 1'): 5 get_hash(5) find_query_in_cache(1) return_to_cache(1) update_query_run_time_stats(3)array(1) {  ["id"]=>  string(1) "1"}Display cache statistics get_stats(0)array(4) {  ["num_entries"]=>  int(1)  ["handler"]=>  string(4) "user"  ["handler_version"]=>  string(5) "1.0.0"  ["data"]=>  array(1) { ["18683c177dc89bb352b29965d112fdaa"]=> array(4) {  ["hits"]=>  int(1)  ["bytes"]=>  int(71)  ["uncached_run_time"]=>  int(398)  ["cached_run_time"]=>  int(4) }  }}Flushing cache, cache put/cache miss clear_cache(0)bool(true) query_is_select('SELECT id FROM test WHERE id = 1'): 5 get_hash(5) find_query_in_cache(1) add_query_to_cache_if_not_exists(6)NULL

22.9.7.5. Installing/Configuring

Copyright 1997-2012 the PHP Documentation Group.

22.9.7.5.1. Requirements

Copyright 1997-2012 the PHP Documentation Group.

PHP 5.3.3 or a newer version of PHP 5.3. PHP 5.4.0 is not yet supported.

PECL/mysqlnd_qc is a mysqlnd plugin. It plugs into the mysqlnd library. To use you plugin with a PHP MySQL extension (mysqli, mysql, PDO_MYSQL) it is necessary to enable use of the mysqlnd library by the PHP MySQL extension in question. Please refer to the extensions manual sections for details.

For using APC storage handler: APC 3.1.3p1-beta or newer.

For using MEMCACHE storage handler: libmemcache 0.38 or newer.

For using sqlite storage handler: sqlite3 bundled with PHP.

22.9.7.5.2. Installation

Copyright 1997-2012 the PHP Documentation Group.

This PECL extension is not bundled with PHP.

Information for installing this PECL extension may be found in the manual chapter titled Installation of PECL extensions. Additional information such as new releases, downloads, source files, maintainer information, and a CHANGELOG, can be located here: http://pecl.php.net/package/mysqlnd_qc

A DLL for this PECL extension is currently unavailable. See also the building on Windows section.

22.9.7.5.3. Runtime Configuration

Copyright 1997-2012 the PHP Documentation Group.

The behaviour of these functions is affected by settings in php.ini.

Table 22.73. mysqlnd_qc Configure Options

NameDefaultChangeableChangelog
mysqlnd_qc.enable_qc1PHP_INI_SYSTEM 
mysqlnd_qc.ttl30PHP_INI_ALL 
mysqlnd_qc.cache_by_default0PHP_INI_ALL 
mysqlnd_qc.cache_no_table0PHP_INI_ALL 
mysqlnd_qc.use_request_time0PHP_INI_ALL 
mysqlnd_qc.time_statistics1PHP_INI_ALL 
mysqlnd_qc.collect_statistics0PHP_INI_ALL 
mysqlnd_qc.collect_statistics_log_file/tmp/mysqlnd_qc.statsPHP_INI_SYSTEM 
mysqlnd_qc.collect_query_trace0PHP_INI_SYSTEM 
mysqlnd_qc.query_trace_bt_depth3PHP_INI_SYSTEM 
mysqlnd_qc.collect_normalized_query_trace0PHP_INI_SYSTEM 
mysqlnd_qc.ignore_sql_comments1PHP_INI_ALL 
mysqlnd_qc.slam_defense0PHP_INI_SYSTEM 
mysqlnd_qc.slam_defense_ttl30PHP_INI_SYSTEM 
mysqlnd_qc.std_data_copy0PHP_INI_SYSTEM 
mysqlnd_qc.apc_prefixqc_PHP_INI_ALL 
mysqlnd_qc.memc_server127.0.0.1PHP_INI_ALL 
mysqlnd_qc.memc_port11211PHP_INI_ALL 
mysqlnd_qc.sqlite_data_file:memory:PHP_INI_ALL 

Here's a short explanation of the configuration directives.

mysqlnd_qc.enable_qc integer

Enables or disables the plugin. If disabled the extension will not plug into mysqlnd to proxy internal mysqlnd C API calls.

mysqlnd_qc.ttl integer

Default Time-to-Live (TTL) for cache entries in seconds.

mysqlnd_qc.cache_by_default integer

Cache all queries regardless if they begin with the SQL hint that enables caching of a query or not. Storage handler cannot overrule the setting. It is evaluated by the core of the plugin.

mysqlnd_qc.cache_no_table integer

Whether to cache queries with no table name in any of columns meta data of their result set, for example, SELECT SLEEP(1), SELECT NOW(), SELECT SUBSTRING().

mysqlnd_qc.use_request_time integer

Use PHP global request time to avoid gettimeofday() system calls? If using APC storage handler it should be set to the value of apc.use_request_time , if not warnings will be generated.

mysqlnd_qc.time_statistics integer

Collect run time and store time statistics using gettimeofday() system call? Data will be collected only if you also set mysqlnd_qc.collect_statistics = 1,

mysqlnd_qc.collect_statistics integer

Collect statistics for mysqlnd_qc_get_core_stats? Does not influence storage handler statistics! Handler statistics can be an integral part of the handler internal storage format. Thereofore, collection of some handler statistics cannot be disabled.

mysqlnd_qc.collect_statistics-log-file integer

If mysqlnd_qc.collect_statistics and mysqlnd_qc.collect_statistics_log_file are set, the plugin will dump statistics into the specified log file at every 10th web request during PHP request shutdown. The log file needs to be writable by the web server user.

Since 1.1.0.

mysqlnd_qc.collect_query_trace integer

Collect query back traces?

mysqlnd_qc.query_trace_bt_depth integer

Maximum depth/level of a query code backtrace.

mysqlnd_qc.ignore_sql_comments integer

Whether to remove SQL comments from a query string before hashing it to generate a cache key. Disable if you do not want two statemts such as SELECT /*my_source_ip=123*/ id FROM test and SELECT /*my_source_ip=456*/ id FROM test to refer to the same cache entry.

Since 1.1.0.

mysqlnd_qc.slam_defense integer

Activates handler based slam defense (cache stampeding protection) if available. Supported by Default and APC storage handler

mysqlnd_qc.slam_defense_ttl integer

TTL for stale cache entries which are served while another client updates the entries. Supported by APC storage handler.

mysqlnd_qc.collect_normalized_query_trace integer

Collect aggregated normalized query traces? The setting has no effect by default. You compile the extension using the define NORM_QUERY_TRACE_LOG to make use of the setting.

mysqlnd_qc.std_data_copy integer

Default storage handler: copy cached wire data? EXPERIMENTAL � use default setting!

mysqlnd_qc.apc_prefix string

The APC storage handler stores data in the APC user cache. The setting sets a prefix to be used for cache entries.

mysqlnd_qc.memc_server string

MEMCACHE storage handler: memcache server host.

mysqlnd_qc.memc_port integer

MEMCACHE storage handler: memcached server port.

mysqlnd_qc.sqlite_data_file string

sqlite storage handler: data file. Any setting but :memory: may be of little practical value.

22.9.7.6. Predefined Constants

Copyright 1997-2012 the PHP Documentation Group.

The constants below are defined by this extension, andwill only be available when the extension has eitherbeen compiled into PHP or dynamically loaded at runtime.

SQL hint related

Example 22.306. Using SQL hint constants

The query cache is controlled by SQL hints. SQL hints are used to enable and disable caching. SQL hints can be used to set the TTL of a query.

The SQL hints recognized by the query cache can be manually changed at compile time. This makes it possible to use mysqlnd_qc in environments in which the default SQL hints are already taken and interpreted by other systems. Therefore it is recommended to use the SQL hint string constants instead of manually adding the default SQL hints to the query string.

<?php/* Use constants for maximum portability */$query = "/*" . MYSQLND_QC_ENABLE_SWITCH . "*/SELECT id FROM test";/* Valid but less portable: default TTL */$query = "/*qc=on*/SELECT id FROM test";/* Valid but less portable: per statement TTL */$query = "/*qc=on*//*qc_ttl=5*/SELECT id FROM test";printf("MYSQLND_QC_ENABLE_SWITCH: %s\n", MYSQLND_QC_ENABLE_SWITCH);printf("MYSQLND_QC_DISABLE_SWITCH: %s\n", MYSQLND_QC_DISABLE_SWITCH);printf("MYSQLND_QC_TTL_SWITCH: %s\n", MYSQLND_QC_TTL_SWITCH);?>   

The above examples will output:

MYSQLND_QC_ENABLE_SWITCH: qc=onMYSQLND_QC_DISABLE_SWITCH: qc=offMYSQLND_QC_TTL_SWITCH: qc_ttl=

MYSQLND_QC_ENABLE_SWITCH (string)
SQL hint used to enable caching of a query.
MYSQLND_QC_DISABLE_SWITCH (string)
SQL hint used to disable caching of a query if mysqlnd_qc.cache_by_default = 1.
MYSQLND_QC_TTL_SWITCH (string)
SQL hint used to set the TTL of a result set.
MYSQLND_QC_SERVER_ID_SWITCH (string)

This SQL hint should not be used in general.

It is needed by PECL/mysqlnd_ms to group cache entries for one statement but originating from different physical connections. If the hint is used connection settings such as user, hostname and charset are not considered for generating a cache key of a query. Instead the given value and the query string are used as input to the hashing function that generates the key.

PECL/mysqlnd_ms may, if instructed, cache results from MySQL Replication slaves. Because it can hold many connections to the slave the cache key shall not be formed from the user, hostname or other settings that may vary for the various slave connections. Instead, PECL/mysqlnd_ms provides an identifier which refers to the group of slave connections that shall be enabled to share cache entries no matter which physical slave connection was to generate the cache entry.

Use of this feature outside of PECL/mysqlnd_ms is not recommended.

mysqlnd_qc_set_cache_condition related

Example 22.307. Example mysqlnd_qc_set_cache_conditionusage

The function mysqlnd_qc_set_cache_condition allows setting conditions for automatic caching of statements which don't begin with the SQL hints necessary to manually enable caching.

<?php/* Cache all accesses to tables with the name "new%" in schema/database "db_example" for 1 second */if (!mysqlnd_qc_set_cache_condition(MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN, "db_example.new%", 1)) {  die("Failed to set cache condition!");}$mysqli = new mysqli("host", "user", "password", "db_example", "port");/* cached although no SQL hint given  */$mysqli->query("SELECT id, title FROM news");$pdo_mysql = new PDO("mysql:host=host;dbname=db_example;port=port", "user", "password");/* not cached: no SQL hint, no pattern match */$pdo_mysql->query("SELECT id, title FROM latest_news");/* cached: TTL 1 second, pattern match */$pdo_mysql->query("SELECT id, title FROM news");?>

MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN (int)
Used as a parameter of mysqlnd_qc_set_cache_condition to set conditions for schema based automatic caching.

22.9.7.7. mysqlnd_qc Functions

Copyright 1997-2012 the PHP Documentation Group.

22.9.7.7.1. mysqlnd_qc_clear_cache

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_clear_cache

    Flush all cache contents

Description

bool mysqlnd_qc_clear_cache();

Flush all cache contents.

Flushing the cache is a storage handler responsibility. All built-in storage handler but the memcache storage handler support flushing the cache. The memcache storage handler cannot flush its cache contents.

User-defined storage handler may or may not support the operation.

Parameters

This function has no parameters.

Return Values

Returns TRUE on success or FALSE on failure.

A return value of FALSE indicates that flushing all cache contents has failed or the operation is not supported by the active storage handler. Applications must not expect that calling the function will always flush the cache.

22.9.7.7.2. mysqlnd_qc_get_available_handlers

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_get_available_handlers

    Returns a list of available storage handler

Description

array mysqlnd_qc_get_available_handlers();

Which storage are available depends on the compile time configuration of the query cache plugin. The default storage handler is always available. All other storage handler must be enabled explicitly when building the extension.

Parameters

This function has no parameters.

Return Values

Returns an array of available built-in storage handler. For each storage handler the version number and version string is given.

Examples

Example 22.308. mysqlnd_qc_get_available_handlersexample

<?phpvar_dump(mysqlnd_qc_get_available_handlers());?>   

The above examples will output:

array(5) {  ["default"]=>  array(2) { ["version"]=> string(5) "1.0.0" ["version_number"]=> int(100000)  }  ["user"]=>  array(2) { ["version"]=> string(5) "1.0.0" ["version_number"]=> int(100000)  }  ["APC"]=>  array(2) { ["version"]=> string(5) "1.0.0" ["version_number"]=> int(100000)  }  ["MEMCACHE"]=>  array(2) { ["version"]=> string(5) "1.0.0" ["version_number"]=> int(100000)  }  ["sqlite"]=>  array(2) { ["version"]=> string(5) "1.0.0" ["version_number"]=> int(100000)  }}

See Also

Installation
mysqlnd_qc_set_storage_handler
22.9.7.7.3. mysqlnd_qc_get_cache_info

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_get_cache_info

    Returns information on the current handler, the number of cache entries and cache entries, if available

Description

array mysqlnd_qc_get_cache_info();

Parameters

This function has no parameters.

Return Values

Returns information on the current handler, the number of cache entries and cache entries, if available. If and what data will be returned for the cache entries is subject to the active storage handler. Storage handler are free to return any data. Storage handler are recommended to return at least the data provided by the default handler, if technically possible.

The scope of the information is the PHP process. Dependng on the PHP deployment model a process may serve one or more web requests.

Values are aggregated for all cache activities on a per storage handler basis. It is not possible to tell how much queries originating from mysqli, PDO_MySQL or mysql.API calls have contributed to the aggregated data values. Use mysqlnd_qc_get_core_stats to get timing data aggregated for all storage handlers.

Array of cache information

handler string

The active storage handler.

All storage handler. Since 1.0.0.

handler_version string

The version of the active storage handler.

All storage handler. Since 1.0.0.

num_entries int

The number of cache entries. The value depends on the storage handler in use.

The default, APC and SQLite storage handler provide the actual number of cache entries.

The MEMCACHE storage handler always returns 0. MEMCACHE does not support counting the number of cache entries.

If a user defined handler is used, the number of entries of the data property is reported.

Since 1.0.0.

data array

The version of the active storage handler.

Additional storage handler dependent data on the cache entries. Storage handler are requested to provide similar and comparable information. A user defined storage handler is free to return any data.

Since 1.0.0.

The following information is provided by the default storage handler for the data property.

The data property holds a hash. The hash is indexed by the internal cache entry identifier of the storage handler. The cache entry identifier is human-readable and contains the query string leading to the cache entry. Please, see also the example below. The following data is given for every cache entry.

statistics array

Statistics of the cache entry.

Since 1.0.0.

PropertyDescriptionVersion
rowsNumber of rows of the cached result set.Since 1.0.0.
stored_sizeThe size of the cached result set in bytes. This is the size of the payload. The value is not suited for calculating the total memory consumption of all cache entries including the administrative overhead of the cache entries.Since 1.0.0.
cache_hitsHow often the cached entry has been returned.Since 1.0.0.
run_timeRun time of the statement to which the cache entry belongs. This is the run time of the uncached statement. It is the time between sending the statement to MySQL receiving a reply from MySQL. Run time saved by using the query cache plugin can be calculated like this: cache_hits * ((run_time - avg_run_time) + (store_time - avg_store_time)).Since 1.0.0.
store_timeStore time of the statements result set to which the cache entry belongs. This is the time it took to fetch and store the results of the uncached statement.Since 1.0.0.
min_run_timeMinimum run time of the cached statement. How long it took to find the statement in the cache.Since 1.0.0.
min_store_timeMinimum store time of the cached statement. The time taken for fetching the cached result set from the storagemedium and decodingSince 1.0.0.
avg_run_timeAverage run time of the cached statement.Since 1.0.0.
avg_store_timeAverage store time of the cached statement.Since 1.0.0.
max_run_timeAverage run time of the cached statement.Since 1.0.0.
max_store_timeAverage store time of the cached statement.Since 1.0.0.
valid_untilTimestamp when the cache entry expires.Since 1.1.0.
metadata array

Metadata of the cache entry. This is the metadata provided by MySQL together with the result set of the statement in question. Different versions of the MySQL server may return different metadata. Unlike with some of the PHP MySQL extensions no attempt is made to hide MySQL server version dependencies and version details from the caller. Please, refer to the MySQL C API documentation that belongs to the MySQL server in use for further details.

The metadata list contains one entry for every column.

Since 1.0.0.

PropertyDescriptionVersion
nameThe field name. Depending on the MySQL version this may be the fields alias name.Since 1.0.0.
org_nameThe field name.Since 1.0.0.
tableThe table name. If an alias name was used for the table, this usually holds the alias name.Since 1.0.0.
org_tableThe table name.Since 1.0.0.
dbThe database/schema name.Since 1.0.0.
max_lengthThe maximum width of the field. Details may vary by MySQL server version.Since 1.0.0.
lengthThe width of the field. Details may vary by MySQL server version.Since 1.0.0.
typeThe data type of the field. Details may vary by the MySQL server in use. This is the MySQL C API type constants value. It is recommended to use type constants provided by the mysqli extension to test for its meaning. You should not test for certain type values bycomparing with certain numbers.Since 1.0.0.

The APC storage handler returns the same information for the data property but no metadata. The metadata of a cache entry is set to NULL.

The MEMCACHE storage handler does not fill the data property. Statistics are not available on a per cache entry basis with the MEMCACHE storage handler.

A user defined storage handler is free to provide any data.

Examples

Example 22.309. mysqlnd_qc_get_cache_infoexample

The example shows the output from the built-in default storage handler. Other storage handler may report different data.

<?php/* Populate the cache, e.g. using mysqli */$mysqli = new mysqli("host", "user", "password", "schema");$mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/SELECT id FROM test");/* Display cache information */var_dump(mysqlnd_qc_get_cache_info());?>   

The above examples will output:

array(4) { ["num_entries"]=> int(1) ["handler"]=> string(7) "default" ["handler_version"]=> string(5) "1.0.0" ["data"]=> array(1) {   ["Localhost via UNIX socket 3306 user schema|/*qc=on*/SELECT id FROM test"]=>   array(2) { ["statistics"]=> array(11) {   ["rows"]=>   int(6)   ["stored_size"]=>   int(101)   ["cache_hits"]=>   int(0)   ["run_time"]=>   int(471)   ["store_time"]=>   int(27)   ["min_run_time"]=>   int(0)   ["max_run_time"]=>   int(0)   ["min_store_time"]=>   int(0)   ["max_store_time"]=>   int(0)   ["avg_run_time"]=>   int(0)   ["avg_store_time"]=>   int(0) } ["metadata"]=> array(1) {   [0]=>   array(8) { ["name"]=> string(2) "id" ["orig_name"]=> string(2) "id" ["table"]=> string(4) "test" ["orig_table"]=> string(4) "test" ["db"]=> string(4) "schema" ["max_length"]=> int(1) ["length"]=> int(11) ["type"]=> int(3)   } }   } }}

See Also

mysqlnd_qc_get_core_stats
22.9.7.7.4. mysqlnd_qc_get_core_stats

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_get_core_stats

    Statistics collected by the core of the query cache

Description

array mysqlnd_qc_get_core_stats();

Returns an array of statistics collected by the core of the cache plugin. The same data fields will be reported for any storage handler because the data is collected by the core.

The PHP configuration setting mysqlnd_qc.collect_statistics controls the collection of statistics. The collection of statistics is disabled by default for performance reasons. Disabling the collection of statistics will also disable the collection of time related statistics.

The PHP configuration setting mysqlnd_qc.collect_time_statistics controls the collection of time related statistics.

The scope of the core statistics is the PHP process. Depending on your deployment model a PHP process may handle one or multiple requests.

Statistics are aggregated for all cache entries and all storage handler. It is not possible to tell how much queries originating from mysqli, PDO_MySQL or mysql API calls have contributed to the aggregated data values.

Parameters

This function has no parameters.

Return Values

Array of core statistics

StatisticDescriptionVersion
cache_hitStatement is considered cacheable and cached data has been reused. Statement is considered cacheable and a cache miss happened but the statement got cached by someone else while we process it and thus we can fetch the result from the refreshed cache.Since 1.0.0.
cache_missStatement is considered cacheable...
  • ... and has been added to the cache

  • ... but the PHP configuration directive setting of mysqlnd_qc.cache_no_table = 1 has prevented caching.

  • ... but an unbuffered result set is requested.

  • ... but a buffered result set was empty.

Since 1.0.0.
cache_putStatement is considered cacheable and has been added to the cache. Take care when calculating derived statistics. Storage handler with a storage life time beyond process scope may report cache_put = 0 together with cache_hit > 0, if another process has filled the cache. You may want to use num_entries from mysqlnd_qc_get_cache_info if the handler supports it ( default, APC).Since 1.0.0.
query_should_cacheStatement is considered cacheable based on query string analysis. The statement may or may not be added to the cache. See also cache_put.Since 1.0.0.
query_should_not_cacheStatement is considered not cacheable based on query string analysis.Since 1.0.0.
query_not_cachedStatement is considered not cacheable or it is considered cachable but the storage handler has not returned a hash key for it.Since 1.0.0.
query_could_cacheStatement is considered cacheable...
  • ... and statement has been run without errors

  • ... and meta data shows at least one column in the result set

The statement may or may not be in the cache already. It may or may not be added to the cache later on.
Since 1.0.0.
query_found_in_cacheStatement is considered cacheable and we have found it in the cache but we have not replayed the cached data yet and we have not send the result set to the client yet. This is not considered a cache hit because the client might not fetch the result or the cached data may be faulty.Since 1.0.0.
query_uncached_otherStatement is considered cacheable and it may or may not be in the cache already but either replaying cached data has failed, no result set is available or some other error has happened. 
query_uncached_no_tableStatement has not been cached because the result set has at least one column which has no table name in its meta data. An example of such a query is SELECT SLEEP(1). To cache those statements you have to change default value of the PHP configuration directive mysqlnd_qc.cache_no_table and set mysqlnd_qc.cache_no_table = 1. Often, it is not desired to cache such statements.Since 1.0.0.
query_uncached_use_resultStatement would have been cached if a buffered result set had been used. The situation is also considered as a cache miss and cache_miss will be incremented as well.Since 1.0.0.
query_aggr_run_time_cache_hitAggregated run time (ms) of all cached queries. Cached queries are those which have incremented cache_hit.Since 1.0.0.
query_aggr_run_time_cache_putAggregated run time (ms) of all uncached queries that have been put into the cache. See also cache_put.Since 1.0.0.
query_aggr_run_time_totalAggregated run time (ms) of all uncached and cached queries that have been inspected and executed by the query cache.Since 1.0.0.
query_aggr_store_time_cache_hitAggregated store time (ms) of all cached queries. Cached queries are those which have incremented cache_hit.Since 1.0.0.
query_aggr_store_time_cache_putAggregated store time ( ms) of all uncached queries that have been put into the cache. See also cache_put.Since 1.0.0.
query_aggr_store_time_totalAggregated store time (ms) of all uncached and cached queries that have been inspected and executed by the query cache.Since 1.0.0.
receive_bytes_recordedRecorded incoming network traffic ( bytes) send from MySQL to PHP. The traffic may or may not have been added to the cache. The traffic is the total for all queries regardless if cached or not.Since 1.0.0.
receive_bytes_replayedNetwork traffic replayed during cache. This is the total amount of incoming traffic saved because of the usage of the query cache plugin.Since 1.0.0.
send_bytes_recordedRecorded outgoing network traffic ( bytes) send from MySQL to PHP. The traffic may or may not have been added to the cache. The traffic is the total for all queries regardless if cached or not.Since 1.0.0.
send_bytes_replayedNetwork traffic replayed during cache. This is the total amount of outgoing traffic saved because of the usage of the query cache plugin.Since 1.0.0.
slam_stale_refreshNumber of cache misses which triggered serving stale data until the client causing the cache miss has refreshed the cacheentry.Since 1.0.0.
slam_stale_hitNumber of cache hits while a stale cache entry gets refreshed.Since 1.0.0.

Examples

Example 22.310. mysqlnd_qc_get_core_statsexample

<?php/* Enable collection of statistics - default: disabled */ini_set("mysqlnd_qc.collect_statistics", 1);/* Enable collection of all timing related statistics -default: enabled but overruled by mysqlnd_qc.collect_statistics = 0 */ini_set("mysqlnd_qc.collect_time_statistics", 1);/* Populate the cache, e.g. using mysqli */$mysqli = new mysqli('host', 'user', 'password', 'schema');/* Cache miss and cache put */$mysqli->query("/*qc=on*/SELECT id FROM test");/* Cache hit */$mysqli->query("/*qc=on*/SELECT id FROM test");/* Display core statistics */var_dump(mysqlnd_qc_get_core_stats());?>   

The above examples will output:

array(26) {  ["cache_hit"]=>  string(1) "1"  ["cache_miss"]=>  string(1) "1"  ["cache_put"]=>  string(1) "1"  ["query_should_cache"]=>  string(1) "2"  ["query_should_not_cache"]=>  string(1) "0"  ["query_not_cached"]=>  string(1) "0"  ["query_could_cache"]=>  string(1) "2"  ["query_found_in_cache"]=>  string(1) "1"  ["query_uncached_other"]=>  string(1) "0"  ["query_uncached_no_table"]=>  string(1) "0"  ["query_uncached_no_result"]=>  string(1) "0"  ["query_uncached_use_result"]=>  string(1) "0"  ["query_aggr_run_time_cache_hit"]=>  string(1) "4"  ["query_aggr_run_time_cache_put"]=>  string(3) "395"  ["query_aggr_run_time_total"]=>  string(3) "399"  ["query_aggr_store_time_cache_hit"]=>  string(1) "2"  ["query_aggr_store_time_cache_put"]=>  string(1) "8"  ["query_aggr_store_time_total"]=>  string(2) "10"  ["receive_bytes_recorded"]=>  string(2) "65"  ["receive_bytes_replayed"]=>  string(2) "65"  ["send_bytes_recorded"]=>  string(2) "29"  ["send_bytes_replayed"]=>  string(2) "29"  ["slam_stale_refresh"]=>  string(1) "0"  ["slam_stale_hit"]=>  string(1) "0"  ["request_counter"]=>  int(1)  ["process_hash"]=>  int(3547549858)}

See Also

Runtime configuration
mysqlnd_qc.collect_statistics
mysqlnd_qc.time_statistics
mysqlnd_qc_get_cache_info
22.9.7.7.5. mysqlnd_qc_get_normalized_query_trace_log

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_get_normalized_query_trace_log

    Returns a normalized query trace log for each query inspected by the query cache

Description

array mysqlnd_qc_get_normalized_query_trace_log();

Returns a normalized query trace log for each query inspected by the query cache. The collection of the trace log is disabled by default. To collect the trace log you have to set the PHP configuration directive mysqlnd_qc.collect_normalized_query_trace to 1

Entries in the trace log are grouped by the normalized query statement. The normalized query statement is the query statement with all statement parameter values being replaced with a question mark. For example, the two statements SELECT id FROM test WHERE id = 1 and SELECT id FROM test WHERE id = 2 are normalized as SELECT id FROM test WHERE id = ?. Whenever a statement is inspected by the query cache which matches the normalized statement pattern, its statistics are grouped by the normalized statement string.

Parameters

This function has no parameters.

Return Values

An array of query log. Every list entry contains the normalized query stringand further detail information.

KeyDescription
queryNormalized statement string.
occurencesHow many statements have matched the normalized statement string in addition to the one which has created the log entry. The value is zero if a statement has been normalized, its normalized representation has been added to the log but no further queries inspected by PECL/mysqlnd_qc have the same normalized statement string.
eligible_for_cachingWhether the statement could be cached. An statement eligible for caching has not necessarily been cached. It not possible to tell for sure if or how many cached statement have contributed to the aggregated normalized statement log entry. However, comparing the minimum and average run time one can make an educated guess.
avg_run_timeThe average run time of all queries contributing to the query log entry. The run time is the time between sending the query statement to MySQL and receiving an answer from MySQL.
avg_store_timeThe average store time of all queries contributing to the query log entry. The store time is the time needed to fetch a statements result set from the server to the client and, storing it on the client.
min_run_timeThe minimum run time of all queries contributing to the query log entry.
min_store_timeThe minimum store time of all queries contributing to the query log entry.
max_run_timeThe maximum run time of all queries contributing to the query log entry.
max_store_timeThe maximum store time of all queries contributing to the query logentry.

Examples

Example 22.311. mysqlnd_qc_get_normalized_query_trace_logexample

mysqlnd_qc.collect_normalized_query_trace=1   
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");/* not cached */$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();/* cache put */$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 2");var_dump($res->fetch_assoc());$res->free();/* cache hit */$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 2");var_dump($res->fetch_assoc());$res->free();var_dump(mysqlnd_qc_get_normalized_query_trace_log());?>   

The above examples will output:

array(1) {  ["id"]=>  string(1) "1"}array(1) {  ["id"]=>  string(1) "2"}array(1) {  ["id"]=>  string(1) "2"}array(4) {  [0]=>  array(9) { ["query"]=> string(25) "DROP TABLE IF EXISTS test" ["occurences"]=> int(0) ["eligible_for_caching"]=> bool(false) ["avg_run_time"]=> int(0) ["min_run_time"]=> int(0) ["max_run_time"]=> int(0) ["avg_store_time"]=> int(0) ["min_store_time"]=> int(0) ["max_store_time"]=> int(0)  }  [1]=>  array(9) { ["query"]=> string(27) "CREATE TABLE test (id INT )" ["occurences"]=> int(0) ["eligible_for_caching"]=> bool(false) ["avg_run_time"]=> int(0) ["min_run_time"]=> int(0) ["max_run_time"]=> int(0) ["avg_store_time"]=> int(0) ["min_store_time"]=> int(0) ["max_store_time"]=> int(0)  }  [2]=>  array(9) { ["query"]=> string(40) "INSERT INTO test (id ) VALUES (? ), (? )" ["occurences"]=> int(0) ["eligible_for_caching"]=> bool(false) ["avg_run_time"]=> int(0) ["min_run_time"]=> int(0) ["max_run_time"]=> int(0) ["avg_store_time"]=> int(0) ["min_store_time"]=> int(0) ["max_store_time"]=> int(0)  }  [3]=>  array(9) { ["query"]=> string(31) "SELECT id FROM test WHERE id =?" ["occurences"]=> int(2) ["eligible_for_caching"]=> bool(true) ["avg_run_time"]=> int(159) ["min_run_time"]=> int(12) ["max_run_time"]=> int(307) ["avg_store_time"]=> int(10) ["min_store_time"]=> int(8) ["max_store_time"]=> int(13)  }}

See Also

Runtime configuration
mysqlnd_qc.collect_normalized_query_trace
mysqlnd_qc.time_statistics
mysqlnd_qc_get_query_trace_log
22.9.7.7.6. mysqlnd_qc_get_query_trace_log

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_get_query_trace_log

    Returns a backtrace for each query inspected by the query cache

Description

array mysqlnd_qc_get_query_trace_log();

Returns a backtrace for each query inspected by the query cache. The collection of the backtrace is disabled by default. To collect the backtrace you have to set the PHP configuration directive mysqlnd_qc.collect_query_trace to 1

The maximum depth of the backtrace is limited to the depth set with the PHP configuration directive mysqlnd_qc.query_trace_bt_depth.

Parameters

This function has no parameters.

Return Values

An array of query backtrace. Every list entry contains the query string, a backtrace and further detail information.

KeyDescription
queryQuery string.
originCode backtrace.
run_timeQuery run time in milliseconds. The collection of all times and the necessary gettimeofday system calls can be disabled by setting the PHP configuration directive mysqlnd_qc.time_statistics to 0
store_timeQuery result set store time in milliseconds. The collection of all times and the necessary gettimeofday system calls can be disabled by setting the PHP configuration directive mysqlnd_qc.time_statistics to 0
eligible_for_cachingTRUE if query is cacheable otherwise FALSE .
no_tableTRUE if the query has generated a result set and at least one column from the result set has no table name set in its metadata. This is usually the case with queries which one probably do not want to cache such as SELECT SLEEP(1). By default any such query will not be added to the cache. See also PHP configuration directive mysqlnd_qc.cache_no_table.
was_addedTRUE if the query result has been put into the cache, otherwise FALSE .
was_already_in_cacheTRUE if the query result would have been added to the cache if it was not already in the cache (cache hit). Otherwise FALSE.

Examples

Example 22.312. mysqlnd_qc_get_query_trace_logexample

mysqlnd_qc.collect_query_trace=1   
<?php/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");/* not cached */$res = $mysqli->query("SELECT id FROM test WHERE id = 1");var_dump($res->fetch_assoc());$res->free();/* cache put */$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 2");var_dump($res->fetch_assoc());$res->free();/* cache hit */$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 2");var_dump($res->fetch_assoc());$res->free();var_dump(mysqlnd_qc_get_query_trace_log());?>   

The above examples will output:

array(1) {  ["id"]=>  string(1) "1"}array(1) {  ["id"]=>  string(1) "2"}array(1) {  ["id"]=>  string(1) "2"}array(6) {  [0]=>  array(8) { ["query"]=> string(25) "DROP TABLE IF EXISTS test" ["origin"]=> string(102) "#0 qc.php(4): mysqli->query('DROP TABLE IF E...')#1 {main}" ["run_time"]=> int(0) ["store_time"]=> int(0) ["eligible_for_caching"]=> bool(false) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(false)  }  [1]=>  array(8) { ["query"]=> string(25) "CREATE TABLE test(id INT)" ["origin"]=> string(102) "#0 qc.php(5): mysqli->query('CREATE TABLE te...')#1 {main}" ["run_time"]=> int(0) ["store_time"]=> int(0) ["eligible_for_caching"]=> bool(false) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(false)  }  [2]=>  array(8) { ["query"]=> string(36) "INSERT INTO test(id) VALUES (1), (2)" ["origin"]=> string(102) "#0 qc.php(6): mysqli->query('INSERT INTO tes...')#1 {main}" ["run_time"]=> int(0) ["store_time"]=> int(0) ["eligible_for_caching"]=> bool(false) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(false)  }  [3]=>  array(8) { ["query"]=> string(32) "SELECT id FROM test WHERE id = 1" ["origin"]=> string(102) "#0 qc.php(9): mysqli->query('SELECT id FROM ...')#1 {main}" ["run_time"]=> int(0) ["store_time"]=> int(25) ["eligible_for_caching"]=> bool(false) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(false)  }  [4]=>  array(8) { ["query"]=> string(41) "/*qc=on*/SELECT id FROM test WHERE id = 2" ["origin"]=> string(103) "#0 qc.php(14): mysqli->query('/*qc=on*/SELECT...')#1 {main}" ["run_time"]=> int(311) ["store_time"]=> int(13) ["eligible_for_caching"]=> bool(true) ["no_table"]=> bool(false) ["was_added"]=> bool(true) ["was_already_in_cache"]=> bool(false)  }  [5]=>  array(8) { ["query"]=> string(41) "/*qc=on*/SELECT id FROM test WHERE id = 2" ["origin"]=> string(103) "#0 qc.php(19): mysqli->query('/*qc=on*/SELECT...')#1 {main}" ["run_time"]=> int(13) ["store_time"]=> int(8) ["eligible_for_caching"]=> bool(true) ["no_table"]=> bool(false) ["was_added"]=> bool(false) ["was_already_in_cache"]=> bool(true)  }}

See Also

Runtime configuration
mysqlnd_qc.collect_query_trace
mysqlnd_qc.query_trace_bt_depth
mysqlnd_qc.time_statistics
mysqlnd_qc.cache_no_table
mysqlnd_qc_get_normalized_query_trace_log
22.9.7.7.7. mysqlnd_qc_set_cache_condition

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_set_cache_condition

    Set conditions for automatic caching

Description

bool mysqlnd_qc_set_cache_condition(int condition_type,
mixed condition,
mixed condition_option);

Sets a condition for automatic caching of statements which do not contain the necessary SQL hints to enable caching of them.

Parameters

condition_type

Type of the condition. The only allowed value is MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN .

condition

Parameter for the condition set with condition_type. Parameter type and structure depend on condition_type

If condition_type equals MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN condition must be a string. The string sets a pattern. Statements are cached if table and database meta data entry of their result sets match the pattern. The pattern is checked for a match with the db and org_table meta data entries provided by the underlying MySQL client server library. Please, check the MySQL Reference manual for details about the two entries. The db and org_table values are concatenated with a dot (.) before matched against condition. Pattern matching supports the wildcards % and _. The wildcard % will match one or many arbitrary characters. _ will match one arbitrary character. The escape symbol is backslash.

condition_option

Option for condition. Type and structure depend on condition_type.

If condition_type equals MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN condition_options is the TTL to be used.

Examples

Example 22.313. mysqlnd_qc_set_cache_conditionexample

<?php/* Cache all accesses to tables with the name "new%" in schema/database "db_example"for 1 second */if (!mysqlnd_qc_set_cache_condition(MYSQLND_QC_CONDITION_META_SCHEMA_PATTERN,"db_example.new%", 1)) {  die("Failed to set cache condition!");}$mysqli = new mysqli("host", "user", "password", "db_example", "port");/* cached although no SQL hint given  */$mysqli->query("SELECT id, title FROM news");$pdo_mysql = new PDO("mysql:host=host;dbname=db_example;port=port", "user", "password");/* not cached: no SQL hint, no pattern match */$pdo_mysql->query("SELECT id, title FROM latest_news");/* cached: TTL 1 second, pattern match */$pdo_mysql->query("SELECT id, title FROM news");?>

Return Values

Returns TRUE on success or FALSE on FAILURE.

See Also

Quickstart: pattern based caching
22.9.7.7.8. mysqlnd_qc_set_is_select

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_set_is_select

    Installs a callback which decides whether a statement is cached

Description

mixed mysqlnd_qc_set_is_select(string callback);

Installs a callback which decides whether a statement is cached.

There are several ways of hinting PELC/mysqlnd_qc to cache a query. By default, PECL/mysqlnd_qc attempts to cache a if caching of all statements is enabled or the query string begins with a certain SQL hint. The plugin internally calls a function named is_select() to find out. This internal function can be replaced with a user-defined callback. Then, the user-defined callback is responsible to decide whether the plugin attempts to cache a statement. Because the internal function is replaced with the callback, the callback gains full control. The callback is free to ignore the configuration setting mysqlnd_qc.cache_by_default and SQL hints.

The callback is invoked for every statement inspected by the plugin. It is given the statements string as a parameter. The callback returns FALSE if the statement shall not be cached. It returns TRUE to make the plugin attempt to cache the statements result set, if any. A so-created cache entry is given the default TTL set with the PHP configuration directive mysqlnd_qc.ttl. If a different TTL shall be used, the callback returns a numeric value to be used as the TTL.

The internal is_select function is part of the internal cache storage handler interface. Thus, a user-defined storage handler offers the same capabilities.

Parameters

This function has no parameters.

Return Values

Returns TRUE on success or FALSE on failure.

Examples

Example 22.314. mysqlnd_qc_set_is_selectexample

<?php/* callback which decides if query is cached */function is_select($query) {  static $patterns = array(   /* true - use default from mysqlnd_qc.ttl */   "@SELECT\s+.*\s+FROM\s+test@ismU" => true,   /* 3 - use TTL = 3 seconds */   "@SELECT\s+.*\s+FROM\s+news@ismU" => 3  );  /* check if query does match pattern */  foreach ($patterns as $pattern => $ttl) { if (preg_match($pattern, $query)) {  printf("is_select(%45s): cache\n", $query);  return $ttl; }  }  printf("is_select(%45s): do not cache\n", $query);  return false;}mysqlnd_qc_set_is_select("is_select");/* Connect, create and populate test table */$mysqli = new mysqli("host", "user", "password", "schema");$mysqli->query("DROP TABLE IF EXISTS test");$mysqli->query("CREATE TABLE test(id INT)");$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");/* cache put */$mysqli->query("SELECT id FROM test WHERE id = 1");/* cache hit */$mysqli->query("SELECT id FROM test WHERE id = 1");/* cache put */$mysqli->query("SELECT * FROM test");?>   

The above examples will output:

is_select( DROP TABLE IF EXISTS test): do not cacheis_select( CREATE TABLE test(id INT)): do not cacheis_select( INSERT INTO test(id) VALUES (1), (2), (3)): do not cacheis_select( SELECT id FROM test WHERE id = 1): cacheis_select( SELECT id FROM test WHERE id = 1): cacheis_select(   SELECT * FROM test): cache

See Also

Runtime configuration
mysqlnd_qc.ttl
mysqlnd_qc.cache_by_default
mysqlnd_qc_set_user_handlers
22.9.7.7.9. mysqlnd_qc_set_storage_handler

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_set_storage_handler

    Change current storage handler

Description

bool mysqlnd_qc_set_storage_handler(string handler);

Sets the storage handler used by the query cache. A list of available storage handler can be obtained from mysqlnd_qc_get_available_handlers. Which storage are available depends on the compile time configuration of the query cache plugin. The default storage handler is always available. All other storage handler must be enabled explicitly when building the extension.

Parameters

handler

Handler can be of type string representing the name of a built-in storage handler or an object of type mysqlnd_qc_handler_default. The names of the built-in storage handler are default, APC, MEMCACHE, sqlite.

Return Values

Returns TRUE on success or FALSE on failure.

If changing the storage handler fails a catchable fatal error will be thrown. The query cache cannot operate if the previous storage handler has been shutdown but no new storage handler has been installed.

Examples

Example 22.315. mysqlnd_qc_set_storage_handlerexample

The example shows the output from the built-in default storage handler. Other storage handler may report different data.

<?phpvar_dump(mysqlnd_qc_set_storage_handler("memcache"));if (true === mysqlnd_qc_set_storage_handler("default"))  printf("Default storage handler activated");/* Catchable fatal error */var_dump(mysqlnd_qc_set_storage_handler("unknown"));?>   

The above examples will output:

bool(true)Default storage handler activatedCatchable fatal error: mysqlnd_qc_set_storage_handler(): Unknown handler 'unknown' in (file) on line (line)

See Also

Installation
mysqlnd_qc_get_available_handlers
22.9.7.7.10. mysqlnd_qc_set_user_handlers

Copyright 1997-2012 the PHP Documentation Group.

  • mysqlnd_qc_set_user_handlers

    Sets the callback functions for a user-defined procedural storage handler

Description

bool mysqlnd_qc_set_user_handlers(string get_hash,
string find_query_in_cache,
string return_to_cache,
string add_query_to_cache_if_not_exists,
string query_is_select,
string update_query_run_time_stats,
string get_stats,
string clear_cache);

Sets the callback functions for a user-defined procedural storage handler.

Parameters

get_hash

Name of the user function implementing the storage handler get_hash functionality.

find_query_in_cache

Name of the user function implementing the storage handler find_in_cache functionality.

return_to_cache

Name of the user function implementing the storage handler return_to_cache functionality.

add_query_to_cache_if_not_exists

Name of the user function implementing the storage handler add_query_to_cache_if_not_exists functionality.

query_is_select

Name of the user function implementing the storage handler query_is_select functionality.

update_query_run_time_stats

Name of the user function implementing the storage handler update_query_run_time_stats functionality.

get_stats

Name of the user function implementing the storage handler get_stats functionality.

clear_cache

Name of the user function implementing the storage handler clear_cache functionality.

Return Values

Returns TRUE on success or FALSE on FAILURE.

See Also

Procedural user-defined storage handler example

22.9.7.8. Change History

Copyright 1997-2012 the PHP Documentation Group.

This change history is a high level summary of selected changes that may impact applications and/or break backwards compatibility.

See also the CHANGES file in the source distribution for a complete list of changes.

22.9.7.8.1. PECL/mysqlnd_qc 1.1 series

Copyright 1997-2012 the PHP Documentation Group.

1.1.0

  • Release date: under development
  • Motto/theme: PHP 5.4 compatibility, schema pattern based caching and mysqlnd_ms support

Feature changes

  • APC storage handler update

    • Fix build for APC 3.1.9+
    • Note: Use of the APC storage handler is currently not recommended due to stability issues of APC itself.
  • New PHP configuration directives

  • New constants and SQL hints

  • New function mysqlnd_qc_set_cache_condition for built-in schema pattern based caching. Likely to support a wider range of conditions in the future.

  • Report valid_until timestamp for cache entries of the default handler through mysqlnd_qc_get_cache_info.

  • Include charset number for cache entry hashing. This should prevent serving result sets which have the wrong charset.

    API change: get_hash_key expects new "charsetnr" (int) parameter after "port".

  • API change: changing is_select() signature from bool is_select() to mixed is_select(). Mixed can be either boolean or array(long ttl, string server_id). This is needed by PECL/mysqlnd_ms.

Other

  • Support acting as a cache backend for PECL/mysqlnd_ms 1.3.0-beta or later to transparently replace MySQL Replication slave reads with cache accesses, if the user explicitly allows.

Bug fixes

  • Fixed Bug #59959 (config.m4, wrong library - 64bit memcached handler builds) (Credits: Remi Collet)
22.9.7.8.2. PECL/mysqlnd_qc 1.0 series

Copyright 1997-2012 the PHP Documentation Group.

1.0.1-stable

  • Release date: 12/2010
  • Motto/theme: Prepared statement support

Added support for Prepared statements and unbuffered queries.

1.0.0-beta

  • Release date: 07/2010
  • Motto/theme: TTL-based cache with various storage options (Memcache, APC, SQLite, user-defined)

Initial public release of the transparent TTL-based query result cache. Flexible storage of cached results. Various storage media supported.

Copyright © 1997, 2013, Oracle and/or its affiliates. All rights reserved. Legal Notices
(Sebelumnya) 22.9.4. MySQL Functions (PDO_M ...22.9.8. Mysqlnd user handler p ... (Berikutnya)