built-in query caching for all php mysql extensions/apis
TRANSCRIPT
MySQL native driver for PHP:The query cache plugin
mysqlnd_qc:
The query cache plugin
Ulf Wendel, Andrey HristovMySQL Connectors TeamSun Microsystems
Table of Contents
At a glanceKey Features
Basic Usage
ArchitectureMySQLnd Plugins
Cache Architecture
Storage handler
UsageAdvanced Usage
Configuration
Key Features
Transparent: no user API changessupports ext/mysqli
supports PDO_MYSQL
supports ext/mysql
Invalidation: TTL, customPer query TTL (Time to Live)
custom: user callbacks
Storage handler: build-in, customDefault (Hash), APC, Memcache
custom: user callbacks
Possibly asked questions
Can stale data be served?Sure, it is Time to live (TTL) by default! But you can implement your own invalidation strategy.
Which PHP versions are supported?PHP 5.3.3-dev or newer. At the time of writing the query cache is in prototype stage.
Where can I get it?http://forge.mysql.com/wiki/MySQLnd_Query_Cache_Plugin_for_PHP
Only buffered queries can be cached
ext/mysqlimysqli_query()
mysqli_real_query() + mysqli_store_result()
PDO_MYSQLPDO::query() if PDO::ATTR_EMULATE_PREPARES = 1 (this is the default)
ext/mysqlmysql_query()
Uncachable queries
ext/mysqlimysqli_real_query() + mysqli_use_result()
mysqli_query() + MYSQLI_ASYNC
mysqli_stmt_*()
PDO_MYSQLPDO::query() if PDO::ATTR_EMULATE_PREPARES = 0
ext/mysqlmysql_unbuffered_query()
Benchmarks?
Please run your own!Too many variables, sorry... for now ;-)
Chart compares handler no more
f
Basic Usage
$mysqli = new mysqli($host, $user, $passwd, $db, $port, $socket);;
// Cached: SQL hint used$res = $mysqli->query("/*qc=on*/" . "SELECT id, label FROM test");
var_dump($res->fetch_all(MYSQLI_ASSOC));$res->free();
SQL hint /*qc=on*/ to control caching
// Uncached: no SQL hint$res = $mysqli->query("SELECT id, label FROM test");var_dump($res->fetch_all(MYSQLI_ASSOC));$res->free();
Installation
Download sourcehttp://forge.mysql.com/wiki/MySQLnd_Query_Cache_Plugin_for_PHP
Copy extension into PHP 5.3.3+ source treecp -R query_cache my_php/ext/mysqlnd_qc
Enable query cache and build./buildconf --force
./configure --help | grep mysql
./configure --help | grep qc
make clean && make
Compared to MySQL Server Cache
Different location!Less work for the server
Shorter distance to the app (round trip times)
Scale by client
No server overload
Less sophisticated invalidation (stale data!)
Compared to Memcache
Memcache is no cacheMemcache is a storage medium
Often used for storing cached data
We offer a Memcache storage handler
Application vs. driver based cachingalmost no application changes needed
caching of raw data instead of processed data
Table of Contents
At a glanceKey Features
Basic Usage
ArchitectureMySQLnd Plugins
Cache Architecture
Storage handler
UsageCustomization
Configuration
How PHP connects to MySQL
PHPMySQL ServerLibrary: implements MySQL Client-Server Protocol
PHP API for PHP applicationsMySQL native driver for PHP / MySQL Client Library
Inside PHP (on the C level!)
PHPExtensionsZend EnginePDOext/mysqlext/mysqliSAPI
PDO_MYSQLPDO_XYZ
MySQL Client Library (libmysql) orMySQL native driver for PHP (default as of PHP 5.3)
PHP 5.3.2: mysqlnd plugin interface
ext/*mysql*
ext/*mysql*
PluginMySQL native driver for PHPC plugins operate transparently: no user API changes
Object-orientation in mysqlnd
mysqlnd_connection
connection_methodshostuserpassword...connection_methods
query()store_result()use_result()free_result()...
Inside mysqlnd: objects of data and function pointer
connection_methods
query()store_result()use_result()free_result()...
Plugin
query()store_result()use_result()free_result()...
Plugins as Proxies or Decorators
mysqlnd_connection
connection_methodshostuserpassword...Plugins replace or extend internal mysqlnd objects
Plugins can change everything
Connection methodssending queries, fetching results
metadata access
utility calls
Prepared Statement methodssending queries, fetching results
Network callssend and fetch raw MySQL protocol data
C level support for Plugins
API callsPlugin registration
management of function tables
Piggybacking datavia connection object
via result set object
via statistics hash
Query cache: proxy-style plugin
CacheMySQL
ext/*mysql*ext/*mysql*mysqlndmysqlndCache miss: record wire data, cache hit: replay
Query Cache Plugin
Query Cache: Miss
mysqlndorig. mysqlnd_conn objectmysqlnd_qc objectquery()
Should cache? Yes!
Is cached? No!
Activate data recorder
query()
Send query to MySQL
Deactivate recorder
Cache wire data
Decode data
Fetch reply
Query Cache: Hit
mysqlndmysqlnd_qc objectquery()
Should cache? Yes!
Is cached? Yes!
Fetch data from cache
Decode data
Storage handler responsibilities
StorageScope: request, process, machine, multi-machine
Location: distance to cache
Replacement strategy
Slam defense strategy
Decide what to cacheDetect SELECT statements
Parse SQL-Hints
Extended statisticsStorage statistics, traces, timings
Cache storage handler (I)
Default (Hash)Scope: process (single or multiple requests)
Location: same process
User can flush cache
Handler maintains storage statistics
APCScope: machine (multiple requests)
Location: local
User can flush cache
Handler maintains storage statistics
Cache storage handler (II)
MemcacheScope: can be shared between machines
Location: can be local or remote
User cannot flush cache
No handler statistics
NOPNo operation
Internal and not exposed to PHP land
Cache storage handler (III)
SQLiteScope, if using :memory:: process (single or multiple requests)
Scope, if using file: single (multiple) machine
Location: can be local or remote
User can flush cache
Handler maintains storage statistics
Berkeley DBtheoretically usable via the new
SQLite C API compatibility wrapper
Cache storage handler (IV)
User (procedural and object oriented)It is all up to you!
User (class mysqlnd_qc_handler_default)Default handler behaviour
Can be specialized by user
User can specialize one, many or all functions
See also extra presentation!
Cache Architecture Summary
Transparent from a user perspectiveNo user API changes
Works with all user APIs
Stores raw wire dataPro: Simplicity low risk of bugs!
Con: Client always needs to decode
Storage handlerChoice of life-span and scope
Choice of distance to client
Cache Miss
Client 2...100Client 2...100Client 2...100BTW, plan your cache carefully!
What if a shared cache entry expires?
Client 1Client 2...nCache Hit
MySQL
Client 2...100Client 2...100Client 2...100Client 1Client 2...n
MySQL
Cache Miss
Optimize storage for reuse?
Memory consumption versus peak loads
Client 1Client 2MySQL
Client 2...100Client 2...100Client 2...100Client 1Client 2...n
MySQL
Cache Miss
Cache HitClient 3..n
Table of Contents
At a glanceKey Features
Basic Usage
ArchitectureMySQLnd Plugins
Cache Architecture
Storage handler
UsageAdvanced Usage
Configuration
Customization: user handler
Procedural and OOP interfaces
Control which query gets cached
Control where to store cached data
Implement your own invalidation strategy
Maintain your own statistics
Procedural and OOP user handler
mysqlnd_qc_set_user_handlers()procedural
you must implement all storage handler functions
extending class mysqlnd_qc_handler_defaultobject oriented
customize build-in default handler
no need to spezialize all handler functions
implementing interface mysqlnd_qc_handlerobject oriented
you must implement all storage handler functions
Procedural user storage handler
void mysqlnd_qc_set_user_handlers(
string get_hash_key,
string find_query_in_cache,
string return_to_cache,
string add_query_to_cache_if_not_exists,
string query_is_select,
string update_cache_stats,
string clear_cache
)
Yes, this API may be ugly.
BUT: Prototype!
BUT: See extra presentation for vodoo!
mysqlnd_qc_set_user_handlers()
User storage handler interface (I)
function get_hash($host_info, $port, $user, $db, $query) {/*
returns string */return $key;}
function find($key) { /* returns boolean */ return
$found;}
function return_to_cache($key) { /* void leave empty */}
function add($key, $data, $ttl, $runtime, $store_time, $row_count)
{ /* returns boolean */ return $added_to_cache;
}
User storage handler interface (II)
function query_is_select($query) {/* returns mixed - boolean
false if the query shall not be cached boolean true or double 0 to
use mysqlnd_qc.ttl default double >= 0 to set TTL different from
mysqlnd_qc.ttl */return $to_cache_or_not;}
function update_stats($key, $run_time, $store_time) { /* void data to update your per query cache statistics *//}
function clear_cache() { /* returns boolean */ return $cache_has_been_flushed;}
Object oriented storage handler
implementing interface mysqlnd_qc_handler
extending mysqlnd_qc_handler_default
See also extra presentation!
API calls
mysqlnd_qc_change_handler()
mysqlnd_qc_clear_cache()
mysqlnd_qc_get_cache_info()
mysqlnd_qc_get_core_stats()
mysqlnd_qc_get_handler()
mysqlnd_qc_get_normalized_query_trace_log()
mysqlnd_qc_get_query_trace_log()
mysqlnd_qc_set_user_handlers()
Changing the storage handler
bool mysqlnd_qc_change_handler(string handler)
Changes the storage handler. Returns false if thecurrent handler
cannot be shutdown or the requestedhandler cannot be initialized.
Failing to changethe handler should be considered as a fatal
errorunless the change fails because the requested handleris
unknown.
Procedural user storage handler
void mysqlnd_qc_set_user_handlers(
string get_hash_key,
string find_query_in_cache,
string return_to_cache,
string add_query_to_cache_if_not_exists,
string query_is_select,
string update_cache_stats,
string clear_cache
)
Sets the function names of a user defined storagehandler and
puts them into use.
See also extra presentation!
Available handlers
array mysqlnd_qc_get_handlers()
Returns a list of available handler and their versions. The
handler default, user, the classmyslqnd_qc_handler_default are
always available.apc and memcache will be reported if support
forthose handlers has been enabled at compile time.
Flushing the cache
The function is not supported by the Memcache handler!
bool mysqlnd_qc_clear_cache()
Returns true if the handler supports the operation,and has
flushed the cache.
Cache info and handler statistics
// Run some queries and generate cache hits$res = $mysqli->query("/*qc=1*/" . "SELECT id, label FROM test");var_dump($res->fetch_all(MYSQLI_ASSOC));
C-based handler cache information and statistics
var_dump(mysqlnd_qc_get_cache_info());
array(4) { ["num_entries"]=> int(%d) ["handler"]=> string(7) "default" ["handler_version"]=> string(5) "1.0.0" ["data"]=> array(%d) { ["%s] => array(2) { [statistics] => array(...), [metadata] => array(...) } [, ...]}
Cache hits, time statistics and more
Remember: handler specific statisticsMemcache: no statistics at all
APC: no metadata
If available:num_entries: number of cache entries
[data][key][statistics] : run/store time statistics
[data][key][statistics] : cache hits
[data][key][metadata]: result set meta data
See also extra presentation!
Core statistics
php.ini setting: mysqlnd_qc_collect_statistics = 1
array mysqlnd_qc_get_core_statistics()
Returns a list 20+ statistics collected by the coreof the query
cache plugin, if the PHP configurationsetting
mysqlnd_qc_collect_statistics is set to 1.The statistics are
provided by the core and thereforeavailable with all storage
handlers and whenusing user-defined storage handlers. The
statisticscover cache accesses, failures, network traffic as well
as aggregated run and store times.
Query back trace
php.ini setting: mysqlnd_qc.query_trace = 1
array mysqlnd_qc_get_query_trace_log()
Returns a query back trace for every query that hasbeen inspected by the query cache regardless if thequery ended up being cached or not. The trace tellsyou where a query has been issues (see alsodebug_backtrace()). Together with the back traceyou get run and store times and information on ifthe query has been cached.
Normalized query back trace
mysqlnd_qc.collect_normalized_query_trace = 1
array mysqlnd_qc_get_normalized_query_trace_log()
Similar to mysqlnd_qc_get_query_trace_log() but withSQL statements normalized and aggregated by thenormalized query string. Normalization refers toreplacing actual parameters, for examplein WHERE a > 1, with questionmarks likeWHERE a > ?. WHERE a > ? will match any valuefor ?, for example 1, 2, 'abc' but not otheridentifiers.
Runtime configuration
Runtime configuration (cont.)
Basics
mysqlnd_qc.ttlTime to live in seconds
Handler can overrule setting for individual queries
mysqlnd_qc.cache_by_defaultCache every query, even those without SQL hint?
Evaluated by the core, handler cannot overrule!
mysqlnd_qc.cache_no_tableCache queries with no table name im their meta data, e.g SELECT SLEEP(1)?
Performance
mysqlnd_qc.use_request_timeUse PHP global request time to avoid gettimeofday() system calls?
Pitfall see APC docs on apc.use_request_time
mysqlnd_qc.time_statisticsCollect run time and store time statistics using gettimeofday() system call?
mysqlnd_qc.std_data_copyDefault handler: copy cached wire data?
EXPERIMENTAL use default of 0
Statistics and Slam defense
mysqlnd_qc.collect_statisticsCollect statistics for mysqlnd_qc_get_core_stats()?
mysqlnd_qc.slam_defenseActivates handler based slam defense if available
Query traces
mysqlnd_qc.collect_query_traceCollect query back traces?
mysqlnd_qc.query_trace_bt_depthMaximum back trace depth
mysqlnd_qc.collect_normalized_query_traceCollect aggregated normalized query traces?
APC storage handler
mysqlnd_qc.use_request_time = apc.use_request timeUse the same timer for TTL invalidation
mysqlnd_qc.apc_prefixKey prefix
APC handler stores data in the APC user cache
Users can manipulate the cache entries!
Memcache storage handler
mysqlnd_qc.memc_serverMemcache server host
Cannot be changed at run time
mysqlnd_qc.memc_portMemcache server port
SQLite storage handler
mysqlnd_qc.sqlite_data_fileSQLite data file
You should use SQLite as an in-memory storage
Exported PHP constants
MYSQLND_QC_ENABLE_SWITCHSQL-hint to enable caching, e.g. qc=on
Only this exact string will recognized!
MYSQLND_QC_DISABLE_SWITCHSQL-hint to disable caching, e.g. qc=off
Only this exact string will be recognized!
MYSQLND_QC_TTL_SWITCHSQL-hint for setting per query TTL, e.g. qc_ttl=
All constants can be changed as compile time!
Exported PHP classes
class mysqlnd_qc_handler_default { public function init() {} public function is_select(...) {} public function get_hash_key(...) {} public function return_to_cache(...) {} public function add_to_cache(...) {} public function find_in_cache(...) {} public function update_cache_stats(...) {} public function get_stats(...) {} public function clear_cache() {} public function shutdown() {}}
Exported PHP interfaces
interface mysqlnd_qc_handler { public function is_select(...) {} public function get_hash_key(...) {} public function return_to_cache(...) {} public function add_to_cache(...) {} public function find_in_cache(...) {} public function update_cache_stats(...) {} public function get_stats(...) {} public function clear_cache() {}}
PresentationsA query cache plugin - this is what you look at
;-)
Query cache plugin benchmark impressions
Dig deeper with QC statistics
Developing user storage handler
Further reading
The End
Feedback: [email protected]
The End
Feedback:
[email protected],
[email protected]
Sun Microsystems, Inc.
Page
Click to edit the title text format
Click to edit the outline text formatSecond Outline Level
Click to edit the notes format
Page
Click to edit the title text format
Presenters NamePresenters TitlePresenters Company
Click to edit the notes format
Page
DefaultAPCMEMCACHE
Config A1008792
Config B988585
Config C998687
PHP ini settingScopeDefaultmysqlnd_qc.ttlINI_ALL30mysqlnd_qc.cache_by_defaultINI_ALL0mysqlnd_qc.cache_no_tableINI_ALL0mysqlnd_qc.use_request_timeINI_ALL0mysqlnd_qc.time_statisticsINI_ALL1mysqlnd_qc.std_data_copyINI_SYSTEM0mysqlnd_qc.apc_prefixINI_ALLqc_mysqlnd_qc.memc_serverINI_ALL127.0.0.1mysqlnd_qc.memc_portINI_ALL11211
???Page ??? (???)26.11.2009, 17:18:45Page / PHP ini settingScopeDefaultmysqlnd_qc.collect_statisticsINI_ALL0 mysqlnd_qc.slam_defenseINI_SYSTEM0 mysqlnd_qc.query_traceINI_SYSTEM0 mysqlnd_qc_query_trace_bt_depthINI_SYSTEM3 mysqlnd_qc.collect_normalized_query_traceINI_SYSTEM0mysqlnd_qc.sqlite_data_fileINI_ALL:memory:
???Page ??? (???)16.06.2010, 13:50:53Page /