Archive for the ‘PHP (english)’ Category

PHP: the 38 characters of the mysqlnd profiler

Октябрь 28th, 2010

Recently I was forced to benchmark a mysqlnd plugin on Windows. X-Debug was no help. It worked flawless on Windows but it can’t tell you what goes on inside a PHP user space API call, for example, you will not know how much time mysqli_query() spends reading a result set. Very Sleepy is nice and the latest Microsoft Visual Studio profiler are probably wonderful but any of those external profiling tools did give me too fine-grained information. Also, they are external profiler which means you have to install extra software.

The mysqlnd statistics didn’t help me either. I didn’t need any aggregated values, I was curios if a certain function was the bottleneck. The solution:

  • extra statistics for critical sections in the plugin using the mysqlnd statistics framework (C coding)
  • dump profiling information into mysqlnd debug log (thanks Andrey)
  • make mysqlnd debug log available on Windows (when using VC9 or newer, thanks Andrey)

Since today mysqlnd adds profiling information to its debug log. Note the "(total = n own= n in_calls=n)" behind the closing tag of a function call. The times are given in milliseconds. For example, "_mysqlnd_pecalloc (total=401 own=401 in_calls=0)" tells you that mysqlnd has spend 401 milliseconds to allocate some memory. Why is that so slow? Simple: I’m using a VM.

   0:>mysqlnd_init
   1:| info : persistent=0
   1:| >_mysqlnd_pecalloc
   2:| | info : file=mysqlnd.c       line=2322
   2:| | info : size=780 ptr=0x2e08d30
   1:| <_mysqlnd_pecalloc (total=401 own=401 in_calls=0)
   1:| >mysqlnd_conn::set_state
   2:| | info : New state=0
   1:| <mysqlnd_conn::set_state (total=247 own=247 in_calls=0)
   1:| >mysqlnd_conn::get_reference
   2:| | info : conn=0 new_refcount=1
   1:| <mysqlnd_conn::get_reference (total=195 own=195 in_calls=0)
   1:| >mysqlnd_conn::init
   2:| | >_mysqlnd_pecalloc
   3:| | | info : file=mysqlnd_net.c   line= 886
   3:| | | info : size=156 ptr=0x2e086f8
   2:| | <_mysqlnd_pecalloc (total=586 own=586 in_calls=0)
   2:| | >mysqlnd_net_init
   3:| | | info : persistent=0
   3:| | | >mysqlnd_net::set_client_option
   4:| | | | info : option=202
   4:| | | | info : MYSQLND_OPT_NET_CMD_BUFFER_SIZE
   4:| | | | info : new_length=4096
   4:| | | | >_mysqlnd_pemalloc
   5:| | | | | info : file=mysqlnd_net.c   line= 586
   5:| | | | | info : size=4096 ptr=0x2e09070 persistent=0
   4:| | | | <_mysqlnd_pemalloc (total=599 own=599 in_calls=0)
   3:| | | <mysqlnd_net::set_client_option (total=4764 own=4165 in_calls=599)
   2:| | <mysqlnd_net_init (total=5406 own=642 in_calls=4764)
   2:| | >_mysqlnd_pecalloc
   3:| | | info : file=mysqlnd_wireprotocol.c line=2095
   3:| | | info : size=72 ptr=0x2e06f78
   2:| | <_mysqlnd_pecalloc (total=442 own=442 in_calls=0)
   2:| | >mysqlnd_protocol_init
   3:| | | info : persistent=0
   2:| | <mysqlnd_protocol_init (total=207 own=207 in_calls=0)
   1:| <mysqlnd_conn::init (total=15320 own=8679 in_calls=6641)
   0:<mysqlnd_init (total=26276 own=10113 in_calls=16163)

Here is how you create such a debug log with profiling information:

  • Get the PHP 5.3.4-dev source, the fresh meat not the stinky one
  • Compile PHP with mysqlnd support and enable debugging, for example, ./configure --with-mysqli=mysqlnd --enable-debug on Linux or configure --with-mysqli --with-mysqlnd --enable-debug on Windows.
  • Set the PHP configuration (php.ini) setting: mysqlnd.debug, for example, mysqlnd.debug="d:t:O,/tmp/mysqlnd.log" (38 characters ;-) ) on Linux or mysqlnd.debug="d:t:O,mysqlnd.log" (34 :-o ).
  • Run your PHP MySQL script

Pitfall: the mysqlnd debug option parser does not support file names that contain ":" You cannot use something like "C:\tmp\mysqlnd.log". Its about debuging and profiling. We will probably not lift that limitation without a strong need. But, of course, mysqlnd is Open Source. If you need it urgently, feel free…


PlanetMySQL Voting: Vote UP / Vote DOWN

PHP: 62 characters to see all MySQL queries

Октябрь 15th, 2010

Did you ever want to see the database queries an arbitrary PHP MySQL application runs? It takes two free downloads and 62 characters to see them.

  • Get PHP 5.3.4-dev
  • Get PECL/mysqlnd_qc
  • Add 19 characters to your configure line: --enable-mysqlnd-qc
  • Add 43 characters at the end of applications source, e.g. using the auto_prepend_file configuration setting: var_dump(mysqlnd_qc_get_query_trace_log());
  • Start your query analysis


array(329) {
  [0]=>
  array(8) {
    ["query"]=>
    string(27) "SET @@session.sql_mode = """
    ["origin"]=>
    string(1330) "#0 /home/nixnutz/Downloads/oxid/core/adodblite/adodbSQL_drivers/mysql/mysql_driver.inc(352): mysql_query('SET @@session.s...', Resource id #26)
#1 /home/nixnutz/Downloads/oxid/core/adodblite/adodb.inc.php(316): mysql_driver_ADOConnection->do_query('SET @@session.s...', -1, -1, false)
#2 /home/nixnutz/Downloads/oxid/core/oxdb.php(216): ADOConnection->Execute('SET @@session.s...')
#3 /home/nixnutz/Downloads/oxid/core/oxconfig.php(479): oxDb::getDb()
#4 /home/nixnutz/Downloads/oxid/core/oxconfig.php(406): oxConfig->_loadVarsFromDb('oxbaseshop')
#5 /home/nixnutz/Downloads/oxid/core/oxconfig.php(448): oxConfig->init()
#6 /home/nixnutz/Downloads/oxid/core/oxsupercfg.php(115): oxConfig::getInstance()
#7 /home/nixnutz/Downloads/oxid/core/oxutilsobject.php(207): oxSuperCfg->getConfig()
#8 /home/nixnutz/Downloads/oxid/core/oxutilsobject.php(109): oxUtilsObject->getClassName('oxutilsobject')
#9 /home/nixnutz/Downloads/oxid/core/oxutilsobject.php(74): oxUtilsObject->oxNew('oxUtilsObject')
#10 /home/nixnutz/Downloads/oxid/core/oxfunctions.php(284): oxUtilsObject::getInstance()
#11 /home/nixnutz/Downloads/oxid/core/oxutils.php(101): oxNew('oxUtils')
#12 /home/nixnutz/Downloads/oxid/core/oxfunctions.php(448): oxUtils::getInstance()
#13 /home/nixnutz/Downloads/oxid/index.php(72): require_once('/home/nixnutz/D...')
#14 {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)
  }
...
}

If you want to know more, check this presentation.


PlanetMySQL Voting: Vote UP / Vote DOWN

PHP: the mysqlnd slow query log (incl. backtrace)

Октябрь 23rd, 2009

Sometimes you forget about what you did years ago, for example the ability of mysqlnd write back traces of slow queries into the PHP error log . Regardless if you use mysqlnd with ext/mysql, ext/mysqli or PDO_MYSQL, mysqlnd is able to tell you which of your code has executed a slow query. To enable the feature, you need to compile PHP with CFLAGS="-D A0". A0? Yeah, we must have had some doubts about the usefulness.

Slow queries

The MySQL server is capable of monitoring queries and recording slow queries in a slow query log. MySQL can log the following types of queries:

  • SQL statements that took more than long_query_time seconds to execute
  • SQL statement that required at least min_examined_row_limit rows to be examined (MySQL 5.1.21+)
  • SQL statement that do not use indexes
  • Slow administrative statements

Please consult the MySQL manual on how to use the slow query log. The basic approach is to set the server startup options --log-slow-queries, --log-queries-not-using-indexes.

Not only the server known which query was slow, clients can tell as well. And this can be used to create a backtrace in PHP to identify the PHP code which has executed a slow query.

It seems little to not documented at all how to identify slow queries when using the C API. If you happen to use the C API as well, have a look at the code example I gave in the german language blog posting SERVER_QUERY_NO_INDEX_USED, SERVER_QUERY_NO_GOOD_INDEX_USED (and SERVER_QUERY_WAS_SLOW).

mysqli_report()

User of ext/mysqli have been able to create backtraces of slow queries for quite some time by help of mysqli_report(). mysqli_report(MYSQLI_REPORT_INDEX) should cause and exception to the thrown whenever a slow query is detected and mysqli_report(MYSQLI_REPORT_INDEX ^ MYSQLI_REPORT_STRICT) should give a warning. There are two drawbacks with this approach. First, it may be inconvenient or virtually impossible to react to the exceptions given the many database abstraction layers used by non-trivial PHP applications. Second, this is ext/mysqli - it won’t work with ext/mysql or PDO_MYSQL.

CFLAGS="-D A0"

If you compile ext/mysql, ext/mysqli and PDO_MYSQL using something like CFLAGS="-D A0" ./configure --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd, you will enable the neat little code passage shown below. Whenever mysqlnd fetches a result from the server and the server hints a slow query, mysqlnd will write a backtrace to the PHP error log. The logging happens regardless who calls mysqlnd: ext/mysql, ext/mysqli, PDO_MYSQL. All queries generating a result set will be recorded.

#if A0
	char *backtrace = mysqlnd_get_backtrace(TSRMLS_C);
	php_log_err(backtrace TSRMLS_CC);
	efree(backtrace);
#endif


From mysqlnd_result.c

NOTE: The feature is experimental. Consider it untested. mysqlnd_get_backtrace() didn’t crash yesterday when forcing it to log all queries from all 440+ PHP tests for ext/mysql and ext/mysqli. It should work just fine but we have not done an extensive testing…

mysqlnd.log_mask

The PHP configuration setting mysqlnd.log_mask defines which queries will be logged. The default is mysqlnd.log_mask = "0", which disables logging. Set it to 16 + 32 = 48 to log slow queries which either use no good index (SERVER_QUERY_NO_GOOD_INDEX_USED = 16) or no index at all (SERVER_QUERY_NO_INDEX_USED = 32). Or, if you are a curious person, try mysqlnd.log_mask=2043 (= 1 + 2 + 8 + … + 1024).

The SEVER_* constants are MySQL internal (C-level) constants (defines) not exported to the PHP userland. There are no corresponding PHP constants. However, you can look up the values in the below table which has been created by inspecting the mysqlnd source.

SERVER_STATUS_IN_TRANS 1
SERVER_STATUS_AUTOCOMMIT 2
SERVER_MORE_RESULTS_EXISTS 8
SERVER_QUERY_NO_GOOD_INDEX_USED 16
SERVER_QUERY_NO_INDEX_USED 32
SERVER_STATUS_CURSOR_EXISTS 64
SERVER_STATUS_LAST_ROW_SENT 128
SERVER_STATUS_DB_DROPPED 256
SERVER_STATUS_NO_BACKSLASH_ESCAPES 512
SERVER_QUERY_WAS_SLOW 1024

From mysqlnd_enum_n_def.h. mysqlnd has taken the values from the corresponding header file of the server. The server code has some few annotations. If you compare the server code and the mysqlnd code don’t be puzzled about SERVER_QUERY_WAS_SLOW - it is from MySQL 6.0, it is in flux, it is undocumented.

The mysqlnd slow query log

Once you put all pieces together, mysqlnd will log (slow) queries. The log not very sophisticated. Just the opposite. For example, mysqlnd cuts off query strings after 15 characters reporting only a fraction of the SQL statement. If you don’t like that, hack mysqlnd_debug.c. Be warned that there may be more such limitations. As said above, this is experimental.

#1 {main}
[23-Oct-2009 13:58:48] #0 /home/nixnutz/src/php-src/branches/PHP_5_3/ext/mysqli/tests/013.php(32): mysqli_query(Object(mysqli), 'select * from t...')
#1 {main}
[23-Oct-2009 13:58:48] #0 /home/nixnutz/src/php-src/branches/PHP_5_3/ext/mysqli/tests/014.skip.php(6): mysqli_query(Object(mysqli), 'SHOW VARIABLES ...')

Back then we stopped at this point. Let us know what you think about it. Comments are welcome.

A0 ?!

A[ndrey] 0. As you know, Andrey is the brain. I’m the helper and ghost writer. The brain just told me that there is another A0 in mysqlnd_alloc.c. However, mysqlnd_alloc.c won’t be compiled. Everything is fine - I am the lucky helper…


PlanetMySQL Voting: Vote UP / Vote DOWN

PHP: 120 tuning screws for mysqlnd

Октябрь 12th, 2009

The MySQL native driver for PHP (mysqlnd) is capable of collecting some 120 performance statistics. This is about twice as much as it was when I blogged about the 59 tuning screws for mysqlnd. While the basics have not not changed and the API calls for accessing the data remained the same (see previous posting) the new figures have never been described before.

The figures are for those of you who want to squeeze the last out of the PHP. Many of the statistics have been written for those who have developed mysqlnd and not for PHP users. The data is certainly still of interest for PHP experts but let me stress out again that it is for experts.

Scope

Statistics are either aggregated on on a per-connection or per-process basis. Changes to per-connection statistics also change the corresponding per-process statistics. But per-process statistics changes are not necessarily reflected in per-connection statistics.

mysqli_get_client_stats() and phpinfo() return per-process statistics. Per-connection statistics are available through mysqli_get_connection_stats(link mysqli)

Threaded PHP

For thread safety statistics are protected by a mutex. There is one mutex for all statistics. Due to the high number of fine grained statistics many mutex locks will happen when collecting statistics. For performance reasons you should turn off statistics in production. Of course, no mutex locks will happen if you use CGI/Fast-CGI.

The ~120 tuning screws

Class: network

Network related data.

Some MySQL Client Server protocol packets are not counted because they require no special en-/decoding routines. mysqlnd currently only counts those commands which require extra methods to be handled.

General notes:

  • Reduce network traffic: fetch no more than required
  • Reduce network traffic: free MySQL server resources as early as possible to lower server resource consumption
bytes_sent, bytes_retreived
 

Scope: connection. Incoming and outgoing traffic: from MySQL to PHP and from PHP to MySQL.

Number of bytes sent from PHP to MySQL and number of bytes received from MySQL.

Usage examples:

  • Check efficiency of compression protocol
  • Check if PHP connects to MySQL
  • Check if PHP needs to be compiled with MySQL support. Note API calls such as mysqli_get_client_version() that won’t cause network traffic.
packets_sent, packets_received
 

Scope: connection. Outgoing traffic: from PHP to MySQL.

Number of MySQL Client Server protocol packages sent and received.

Only useful for debugging CS protocol implementation.

protocol_overhead_in, protocol_overhead_out
 

Scope: connection. Incoming and outgoing traffic: from MySQL to PHP and from PHP to MySQL.

MySQL Client Server protocol overhead in bytes for incoming and outgoing traffic. Currently only the Packet Header (4 bytes) is considered as overhead. Therefore the following is true:

  • protocol_overhead_in = packets_received * 4
  • protocol_overhead_out = packets_sent * 4

Only useful for debugging CS protocol implementation.

bytes_received_ok_packets, packets_received_ok
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol OK packets and their total size in bytes. OK packages can contain a status message. The length of the status message can vary and thus the size of an OK package is not fixed.

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

bytes_received_eof_packets, packets_received_eof
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol EOF packets and their total size in bytes. EOF can vary in size depending on the server version. Also, EOF can transport an error message. Like with other packet statistics the number of packets will be increased even if PHP does not receive the expected packet but, for example, an error message.

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

bytes_received_rset_header_packet, packets_received_reset_header
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol result set header packets and their total size in bytes. The size of the packets varies depending on the payload (LOAD LOCAL INFILE, INSERT/UPDATE, SELECT, error message).

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

bytes_received_rset_field_meta_packet, packets_received_rset_field_meta
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol result set meta data (field information) packets and their total size in bytes. Of course the size varies with the fields in the result set. The packet may also transport an error or an EOF packet in case of COM_LIST_FIELDS.

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

bytes_received_rset_row_packet, packets_received_rset_row
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol result set row data packets and their total size in bytes. The packet may also transport an error or an EOF packet. You can reverse engineer the number of error and EOF packets by substracting rows_fetched_from_server_normal and rows_fetched_from_server_ps from bytes_received_rset_row_packet.

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

bytes_received_prepare_response_packet, packets_received_prepare_response
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol OK for Prepared Statement Initialization packets (prepared statement init packets) and their total size in bytes. The packet may also transport an error. The packet size depends on the MySQL version: 9 bytes with MySQL 4.1 and 12 bytes from MySQL 5.0 on. There is no safe way to know how many errors happened. You may be able to guess that an error has occured if, for example, you always connect to MySQL 5.0 or newer and, bytes_received_prepare_response_packet != packets_received_prepare_response * 12. See also ps_prepared_never_executed, ps_prepared_once_executed.

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

bytes_received_change_user_packet, packets_received_change_user
 

Scope: connection. Incoming traffic: from MySQL to PHP.

Number of MySQL Client Server protocol COM_CHANGE_USER packets and their total size in bytes. The packet may also transport an error or EOF.

Only useful for debugging CS protocol implementation. Note that the total size in bytes includes the size of the header packet (4 bytes, see protocol overhead).

packets_sent_command
 

Scope: connection. Outgoing traffic: from PHP to MySQL.

Number of MySQL Client Server protocol commands sent from PHP to MySQL. There is no way to know which specific commands and how many of them have been sent. At its best you can use it to check if PHP has sent any commands to MySQL to know if you can consider to disable MySQL support in your PHP binary. There is also no way to reverse engineer the number of errors that may have occured while sending data to MySQL. The only error recoded is command_buffer_too_small (see below).

Only useful for debugging CS protocol implementation.

Class: result set

Information about result sets.

General notes:

  • Identify scripts that cause high load
  • Check if script makes MySQL calculate more rows than needed
  • Identify slow queries
result_set_queries
 

Scope: connection.

Number of queries that have generated a result set. Examples of queries that generate a result set: SELECT, SHOW. The statistic will not be incremented if there is an error reading the result set header packet from the line.

You may use it an an indirect measure for the number of queries PHP has sent to MySQL, for example, to identify a client that causes a high database load.

non_result_set_queries
 

Scope: connection.

Number of queries that did not generate a result set. Examples of queries that do not generate a result set: INSERT, UPDATE, LOAD DATA, SHOW. The statistic will not be incremented if there is an error reading the result set header packet from the line.

You may use it an an indirect measure for the number of queries PHP has sent to MySQL, for example, to identify a client that causes a high database load.

no_index_used
 

Scope: connection.

Number of queries that have generated a result set but did not use an index (see also mysqld start option –log-queries-not-using-indexes). If you want these queries to be reported you can use mysqli_report(MYSQLI_REPORT_INDEX) to make ext/mysqli throw an exception. If you prefer a warning instead of an exception use mysqli_report(MYSQLI_REPORT_INDEX ^ MYSQLI_REPORT_STRICT).

Aside note: see earlier (german language) blog post on undocumented C API flags.

bad_index_used
 

Scope: connection.

Number of queries that have generated a result set and did not use a good index (see also mysqld start option –log-slow-queries). If you want these queries to be reported you can use mysqli_report(MYSQLI_REPORT_INDEX) to make ext/mysqli throw an exception. If you prefer a warning instead of an exception use mysqli_report(MYSQLI_REPORT_INDEX ^ MYSQLI_REPORT_STRICT)

slow_queries
 

Scope: connection.

This flag seems not mentioned in the MySQL documentation. Likely meaning: SQL statements that took more than long_query_time seconds to execute and required at least min_examined_row_limit rows to be examined. Not reported through mysqli_report().

buffered_sets
 

Scope: connection.

Number of buffered result sets returned by "normal" queries. "Normal" means "not prepared statement" in the following.

Examples of API calls that will buffer result sets on the client: mysql_query(), mysqli_query(), mysqli_store_result(), mysqli_stmt_get_result().

Buffering result sets on the client ensures that server resources are free’d as soon as possible and it makes result set scrolling easier. The downside is the additional memory consumption on the client for buffering data. Note that mysqlnd (unlike the MySQL Client Library) respects the PHP memory limit because it uses PHP internal memory management functions to allocate memory. This is also the reason why memory_get_usage() reports a higer memory consumption when using mysqlnd instead of the MySQL Client Library. memory_get_usage() does not measure the memory consumption of the MySQL Client Library at all because the MySQL Client Library does not use PHP internal memory management functions monitored by the function!

unbuffered_sets
 

Scope: connection.

Number of unbuffered result sets returned by "normal" queries.

Examples of API calls that will not buffer result sets on the client: mysqli_use_result().

ps_buffered_sets
 

Scope: connection.

Number of buffered result sets returned by prepared statements. By default prepared statements are unbuffered.

Examples of API calls that will not buffer result sets on the client: mysqli_stmt_store_result().

ps_unbuffered_sets
 

Scope: connection.

Number of unbuffered result sets returned by prepared statements. By default prepared statements are unbuffered.

flushed_normal_sets, flushed_ps_sets
 

Scope: connection.

Number of result sets from "normal" queries and prepared statements with unread data which have been flushed silently for you. Flushing happens only with unbuffered result sets.

Unbuffered result sets must be fetched completely before a new query can be run on the connection otherwise MySQL will throw an error. If the application does not fetch all rows from an unbuffered result set, mysqlnd does implicitly fetch the result set to clear the line. See also rows_skipped_normal, rows_skipped_ps.

Some possible causes for an implicit flush

  • Faulty client application
  • Client stopped reading after it found what it was looking for but has made MySQL calculate more records than needed
  • Client application has stopped unexpectedly
ps_prepared_never_executed
 

Scope: connection.

Number of statements prepared but never executed.

Prepared statements occupy server resources. You should not prepare a statement if you do not plan to execute it.

ps_prepared_once_executed
 

Scope: connection.

Number of prepared statements executed only one.

One of the ideas behind prepared statements is that the same query gets executed over and over again (with different parameters) and some parsing and other preparation work can be saved, if statement execution is split up in separate prepare and execute stages. The idea is to prepare once and "cache" results, for example, the parse tree to be reused during multiple statement executions. If you execute a prepared statement only once the two stage processing can be inefficient compared to "normal" queries because all the "caching" means extra work and it takes (limited) server resources to hold the cached information. Consequently, prepared statements that are executed only once may cause performance hurts.

rows_fetched_from_server_normal, rows_fetched_from_server_ps
 

Scope: connection.

Total number of result set rows successfully fetched from MySQL regardless if the client application has consumed them or not. Some of the rows may not have been fetched by the client application but have been flushed implicitly.

See also packets_received_rset_row.

rows_buffered_from_client_normal, rows_buffered_from_client_ps
 

Scope: connection.

Total number of succesfully buffered rows originating from a "normal" query or a prepared statement. This is the number of rows that have been fetched from MySQL and buffered on client. Note that there are two distinct statistics on rows that have been buffered (MySQL -> mysqlnd internal buffer) and buffered rows that have been fetched by the client application (mysqlnd internal buffer -> client application). If the number of buffered rows is higher than the number of fetched buffered rows it can mean that the client application runs queries that cause larger result sets than needed resulting in rows not read by the client.

Examples of queries that will buffere results: mysqli_query(), mysqli_store_results().

rows_fetched_from_client_normal_buffered, rows_fetched_from_client_ps_buffered
 

Scope: connection.

Total number of rows fetched by the client from a buffered result set created by a "normal" query or a prepared statement.

rows_fetched_from_client_normal_unbuffered, rows_fetched_from_client_ps_unbuffered
 

Scope: connection.

Total number of rows fetched by the client from a unbuffered result set created by a "normal" query or a prepared statement.

rows_fetched_from_client_ps_cursor
 

Scope: connection.

Total number of rows fetch by the client from a cursor created by a prepared statement.

rows_skipped_normal, rows_skipped_ps
 

Scope: connection.

Buggy - don’t use it.

Possible future meaning: number of rows skipped when flushing a result set.

copy_on_write_saved, copy_on_write_performed
 

Scope: process.

With mysqlnd variables returned by the extensions point into mysqlnd internal network result buffers. If you do not change the variables fetched data will be kept only once in memory. If you change the variables, mysqlnd has to perform a copy-on-write to protect the internal network result buffers from being changed. With the MySQL Client Library you always hold fetched data twice in memory. Once in the internal MySQL Client Library buffers and once in the variables returned by the extensions. In theory mysqlnd can save up to 40% memory. However, note that the memory saving cannot be measured using memory_get_usage() (read above why).

explicit_free_result, implicit_free_result
 

Scope: connection, process (only during prepared statement cleanup).

Total number of free’d result sets. The free is always considered explicit but for result sets created by an init command (e.g. mysqli_options(MYSQLI_INIT_COMMAND , ...))

proto_text_fetched_null, proto_text_fetched_bit, proto_text_fetched_tinyint, proto_text_fetched_short, proto_text_fetched_int24, proto_text_fetched_intproto_text_fetched_int, proto_text_fetched_bigint, proto_text_fetched_decimal, proto_text_fetched_float, proto_text_fetched_double, proto_text_fetched_date, proto_text_fetched_year, proto_text_fetched_time, proto_text_fetched_datetime, proto_text_fetched_timestamp, proto_text_fetched_string, proto_text_fetched_blob, proto_text_fetched_enum, proto_text_fetched_set, proto_text_fetched_geometry, proto_text_fetched_other
 

Scope: connection.

Total number of columns of a certain type fetched from a "normal" query (MySQL text protocol). Mapping from C API / MySQL meta data type to statistics name:

  • MYSQL_TYPE_NULL - proto_text_fetched_null
  • MYSQL_TYPE_BIT - proto_text_fetched_bit
  • MYSQL_TYPE_TINY - proto_text_fetched_tinyint
  • MYSQL_TYPE_SHORT - proto_text_fetched_short
  • MYSQL_TYPE_INT24 - proto_text_fetched_int24
  • MYSQL_TYPE_LONG - proto_text_fetched_int
  • MYSQL_TYPE_LONGLONG - proto_text_fetched_bigint
  • MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NEWDECIMAL - proto_text_fetched_decimal
  • MYSQL_TYPE_FLOAT - proto_text_fetched_float
  • MYSQL_TYPE_DOUBLE - proto_text_fetched_double
  • MYSQL_TYPE_DATE, MYSQL_TYPE_NEWDATE - proto_text_fetched_date
  • MYSQL_TYPE_YEAR - proto_text_fetched_year
  • MYSQL_TYPE_TIME - proto_text_fetched_time
  • MYSQL_TYPE_DATETIME - proto_text_fetched_datetime
  • MYSQL_TYPE_TIMESTAMP - proto_text_fetched_timestamp
  • MYSQL_TYPE_STRING, MYSQL_TYPE_VARSTRING, MYSQL_TYPE_VARCHAR - proto_text_fetched_string
  • MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB - proto_text_fetched_blob
  • MYSQL_TYPE_ENUM - proto_text_fetched_enum
  • MYSQL_TYPE_SET - proto_text_fetched_set
  • MYSQL_TYPE_GEOMETRY - proto_text_fetched_geometry
  • any MYSQL_TYPE_* not listed before (there should be none) - proto_text_fetched_other

Note that the MYSQL_*-type constants may not be associated with the very same SQL column types in every version of MySQL.

proto_binary_fetched_null, proto_binary_fetched_bit, proto_binary_fetched_tinyint, proto_binary_fetched_short, proto_binary_fetched_int24, proto_binary_fetched_intproto_binary_fetched_int, proto_binary_fetched_bigint, proto_binary_fetched_decimal, proto_binary_fetched_float, proto_binary_fetched_double, proto_binary_fetched_date, proto_binary_fetched_year, proto_binary_fetched_time, proto_binary_fetched_datetime, proto_binary_fetched_timestamp, proto_binary_fetched_string, proto_binary_fetched_blob, proto_binary_fetched_enum, proto_binary_fetched_set, proto_binary_fetched_geometry, proto_binary_fetched_other
 

Scope: connection.

Total number of columns of a certain type fetched from a prepared statement (MySQL binary protocol). Type mapping see proto_text_* above

Class: connection

Information on connections.

connect_success, connect_failure
 

Scope: connection.

Total number of successful / failed connection attempt. Reused connections and all otker kinds of connections are included.

reconnect
 

Scope: process.

Total number of (real_)connect attempts made on an already opened connection handle.

The code sequence $link = new mysqli(...); $link->real_connect(...) will cause a reconnect. But $link = new mysqli(...); $link->connect(...) will not because $link->connect(...) will explicitly close the existing connection before a new connection is established.

pconnect_success
 

Scope: connection.

Total number of successful persistent connection attempts. Note that connect_success holds the sum of successful persistent and non-persistent connection attempts. The number of successful non-persistent connection attempts is connect_success - pconnect_success.

active_connections
 

Scope: connection.

Total number of active persistent and non-persistent connections.

active_persistent_connections
 

Scope: connection.

Total number of active persistent connections. The total number of active non-persistent connections is active_connections - active_persistent_connections.

explicit_close
 

Scope: connection.

Total number of explicitly closed connections (ext/mysqli only). Examples of code snippets that cause an explicit close :

  • $link = new mysqli(...); $link->close(...)
  • $link = new mysqli(...); $link->connect(...)
implicit_close
 

Scope: connection.

Total number of implicitly closed connections (ext/mysqli only). Examples of code snippets that cause an implicit close :

  • $link = new mysqli(...); $link->real_connect(...)
  • unset($link)
  • persistent connection: pooled connection has been created with real_connect and there may be unknown options set - close implicitly to avoid returning a connection with unknown options
  • persistent connection: ping/change_user fails and ext/mysqli closes the connection
  • end of script execution: close connections that have not been closed by the user
disconnect_close
 

Scope: connection.

Connection failures indicated by the C API call mysql_real_connect() during an attempt to establish a connection. It is called disconnect_close because the connection handle passed to the C API call will be closed.

in_middle_of_command_close
 

Scope: process.

A connection has been closed in the middle of a command execution (outstanding result sets not fetched, after sending a query and before retrieving an answer, while fetching data, while transferring data with LOAD DATA). Unless you use asynchronous queries this should only happen if your script stops unexpectedly and PHP shuts down the connections for you.

init_command_executed_count
 

Total number of init command (e.g. mysqli_options(MYSQLI_INIT_COMMAND , ...)) executions. The number of successful executions is init_command_executed_count - init_command_failed_count.

init_command_failed_count
 

Totoal number of failed init commands.

Class: assorted
explicit_stmt_close, implicit_stmt_close
 

Scope: process.

Total number of close prepared statements. A close is always considered explicit but for a failed prepare.

mem_emalloc_count, mem_emalloc_ammount, mem_ecalloc_count, mem_ecalloc_ammount, mem_erealloc_count, mem_erealloc_ammount, mem_efree_count, mem_malloc_count, mem_malloc_ammount, mem_calloc_count, mem_calloc_ammount, mem_realloc_count, mem_realloc_ammount, mem_free_count
 

Scope: process.

Development only: memory management calls.

command_buffer_too_small
 

Scope: connection.

Number of network command buffer extensions while sending commands from PHP to MySQL.

mysqlnd allocates an internal command/network buffer of mysqlnd.net_cmd_buffer_size (php.ini) bytes for every connection. If a MySQL Client Server protocol command, for example, COM_QUERY ("normal&quot query), does not fit into the buffer, mysqlnd will grow the buffer to what is needed for sending the command. Whenever the buffer gets extended for one connection command_buffer_too_small will be incremented by one.

If mysqlnd has to grow the buffer beyond its initial size of mysqlnd.net_cmd_buffer_size (php.ini) bytes for almost every connection, you should consider to increase the default size to avoid re-allocations.

The default buffer size is 2048 bytes in PHP 5.3.0. In future versions the default will be 4kB or larger. The default can changed either through the php.ini setting mysqlnd.net_cmd_buffer_size or using mysqli_options(MYSQLI_OPT_NET_CMD_BUFFER_SIZE, int size).

It is recommended to set the buffer size to no less than 4096 bytes because mysqlnd also uses it when reading certain communication packet from MySQL. In PHP 5.3.0, mysqlnd will not grow the buffer if MySQL sends a packet that is larger than the current size of the buffer. As a consequence mysqlnd is unable to decode the packet and the client application will get an error. There are only two situations when the packet can be larger than the 2048 bytes default of mysqlnd.net_cmd_buffer_size in PHP 5.3.0: the packet transports a very long error message or the packet holds column meta data from COM_LIST_FIELD (mysql_list_fields() and the meta data comes from a string column with a very long default value (>1900 bytes). No bug report on this exists - it should happen rarely.

As of PHP 5.3.2 mysqlnd does not allow setting buffers smaller than 4096 bytes.


PlanetMySQL Voting: Vote UP / Vote DOWN