# name : processlist_row_stats.patch # introduced : 11 or before # maintainer : Oleg # #!!! notice !!! # Any small change to this file in the main branch # should be done or reviewed by the maintainer! --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2424,6 +2424,7 @@ thd->sent_row_count++; thd->sent_row_count_2++; + DEBUG_SYNC(thd, "sent_row"); if (thd->vio_ok()) DBUG_RETURN(protocol->write()); --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1766,7 +1766,8 @@ /**************************************************************************** Return info about all processes - returns for each thread: thread id, user, host, db, command, info + returns for each thread: thread id, user, host, db, command, info, + rows_sent, rows_examined, rows_read ****************************************************************************/ class thread_info :public ilink { @@ -1784,6 +1785,7 @@ uint command; const char *user,*host,*db,*proc_info,*state_info; CSET_STRING query_string; + ulonglong rows_sent, rows_examined, rows_read; }; #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION @@ -1836,6 +1838,15 @@ field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); field->maybe_null=1; + field_list.push_back(field= new Item_return_int("Rows_sent", + MY_INT64_NUM_DECIMAL_DIGITS, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(field= new Item_return_int("Rows_examined", + MY_INT64_NUM_DECIMAL_DIGITS, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(field= new Item_return_int("Rows_read", + MY_INT64_NUM_DECIMAL_DIGITS, + MYSQL_TYPE_LONGLONG)); if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_VOID_RETURN; @@ -1889,6 +1900,9 @@ thd_info->query_string= CSET_STRING(q, q ? length : 0, tmp->query_charset()); } + thd_info->rows_sent= tmp->sent_row_count; + thd_info->rows_examined= tmp->examined_row_count; + thd_info->rows_read= tmp->warning_info->current_row_for_warning(); mysql_mutex_unlock(&tmp->LOCK_thd_data); thd_info->start_time= tmp->start_time; thread_infos.append(thd_info); @@ -1917,6 +1931,9 @@ protocol->store(thd_info->state_info, system_charset_info); protocol->store(thd_info->query_string.str(), thd_info->query_string.charset()); + protocol->store(thd_info->rows_sent); + protocol->store(thd_info->rows_examined); + protocol->store(thd_info->rows_read); if (protocol->write()) break; /* purecov: inspected */ } @@ -2027,6 +2044,15 @@ table->field[8]->store(((tmp->start_utime ? now_utime - tmp->start_utime : 0)/ 1000)); + mysql_mutex_lock(&tmp->LOCK_thd_data); + /* ROWS_SENT */ + table->field[9]->store((ulonglong) tmp->sent_row_count); + /* ROWS_EXAMINED */ + table->field[10]->store((ulonglong) tmp->examined_row_count); + /* ROWS_READ */ + table->field[11]->store((ulonglong) tmp->warning_info->current_row_for_warning()); + mysql_mutex_unlock(&tmp->LOCK_thd_data); + if (schema_table_store_record(thd, table)) { mysql_mutex_unlock(&LOCK_thread_count); @@ -8140,6 +8166,12 @@ SKIP_OPEN_TABLE}, {"TIME_MS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Time_ms", SKIP_OPEN_TABLE}, + {"ROWS_SENT", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_UNSIGNED, "Rows_sent", SKIP_OPEN_TABLE}, + {"ROWS_EXAMINED", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_UNSIGNED, "Rows_examined", SKIP_OPEN_TABLE}, + {"ROWS_READ", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + MY_I_S_UNSIGNED, "Rows_read", SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; --- /dev/null +++ b/mysql-test/include/percona_processlist_row_stats_show.inc @@ -0,0 +1,7 @@ +--replace_column 1 ### 3 ### 6 ### 7 ### +SHOW PROCESSLIST; + +--replace_column 1 ### +SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; + +SET DEBUG_SYNC= 'now SIGNAL threads_dumped'; --- /dev/null +++ b/mysql-test/r/percona_processlist_row_stats.result @@ -0,0 +1,70 @@ +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES(10); +INSERT INTO t2 VALUES(10); +INSERT INTO t2 VALUES(20); +INSERT INTO t2 VALUES(10); +INSERT INTO t2 VALUES(20); +SET DEBUG_SYNC= 'locked_table_name SIGNAL thread1_ready WAIT_FOR threads_dumped'; +CREATE TABLE t1 (a INT); +SET DEBUG_SYNC= 'now WAIT_FOR thread1_ready'; +SET DEBUG_SYNC= 'execute_command_after_close_tables SIGNAL thread2_ready WAIT_FOR threads_dumped'; +SELECT a FROM t2 WHERE a > 15; +SET DEBUG_SYNC= 'now WAIT_FOR thread2_ready'; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Rows_sent Rows_examined Rows_read +### root ### test Query ### ### SHOW PROCESSLIST 0 0 2 +### root ### test Query ### ### CREATE TABLE t1 (a INT) 0 0 1 +### root ### test Query ### ### SELECT a FROM t2 WHERE a > 15 2 5 6 +SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; +id info rows_sent rows_examined rows_read +### SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id 0 0 1 +### CREATE TABLE t1 (a INT) 0 0 1 +### SELECT a FROM t2 WHERE a > 15 2 5 6 +SET DEBUG_SYNC= 'now SIGNAL threads_dumped'; +a +20 +20 +SET DEBUG_SYNC= 'sent_row SIGNAL thread1_ready WAIT_FOR threads_dumped'; +SELECT a FROM t2 WHERE a < 15; +SET DEBUG_SYNC= 'now WAIT_FOR thread1_ready'; +SET DEBUG_SYNC= 'sent_row SIGNAL thread2_ready WAIT_FOR threads_dumped'; +SELECT a FROM t2 WHERE a > 15; +SET DEBUG_SYNC= 'now WAIT_FOR thread2_ready'; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Rows_sent Rows_examined Rows_read +### root ### test Query ### ### SHOW PROCESSLIST 0 0 4 +### root ### test Query ### ### SELECT a FROM t2 WHERE a < 15 1 0 1 +### root ### test Query ### ### SELECT a FROM t2 WHERE a > 15 1 0 3 +SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; +id info rows_sent rows_examined rows_read +### SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id 0 0 1 +### SELECT a FROM t2 WHERE a < 15 1 0 1 +### SELECT a FROM t2 WHERE a > 15 1 0 3 +SET DEBUG_SYNC= 'now SIGNAL threads_dumped'; +a +10 +10 +10 +a +20 +20 +SET DEBUG_SYNC= 'execute_command_after_close_tables SIGNAL thread1_ready WAIT_FOR threads_dumped'; +UPDATE t2 SET a = 15 WHERE a = 20; +SET DEBUG_SYNC= 'now WAIT_FOR thread1_ready'; +SET DEBUG_SYNC= 'execute_command_after_close_tables SIGNAL thread2_ready WAIT_FOR threads_dumped'; +UPDATE t2 SET a = 15 WHERE a = 10; +SET DEBUG_SYNC= 'now WAIT_FOR thread2_ready'; +SHOW PROCESSLIST; +Id User Host db Command Time State Info Rows_sent Rows_examined Rows_read +### root ### test Query ### ### SHOW PROCESSLIST 0 0 4 +### root ### test Query ### ### UPDATE t2 SET a = 15 WHERE a = 20 0 5 6 +### root ### test Query ### ### UPDATE t2 SET a = 15 WHERE a = 10 0 5 6 +SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; +id info rows_sent rows_examined rows_read +### SELECT id, info, rows_sent, rows_examined, rows_read FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id 0 0 1 +### UPDATE t2 SET a = 15 WHERE a = 20 0 5 6 +### UPDATE t2 SET a = 15 WHERE a = 10 0 5 6 +SET DEBUG_SYNC= 'now SIGNAL threads_dumped'; +DROP TABLES t1, t2; --- /dev/null +++ b/mysql-test/t/percona_processlist_row_stats.test @@ -0,0 +1,79 @@ +# Testing of INFORMATION_SCHEMA.PROCESSLIST fields ROWS_SENT, ROWS_EXAMINED, ROWS_READ +--source include/have_debug_sync.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES(10); +INSERT INTO t2 VALUES(10); +INSERT INTO t2 VALUES(20); +INSERT INTO t2 VALUES(10); +INSERT INTO t2 VALUES(20); + +--connect (conn1, localhost, root, ,) +--connect (conn2, localhost, root, ,) + +--connection conn1 +SET DEBUG_SYNC= 'locked_table_name SIGNAL thread1_ready WAIT_FOR threads_dumped'; +send CREATE TABLE t1 (a INT); +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR thread1_ready'; + +--connection conn2 +SET DEBUG_SYNC= 'execute_command_after_close_tables SIGNAL thread2_ready WAIT_FOR threads_dumped'; +send SELECT a FROM t2 WHERE a > 15; +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR thread2_ready'; + +--source include/percona_processlist_row_stats_show.inc + +--connection conn1 +reap; +--connection conn2 +reap; + +--connection conn1 +SET DEBUG_SYNC= 'sent_row SIGNAL thread1_ready WAIT_FOR threads_dumped'; +send SELECT a FROM t2 WHERE a < 15; +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR thread1_ready'; + +--connection conn2 +SET DEBUG_SYNC= 'sent_row SIGNAL thread2_ready WAIT_FOR threads_dumped'; +send SELECT a FROM t2 WHERE a > 15; +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR thread2_ready'; + +--source include/percona_processlist_row_stats_show.inc + +--connection conn1 +reap; +--connection conn2 +reap; + +--connection conn1 +SET DEBUG_SYNC= 'execute_command_after_close_tables SIGNAL thread1_ready WAIT_FOR threads_dumped'; +send UPDATE t2 SET a = 15 WHERE a = 20; +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR thread1_ready'; + +--connection conn2 +SET DEBUG_SYNC= 'execute_command_after_close_tables SIGNAL thread2_ready WAIT_FOR threads_dumped'; +send UPDATE t2 SET a = 15 WHERE a = 10; +--connection default +SET DEBUG_SYNC= 'now WAIT_FOR thread2_ready'; + +--source include/percona_processlist_row_stats_show.inc + +--connection conn1 +reap; +--connection conn2 +reap; + +--connection default +disconnect conn1; +disconnect conn2; +DROP TABLES t1, t2;