<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Measuring cache efficiency</title> </head> <body><div class="manualnavbar" style="text-align: center;"> <div class="prev" style="text-align: left; float: left;"><a href="mysqlnd-qc.cache-candidates.html">Finding cache candidates</a></div> <div class="next" style="text-align: right; float: right;"><a href="mysqlnd-qc.set-user-handlers.html">Beyond TTL: user-defined storage</a></div> <div class="up"><a href="mysqlnd-qc.quickstart.html">Quickstart and Examples</a></div> <div class="home"><a href="index.html">PHP Manual</a></div> </div><hr /><div id="mysqlnd-qc.cache-efficiency" class="section"> <h2 class="title">Measuring cache efficiency</h2> <p class="para"> PECL/mysqlnd_qc offers three ways to measure the cache efficiency. The function <span class="function"><a href="function.mysqlnd-qc-get-normalized-query-trace-log.html" class="function">mysqlnd_qc_get_normalized_query_trace_log()</a></span> returns statistics aggregated by the normalized query string, <span class="function"><a href="function.mysqlnd-qc-get-cache-info.html" class="function">mysqlnd_qc_get_cache_info()</a></span> 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 <span class="function"><a href="function.mysqlnd-qc-get-core-stats.html" class="function">mysqlnd_qc_get_core_stats()</a></span>. </p> <p class="para"> The functions <span class="function"><a href="function.mysqlnd-qc-get-normalized-query-trace-log.html" class="function">mysqlnd_qc_get_normalized_query_trace_log()</a></span> and <span class="function"><a href="function.mysqlnd-qc-get-core-stats.html" class="function">mysqlnd_qc_get_core_stats()</a></span> 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 <a href="mysqlnd-qc.configuration.html#ini.mysqlnd-qc.time-statistics" class="link">mysqlnd_qc.time_statistics</a> 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. </p> <p class="para"> <div class="example" id="example-1856"> <p><strong>Example #1 Collecting statistics data with the <em>mysqlnd_qc.time_statistics</em> ini setting</strong></p> <div class="example-contents"> <div class="inicode"><pre class="inicode">mysqlnd_qc.enable_qc=1 mysqlnd_qc.collect_statistics=1</pre> </div> </div> <div class="example-contents"> <div class="phpcode"><code><span style="color: #000000"> <span style="color: #0000BB"><?php<br /></span><span style="color: #FF8000">/* connect to MySQL */<br /></span><span style="color: #0000BB">$mysqli </span><span style="color: #007700">= new </span><span style="color: #0000BB">mysqli</span><span style="color: #007700">(</span><span style="color: #DD0000">"host"</span><span style="color: #007700">, </span><span style="color: #DD0000">"user"</span><span style="color: #007700">, </span><span style="color: #DD0000">"password"</span><span style="color: #007700">, </span><span style="color: #DD0000">"schema"</span><span style="color: #007700">, </span><span style="color: #DD0000">"port"</span><span style="color: #007700">, </span><span style="color: #DD0000">"socket"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"DROP TABLE IF EXISTS test"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"CREATE TABLE test(id INT)"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"INSERT INTO test(id) VALUES (1), (2), (3)"</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">/* dummy queries */<br /></span><span style="color: #007700">for (</span><span style="color: #0000BB">$i </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">; </span><span style="color: #0000BB">$i </span><span style="color: #007700"><= </span><span style="color: #0000BB">4</span><span style="color: #007700">; </span><span style="color: #0000BB">$i</span><span style="color: #007700">++) {<br /> </span><span style="color: #0000BB">$query </span><span style="color: #007700">= </span><span style="color: #0000BB">sprintf</span><span style="color: #007700">(</span><span style="color: #DD0000">"/*%s*/SELECT id FROM test WHERE id = %d"</span><span style="color: #007700">, </span><span style="color: #0000BB">MYSQLND_QC_ENABLE_SWITCH</span><span style="color: #007700">, </span><span style="color: #0000BB">$i </span><span style="color: #007700">% </span><span style="color: #0000BB">2</span><span style="color: #007700">);<br /> </span><span style="color: #0000BB">$res </span><span style="color: #007700">= </span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /> <br /> </span><span style="color: #0000BB">$res</span><span style="color: #007700">-></span><span style="color: #0000BB">free</span><span style="color: #007700">();<br />}<br /><br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">mysqlnd_qc_get_core_stats</span><span style="color: #007700">());<br /></span><span style="color: #0000BB">?></span> </span> </code></div> </div> <div class="example-contents"><p>The above examples will output something similar to:</p></div> <div class="example-contents screen"> <div class="cdata"><pre> 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) } </pre></div> </div> </div> </p> <p class="para"> For a quick overview, call <span class="function"><a href="function.mysqlnd-qc-get-core-stats.html" class="function">mysqlnd_qc_get_core_stats()</a></span>. 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. </p> <p class="para"> 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 <span class="function"><a href="function.mysqlnd-qc-get-cache-info.html" class="function">mysqlnd_qc_get_cache_info()</a></span> function. Please note, that the information returned depends on the storage handler. Values are aggregated on a per process basis. </p> <p class="para"> <div class="example" id="example-1857"> <p><strong>Example #2 Example <span class="function"><a href="function.mysqlnd-qc-get-cache-info.html" class="function">mysqlnd_qc_get_cache_info()</a></span> usage</strong></p> <div class="example-contents"> <div class="inicode"><pre class="inicode">mysqlnd_qc.enable_qc=1</pre> </div> </div> <div class="example-contents"> <div class="phpcode"><code><span style="color: #000000"> <span style="color: #0000BB"><?php<br /></span><span style="color: #FF8000">/* connect to MySQL */<br /></span><span style="color: #0000BB">$mysqli </span><span style="color: #007700">= new </span><span style="color: #0000BB">mysqli</span><span style="color: #007700">(</span><span style="color: #DD0000">"host"</span><span style="color: #007700">, </span><span style="color: #DD0000">"user"</span><span style="color: #007700">, </span><span style="color: #DD0000">"password"</span><span style="color: #007700">, </span><span style="color: #DD0000">"schema"</span><span style="color: #007700">, </span><span style="color: #DD0000">"port"</span><span style="color: #007700">, </span><span style="color: #DD0000">"socket"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"DROP TABLE IF EXISTS test"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"CREATE TABLE test(id INT)"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"INSERT INTO test(id) VALUES (1), (2), (3)"</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">/* dummy queries to fill the query trace */<br /></span><span style="color: #007700">for (</span><span style="color: #0000BB">$i </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">; </span><span style="color: #0000BB">$i </span><span style="color: #007700"><= </span><span style="color: #0000BB">4</span><span style="color: #007700">; </span><span style="color: #0000BB">$i</span><span style="color: #007700">++) {<br /> </span><span style="color: #0000BB">$query </span><span style="color: #007700">= </span><span style="color: #0000BB">sprintf</span><span style="color: #007700">(</span><span style="color: #DD0000">"/*%s*/SELECT id FROM test WHERE id = %d"</span><span style="color: #007700">, </span><span style="color: #0000BB">MYSQLND_QC_ENABLE_SWITCH</span><span style="color: #007700">, </span><span style="color: #0000BB">$i </span><span style="color: #007700">% </span><span style="color: #0000BB">2</span><span style="color: #007700">);<br /> </span><span style="color: #0000BB">$res </span><span style="color: #007700">= </span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /> <br /> </span><span style="color: #0000BB">$res</span><span style="color: #007700">-></span><span style="color: #0000BB">free</span><span style="color: #007700">();<br />}<br /><br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">mysqlnd_qc_get_cache_info</span><span style="color: #007700">());<br /></span><span style="color: #0000BB">?></span> </span> </code></div> </div> <div class="example-contents"><p>The above examples will output something similar to:</p></div> <div class="example-contents screen"> <div class="cdata"><pre> array(4) { ["num_entries"]=> int(2) ["handler"]=> string(7) "default" ["handler_version"]=> string(5) "1.0.0" ["data"]=> array(2) { ["Localhost via UNIX socket 3306 root test|/*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 socket 3306 root test|/*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) } } } } } </pre></div> </div> </div> </p> <p class="para"> 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 <em>SELECT id FROM test WHERE id = 0</em> and <em>SELECT id FROM test WHERE id = 1</em> are normalized into <em>SELECT id FROM test WHERE id = ?</em>. Their both statistics are aggregated into one entry for <em>SELECT id FROM test WHERE id = ?</em>. </p> <p class="para"> <div class="example" id="example-1858"> <p><strong>Example #3 Example <span class="function"><a href="function.mysqlnd-qc-get-normalized-query-trace-log.html" class="function">mysqlnd_qc_get_normalized_query_trace_log()</a></span> usage</strong></p> <div class="example-contents"> <div class="inicode"><pre class="inicode">mysqlnd_qc.enable_qc=1 mysqlnd_qc.collect_normalized_query_trace=1</pre> </div> </div> <div class="example-contents"> <div class="phpcode"><code><span style="color: #000000"> <span style="color: #0000BB"><?php<br /></span><span style="color: #FF8000">/* connect to MySQL */<br /></span><span style="color: #0000BB">$mysqli </span><span style="color: #007700">= new </span><span style="color: #0000BB">mysqli</span><span style="color: #007700">(</span><span style="color: #DD0000">"host"</span><span style="color: #007700">, </span><span style="color: #DD0000">"user"</span><span style="color: #007700">, </span><span style="color: #DD0000">"password"</span><span style="color: #007700">, </span><span style="color: #DD0000">"schema"</span><span style="color: #007700">, </span><span style="color: #DD0000">"port"</span><span style="color: #007700">, </span><span style="color: #DD0000">"socket"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"DROP TABLE IF EXISTS test"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"CREATE TABLE test(id INT)"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #DD0000">"INSERT INTO test(id) VALUES (1), (2), (3)"</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">/* dummy queries to fill the query trace */<br /></span><span style="color: #007700">for (</span><span style="color: #0000BB">$i </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">; </span><span style="color: #0000BB">$i </span><span style="color: #007700"><= </span><span style="color: #0000BB">4</span><span style="color: #007700">; </span><span style="color: #0000BB">$i</span><span style="color: #007700">++) {<br /> </span><span style="color: #0000BB">$query </span><span style="color: #007700">= </span><span style="color: #0000BB">sprintf</span><span style="color: #007700">(</span><span style="color: #DD0000">"/*%s*/SELECT id FROM test WHERE id = %d"</span><span style="color: #007700">, </span><span style="color: #0000BB">MYSQLND_QC_ENABLE_SWITCH</span><span style="color: #007700">, </span><span style="color: #0000BB">$i </span><span style="color: #007700">% </span><span style="color: #0000BB">2</span><span style="color: #007700">);<br /> </span><span style="color: #0000BB">$res </span><span style="color: #007700">= </span><span style="color: #0000BB">$mysqli</span><span style="color: #007700">-></span><span style="color: #0000BB">query</span><span style="color: #007700">(</span><span style="color: #0000BB">$query</span><span style="color: #007700">);<br /> <br /> </span><span style="color: #0000BB">$res</span><span style="color: #007700">-></span><span style="color: #0000BB">free</span><span style="color: #007700">();<br />}<br /><br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">mysqlnd_qc_get_normalized_query_trace_log</span><span style="color: #007700">());<br /></span><span style="color: #0000BB">?></span> </span> </code></div> </div> <div class="example-contents"><p>The above examples will output something similar to:</p></div> <div class="example-contents screen"> <div class="cdata"><pre> 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) } } </pre></div> </div> </div> </p> <p class="para"> The source distribution of PECL/mysqlnd_qc contains a directory <em>web/</em> 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. </p> <p class="para"> Since PECL/mysqlnd_qc 1.1.0 it is possible to write statistics into a log file. Please, see <em><a href="mysqlnd-qc.configuration.html#ini.mysqlnd-qc.collect-statistics-log-file" class="link"> mysqlnd_qc.collect_statistics_log_file</a></em>. </p> </div><hr /><div class="manualnavbar" style="text-align: center;"> <div class="prev" style="text-align: left; float: left;"><a href="mysqlnd-qc.cache-candidates.html">Finding cache candidates</a></div> <div class="next" style="text-align: right; float: right;"><a href="mysqlnd-qc.set-user-handlers.html">Beyond TTL: user-defined storage</a></div> <div class="up"><a href="mysqlnd-qc.quickstart.html">Quickstart and Examples</a></div> <div class="home"><a href="index.html">PHP Manual</a></div> </div></body></html>