diff -r 06eb221fefe3 include/my_time.h --- a/include/my_time.h Thu Mar 27 11:23:01 2008 +0100 +++ b/include/my_time.h Mon Apr 07 14:29:08 2008 +0200 @@ -140,7 +140,7 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to); int my_datetime_to_str(const MYSQL_TIME *l_time, char *to); int my_TIME_to_str(const MYSQL_TIME *l_time, char *to); - +ulonglong my_timer(ulonglong *ltime, ulonglong frequency); C_MODE_END #endif /* _my_time_h_ */ diff -r 06eb221fefe3 scripts/mysqldumpslow.sh --- a/scripts/mysqldumpslow.sh Thu Mar 27 11:23:01 2008 +0100 +++ b/scripts/mysqldumpslow.sh Mon Apr 07 14:29:08 2008 +0200 @@ -83,8 +83,8 @@ s/^#? Time: \d{6}\s+\d+:\d+:\d+.*\n//; my ($user,$host) = s/^#? User\@Host:\s+(\S+)\s+\@\s+(\S+).*\n// ? ($1,$2) : ('',''); - s/^# Query_time: (\d+) Lock_time: (\d+) Rows_sent: (\d+).*\n//; - my ($t, $l, $r) = ($1, $2, $3); + s/^# Query_time: (\d+(\.\d+)?) Lock_time: (\d+(\.\d+)?) Rows_sent: (\d+(\.\d+)?).*\n//; + my ($t, $l, $r) = ($1, $3, $5); $t -= $l unless $opt{l}; # remove fluff that mysqld writes to log when it (re)starts: diff -r 06eb221fefe3 sql-common/my_time.c --- a/sql-common/my_time.c Thu Mar 27 11:23:01 2008 +0100 +++ b/sql-common/my_time.c Mon Apr 07 14:29:08 2008 +0200 @@ -1252,3 +1252,37 @@ return 0; } +/* + int my_timer(ulonglong *ltime, ulonglong frequency) + + For performance measurement this function returns the number + of microseconds since the epoch (SVr4, BSD 4.3, POSIX 1003.1-2001) + or system start (Windows platforms). + + For windows platforms frequency value (obtained via + QueryPerformanceFrequency) has to be specified. The global frequency + value is set in mysqld.cc. + + If Windows platform doesn't support QueryPerformanceFrequency we will + obtain the time via GetClockCount, which supports microseconds only. +*/ + +ulonglong my_timer(ulonglong *ltime, ulonglong frequency) +{ + ulonglong newtime= 0; +#ifdef __WIN__ + if (frequency) + { + QueryPerformanceCounter((LARGE_INTEGER *)&newtime); + newtime/= (frequency * 1000000); + } else + newtime= (GetTickCount() * 1000; /* GetTickCount only returns milliseconds */ +#else + struct timeval t; + gettimeofday(&t, NULL); + newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec; +#endif + if (ltime) + *ltime= newtime; + return newtime; +} diff -r 06eb221fefe3 sql/filesort.cc --- a/sql/filesort.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/filesort.cc Mon Apr 07 14:29:08 2008 +0200 @@ -173,6 +173,7 @@ { statistic_increment(thd->status_var.filesort_scan_count, &LOCK_status); } + thd->query_plan_flags|= QPLAN_FILESORT; #ifdef CAN_TRUST_RANGE if (select && select->quick && select->quick->records > 0L) { @@ -239,6 +240,7 @@ } else { + thd->query_plan_flags|= QPLAN_FILESORT_DISK; if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer) { x_free(table_sort.buffpek); @@ -1070,6 +1072,7 @@ statistic_increment(current_thd->status_var.filesort_merge_passes, &LOCK_status); + current_thd->query_plan_fsort_passes++; if (param->not_killable) { killed= ¬_killable; diff -r 06eb221fefe3 sql/log.cc --- a/sql/log.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/log.cc Mon Apr 07 14:29:08 2008 +0200 @@ -2076,10 +2076,11 @@ */ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, - time_t query_start_arg) + time_t query_start_arg, ulonglong query_start_timer) { bool error=0; time_t current_time; + ulonglong current_timer; if (!is_open()) return 0; DBUG_ENTER("MYSQL_LOG::write"); @@ -2090,7 +2091,8 @@ int tmp_errno=0; char buff[80],*end; end=buff; - if (!(thd->options & OPTION_UPDATE_LOG)) + if (!(thd->options & OPTION_UPDATE_LOG) && + !(thd->slave_thread && opt_log_slow_slave_statements)) { VOID(pthread_mutex_unlock(&LOCK_log)); DBUG_RETURN(0); @@ -2120,22 +2122,69 @@ if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", sctx->priv_user ? sctx->priv_user : "", - sctx->user ? sctx->user : "", + sctx->user ? sctx->user : (thd->slave_thread ? "SQL_SLAVE" : ""), sctx->host ? sctx->host : "", sctx->ip ? sctx->ip : "") == (uint) -1) tmp_errno=errno; } - if (query_start_arg) + if (query_start_timer) { + char buf[5][20]; + ulonglong current_timer= my_timer(¤t_timer, frequency); + sprintf(buf[0], "%.6f", (current_timer - query_start_timer) / 1000000.0); + sprintf(buf[1], "%.6f", (thd->timer_after_lock - query_start_timer) / 1000000.0); + if (!query_length) + { + thd->sent_row_count= thd->examined_row_count= 0; + thd->innodb_was_used= FALSE; + thd->query_plan_flags= QPLAN_NONE; + thd->query_plan_fsort_passes= 0; + } + /* For slow query log */ if (my_b_printf(&log_file, - "# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n", - (ulong) (current_time - query_start_arg), - (ulong) (thd->time_after_lock - query_start_arg), + "# Thread_id: %lu Schema: %s\n" \ + "# Query_time: %s Lock_time: %s Rows_sent: %lu Rows_examined: %lu\n", + (ulong) thd->thread_id, (thd->db ? thd->db : ""), + buf[0], buf[1], (ulong) thd->sent_row_count, (ulong) thd->examined_row_count) == (uint) -1) tmp_errno=errno; + if ((thd->variables.log_slow_verbosity & SLOG_V_QUERY_PLAN) && + my_b_printf(&log_file, + "# QC_Hit: %s Full_scan: %s Full_join: %s Tmp_table: %s Tmp_table_on_disk: %s\n" \ + "# Filesort: %s Filesort_on_disk: %s Merge_passes: %lu\n", + ((thd->query_plan_flags & QPLAN_QC) ? "Yes" : "No"), + ((thd->query_plan_flags & QPLAN_FULL_SCAN) ? "Yes" : "No"), + ((thd->query_plan_flags & QPLAN_FULL_JOIN) ? "Yes" : "No"), + ((thd->query_plan_flags & QPLAN_TMP_TABLE) ? "Yes" : "No"), + ((thd->query_plan_flags & QPLAN_TMP_DISK) ? "Yes" : "No"), + ((thd->query_plan_flags & QPLAN_FILESORT) ? "Yes" : "No"), + ((thd->query_plan_flags & QPLAN_FILESORT_DISK) ? "Yes" : "No"), + thd->query_plan_fsort_passes) == (uint) -1) + tmp_errno=errno; + if ((thd->variables.log_slow_verbosity & SLOG_V_INNODB) && thd->innodb_was_used) + { + sprintf(buf[2], "%.6f", thd->innodb_io_reads_wait_timer / 1000000.0); + sprintf(buf[3], "%.6f", thd->innodb_lock_que_wait_timer / 1000000.0); + sprintf(buf[4], "%.6f", thd->innodb_innodb_que_wait_timer / 1000000.0); + if (my_b_printf(&log_file, + "# InnoDB_IO_r_ops: %lu InnoDB_IO_r_bytes: %lu InnoDB_IO_r_wait: %s\n" \ + "# InnoDB_rec_lock_wait: %s InnoDB_queue_wait: %s\n" \ + "# InnoDB_pages_distinct: %lu\n", + (ulong) thd->innodb_io_reads, + (ulong) thd->innodb_io_read, + buf[2], buf[3], buf[4], + (ulong) thd->innodb_page_access) == (uint) -1) + tmp_errno=errno; + } + else + { + if ((thd->variables.log_slow_verbosity & SLOG_V_INNODB) && + my_b_printf(&log_file,"# No InnoDB statistics available for this query\n") == (uint) -1) + tmp_errno=errno; + } } if (thd->db && strcmp(thd->db,db)) { // Database changed diff -r 06eb221fefe3 sql/log_event.cc --- a/sql/log_event.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/log_event.cc Mon Apr 07 14:29:08 2008 +0200 @@ -2038,6 +2038,7 @@ /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); + log_slow_statement(thd); } else diff -r 06eb221fefe3 sql/my_time.c --- a/sql/my_time.c Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/my_time.c Mon Apr 07 14:29:08 2008 +0200 @@ -1252,3 +1252,37 @@ return 0; } +/* + int my_timer(ulonglong *ltime, ulonglong frequency) + + For performance measurement this function returns the number + of microseconds since the epoch (SVr4, BSD 4.3, POSIX 1003.1-2001) + or system start (Windows platforms). + + For windows platforms frequency value (obtained via + QueryPerformanceFrequency) has to be specified. The global frequency + value is set in mysqld.cc. + + If Windows platform doesn't support QueryPerformanceFrequency we will + obtain the time via GetClockCount, which supports microseconds only. +*/ + +ulonglong my_timer(ulonglong *ltime, ulonglong frequency) +{ + ulonglong newtime= 0; +#ifdef __WIN__ + if (frequency) + { + QueryPerformanceCounter((LARGE_INTEGER *)&newtime); + newtime/= (frequency / 1000000); + } else + newtime= (GetTickCount() * 1000); /* GetTickCount only returns milliseconds */ +#else + struct timeval t; + gettimeofday(&t, NULL); + newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec; +#endif + if (ltime) + *ltime= newtime; + return newtime; +} diff -r 06eb221fefe3 sql/mysql_priv.h --- a/sql/mysql_priv.h Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/mysql_priv.h Mon Apr 07 14:29:08 2008 +0200 @@ -483,6 +483,78 @@ #define WEEK_FIRST_WEEKDAY 4 #define STRING_BUFFER_USUAL_SIZE 80 + +/* Slow log */ + +struct msl_opts +{ + ulong val; + char *name; +}; + +#define SLOG_V_MICROTIME 1 << 0 +#define SLOG_V_QUERY_PLAN 1 << 1 +#define SLOG_V_INNODB 1 << 2 +/* ... */ +#define SLOG_V_INVALID 1 << 31 +#define SLOG_V_NONE SLOG_V_MICROTIME + +static const struct msl_opts slog_verb[]= +{ + /* Basic flags */ + + { SLOG_V_MICROTIME, "microtime" }, + { SLOG_V_QUERY_PLAN, "query_plan" }, + { SLOG_V_INVALID, "innodb" }, + + /* End of baisc flags */ + + { 0, "" }, + + /* Complex flags */ + + { SLOG_V_MICROTIME, "minimal" }, + { SLOG_V_MICROTIME|SLOG_V_QUERY_PLAN, "standard" }, + { SLOG_V_INVALID, "full" }, + + /* End of complex flags */ + + { SLOG_V_INVALID, (char *)0 } +}; + +#define QPLAN_NONE 0 +#define QPLAN_QC 1 << 0 +#define QPLAN_QC_NO 1 << 1 +#define QPLAN_FULL_SCAN 1 << 2 +#define QPLAN_FULL_JOIN 1 << 3 +#define QPLAN_TMP_TABLE 1 << 4 +#define QPLAN_TMP_DISK 1 << 5 +#define QPLAN_FILESORT 1 << 6 +#define QPLAN_FILESORT_DISK 1 << 7 +/* ... */ +#define QPLAN_MAX 1 << 31 + +#define SLOG_F_QC_NO QPLAN_QC_NO +#define SLOG_F_FULL_SCAN QPLAN_FULL_SCAN +#define SLOG_F_FULL_JOIN QPLAN_FULL_JOIN +#define SLOG_F_TMP_TABLE QPLAN_TMP_TABLE +#define SLOG_F_TMP_DISK QPLAN_TMP_DISK +#define SLOG_F_FILESORT QPLAN_FILESORT +#define SLOG_F_FILESORT_DISK QPLAN_FILESORT_DISK +#define SLOG_F_INVALID 1 << 31 +#define SLOG_F_NONE 0 + +static const struct msl_opts slog_filter[]= +{ + { SLOG_F_QC_NO, "qc_miss" }, + { SLOG_F_FULL_SCAN, "full_scan" }, + { SLOG_F_FULL_JOIN, "full_join" }, + { SLOG_F_TMP_TABLE, "tmp_table" }, + { SLOG_F_TMP_DISK, "tmp_table_on_disk" }, + { SLOG_F_FILESORT, "filesort" }, + { SLOG_F_FILESORT_DISK, "filesort_on_disk" }, + { SLOG_F_INVALID, (char *)0 } +}; enum enum_parsing_place { @@ -1323,7 +1395,7 @@ extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; extern char* opt_secure_file_priv; -extern my_bool opt_log_slow_admin_statements; +extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements; extern my_bool sp_automatic_privileges, opt_noacl; extern my_bool opt_old_style_user_limits, trust_function_creators; extern uint opt_crash_binlog_innodb; diff -r 06eb221fefe3 sql/mysqld.cc --- a/sql/mysqld.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/mysqld.cc Mon Apr 07 14:29:08 2008 +0200 @@ -169,7 +169,6 @@ static void getvolumeID(BYTE *volumeName); #endif /* __NETWARE__ */ - #ifdef _AIX41 int initgroups(const char *,unsigned int); #endif @@ -227,6 +226,7 @@ extern "C" int gethostname(char *name, int namelen); #endif +ulonglong frequency= 0; /* Constants */ @@ -398,6 +398,7 @@ my_bool opt_secure_auth= 0; char* opt_secure_file_priv= 0; my_bool opt_log_slow_admin_statements= 0; +my_bool opt_log_slow_slave_statements= 0; my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; uint opt_large_page_size= 0; @@ -3521,6 +3522,8 @@ unireg_abort(1); } } + if (!QueryPerformanceFrequency((LARGE_INTEGER *)&frequency)) + frequency= 0; #endif /* __WIN__ */ if (init_common_variables(MYSQL_CONFIG_NAME, @@ -4769,7 +4772,7 @@ OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE, OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_BLOCK_SIZE, OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD, - OPT_LONG_QUERY_TIME, + OPT_LONG_QUERY_TIME, OPT_MIN_EXAMINED_ROW_LIMIT, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET, OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE, OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS, @@ -4860,6 +4863,10 @@ OPT_TIMED_MUTEXES, OPT_OLD_STYLE_USER_LIMITS, OPT_LOG_SLOW_ADMIN_STATEMENTS, + OPT_LOG_SLOW_SLAVE_STATEMENTS, + OPT_LOG_SLOW_RATE_LIMIT, + OPT_LOG_SLOW_VERBOSITY, + OPT_LOG_SLOW_FILTER, OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, @@ -5247,6 +5254,11 @@ "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to the slow log if it is open.", (gptr*) &opt_log_slow_admin_statements, (gptr*) &opt_log_slow_admin_statements, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"log-slow-slave-statements", OPT_LOG_SLOW_SLAVE_STATEMENTS, + "Log slow replicated statements to the slow log if it is open.", + (gptr*) &opt_log_slow_slave_statements, + (gptr*) &opt_log_slow_slave_statements, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-queries", OPT_SLOW_QUERY_LOG, "Log slow queries to this log file. Defaults logging to hostname-slow.log file. Must be enabled to activate other slow log options.", @@ -5911,11 +5923,27 @@ (gptr*) 0, 0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, 1, 100, 0, 1, 0}, + {"log_slow_filter", OPT_LOG_SLOW_FILTER, + "Log only the queries that followed certain execution plan. Multiple flags allowed in a comma-separated string. [qc_miss, full_scan, full_join, tmp_table, tmp_table_on_disk, filesort, filesort_on_disk]", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, SLOG_F_NONE, 0, 0}, + {"log_slow_rate_limit", OPT_LOG_SLOW_RATE_LIMIT, + "Rate limit statement writes to slow log to only those from every (1/log_slow_rate_limit) session.", + (gptr*) &global_system_variables.log_slow_rate_limit, + (gptr*) &max_system_variables.log_slow_rate_limit, 0, GET_ULONG, + REQUIRED_ARG, 0, 1, ~0L, 0, 1L, 0}, + {"log_slow_verbosity", OPT_LOG_SLOW_VERBOSITY, + "Choose how verbose the messages to your slow log will be. Multiple flags allowed in a comma-separated string. [microtime, query_plan, innodb]", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, SLOG_V_MICROTIME, 0, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file.", (gptr*) &global_system_variables.long_query_time, (gptr*) &max_system_variables.long_query_time, 0, GET_ULONG, - REQUIRED_ARG, 10, 1, LONG_TIMEOUT, 0, 1, 0}, + REQUIRED_ARG, 10000000, 0, LONG_TIMEOUT * 1000000, 0, 1, 0}, + {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT, + "Don't log queries which examine less than min_examined_row_limit rows to file.", + (gptr*) &global_system_variables.min_examined_row_limit, + (gptr*) &max_system_variables.min_examined_row_limit, 0, GET_ULONG, + REQUIRED_ARG, 0, 0, ~0L, 0, 1L, 0}, {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES, "If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive. Should be set to 2 if you are using a case insensitive file system", (gptr*) &lower_case_table_names, @@ -6683,7 +6711,9 @@ global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; - + global_system_variables.log_slow_verbosity= SLOG_V_MICROTIME; + global_system_variables.log_slow_filter= SLOG_F_NONE; + /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal when collecting index statistics for MyISAM tables. @@ -7144,6 +7174,24 @@ case OPT_BOOTSTRAP: opt_noacl=opt_bootstrap=1; break; + case OPT_LOG_SLOW_FILTER: + if ((global_system_variables.log_slow_filter= + msl_flag_resolve_by_name(slog_filter, argument, + SLOG_F_NONE, SLOG_F_INVALID)) == SLOG_F_INVALID) + { + fprintf(stderr,"Invalid argument to log_slow_filter\n"); + exit(1); + } + break; + case OPT_LOG_SLOW_VERBOSITY: + if ((global_system_variables.log_slow_verbosity= + msl_flag_resolve_by_name(slog_verb, argument, + SLOG_V_NONE, SLOG_V_INVALID)) == SLOG_V_INVALID) + { + fprintf(stderr,"Invalid argument to log_slow_verbosity\n"); + exit(1); + } + break; case OPT_STORAGE_ENGINE: { if ((enum db_type)((global_system_variables.table_type= @@ -7468,10 +7516,14 @@ if (opt_bdb) sql_print_warning("this binary does not contain BDB storage engine"); #endif - if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes) && + if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes || + opt_log_slow_slave_statements) && !opt_slow_log) - sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set"); - + { + sql_print_warning("options --log-slow-admin-statements, --log-slow-slave-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set"); + opt_log_slow_slave_statements= FALSE; + } + if (argc > 0) { fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv); diff -r 06eb221fefe3 sql/set_var.cc --- a/sql/set_var.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/set_var.cc Mon Apr 07 14:29:08 2008 +0200 @@ -215,7 +215,7 @@ sys_log_queries_not_using_indexes("log_queries_not_using_indexes", &opt_log_queries_not_using_indexes); sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings); -sys_var_thd_ulong sys_long_query_time("long_query_time", +sys_var_thd_ulonglong sys_long_query_time("long_query_time", &SV::long_query_time); sys_var_bool_const_ptr sys_log_slow("log_slow_queries", &opt_slow_log); sys_var_thd_bool sys_low_priority_updates("low_priority_updates", @@ -281,6 +281,8 @@ &SV::max_tmp_tables); sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count", &max_write_lock_count); +sys_var_thd_ulong sys_min_examined_row_limit("min_examined_row_limit", + &SV::min_examined_row_limit); sys_var_thd_ulong sys_multi_range_count("multi_range_count", &SV::multi_range_count); sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size", @@ -324,6 +326,20 @@ sys_var_bool_ptr sys_relay_log_purge("relay_log_purge", &relay_log_purge); #endif +sys_var_thd_ulong sys_log_slow_rate_limit("log_slow_rate_limit", + &SV::log_slow_rate_limit); +sys_var_thd_msl_flag sys_log_slow_filter("log_slow_filter", + &SV::log_slow_filter, + SLOG_F_NONE, + SLOG_F_NONE, + SLOG_F_INVALID, + slog_filter); +sys_var_thd_msl_flag sys_log_slow_verbosity("log_slow_verbosity", + &SV::log_slow_verbosity, + SLOG_V_NONE, + SLOG_V_MICROTIME, + SLOG_V_INVALID, + slog_verb); sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", &rpl_recovery_rank); sys_var_long_ptr sys_query_cache_size("query_cache_size", @@ -675,6 +691,9 @@ &sys_log_off, &sys_log_queries_not_using_indexes, &sys_log_slow, + &sys_log_slow_filter, + &sys_log_slow_rate_limit, + &sys_log_slow_verbosity, &sys_log_update, &sys_log_warnings, &sys_long_query_time, @@ -698,6 +717,7 @@ &sys_max_tmp_tables, &sys_max_user_connections, &sys_max_write_lock_count, + &sys_min_examined_row_limit, &sys_multi_range_count, &sys_myisam_data_pointer_size, &sys_myisam_max_sort_file_size, @@ -963,6 +983,8 @@ {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL}, #endif {sys_log_slow.name, (char*) &sys_log_slow, SHOW_SYS}, + {sys_log_slow_filter.name, (char*) &sys_log_slow_filter, SHOW_SYS}, + {sys_log_slow_verbosity.name, (char*) &sys_log_slow_verbosity, SHOW_SYS}, {sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS}, {sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS}, {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS}, @@ -991,6 +1013,7 @@ {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, + {sys_min_examined_row_limit.name, (char*) &sys_min_examined_row_limit, SHOW_SYS}, {sys_multi_range_count.name, (char*) &sys_multi_range_count, SHOW_SYS}, {sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS}, {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size, @@ -1043,6 +1066,7 @@ {sys_query_prealloc_size.name, (char*) &sys_query_prealloc_size, SHOW_SYS}, {sys_range_alloc_block_size.name, (char*) &sys_range_alloc_block_size, SHOW_SYS}, + {sys_log_slow_rate_limit.name, (char*) &sys_log_slow_rate_limit, SHOW_SYS}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, @@ -1639,6 +1663,57 @@ return (byte*) &(thd->variables.*offset); } +void sys_var_thd_microtime::set_default(THD *thd, enum_var_type type) +{ + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.*offset= (ulonglong) option_limits->def_value; + pthread_mutex_unlock(&LOCK_global_system_variables); +} + +bool sys_var_thd_microtime::check(THD *thd, set_var *var) +{ + if (var->value->result_type() == DECIMAL_RESULT) + var->save_result.ulonglong_value= (ulonglong)(var->value->val_real() * 1000000); + else + var->save_result.ulonglong_value= (ulonglong)var->value->val_int() * 1000000; + return 0; +} + +byte *sys_var_thd_microtime::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + if (type == OPT_GLOBAL) + return (byte*) &(global_system_variables.*offset); + return (byte*) &(thd->variables.*offset); +} + +bool sys_var_thd_microtime::update(THD *thd, set_var *var) +{ + bool fixed= FALSE; + ulonglong tmp= var->save_result.ulonglong_value; + + if (tmp > max_system_variables.*offset) + tmp= max_system_variables.*offset; + + if (option_limits) + tmp= getopt_ull_limit_value(tmp, option_limits, &fixed); + + if (fixed) + throw_bounds_warning(thd, option_limits->name, tmp); + + /* Lock is needed to make things safe on 32 bit systems */ + if (var->type == OPT_GLOBAL) + { + /* Lock is needed to make things safe on 32 bit systems */ + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.*offset= tmp; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.*offset= (ulonglong) tmp; + + return 0; +} bool sys_var_thd_ha_rows::update(THD *thd, set_var *var) { @@ -3483,6 +3558,191 @@ #endif } +/* Slow log stuff */ + +ulong msl_option_resolve_by_name(const struct msl_opts *opts, const char *name, ulong len) +{ + ulong i; + + for (i=0; opts[i].name; i++) + { + if (!my_strnncoll(&my_charset_latin1, + (const uchar *)name, len, + (const uchar *)opts[i].name, strlen(opts[i].name))) + return opts[i].val; + } + return opts[i].val; +} + +ulong msl_flag_resolve_by_name(const struct msl_opts *opts, const char *names_list, + const ulong none_val, const ulong invalid_val) +{ + const char *p, *e; + ulong val= none_val; + + if (!*names_list) + return val; + + for (p= e= names_list; ; e++) + { + ulong i; + + if (*e != ',' && *e) + continue; + for (i=0; opts[i].name; i++) + { + if (!my_strnncoll(&my_charset_latin1, + (const uchar *)p, e - p, + (const uchar *)opts[i].name, strlen(opts[i].name))) + { + val= val | opts[i].val; + break; + } + } + if (opts[i].val == invalid_val) + return invalid_val; + if (!*e) + break; + p= e + 1; + } + return val; +} + +const char *msl_option_get_name(const struct msl_opts *opts, ulong val) +{ + for (ulong i=0; opts[i].name && opts[i].name[0]; i++) + { + if (opts[i].val == val) + return opts[i].name; + } + return "*INVALID*"; +} + +char *msl_flag_get_name(const struct msl_opts *opts, char *buf, ulong val) +{ + uint offset= 0; + + *buf= '\0'; + for (ulong i=0; opts[i].name && opts[i].name[0]; i++) + { + if (opts[i].val & val) + offset+= snprintf(buf+offset, STRING_BUFFER_USUAL_SIZE - offset - 1, + "%s%s", (offset ? "," : ""), opts[i].name); + } + return buf; +} + +/**************************************************************************** + Functions to handle log_slow_verbosity +****************************************************************************/ + +/* Based upon sys_var::check_enum() */ + +bool sys_var_thd_msl_option::check(THD *thd, set_var *var) +{ + char buff[STRING_BUFFER_USUAL_SIZE]; + String str(buff, sizeof(buff), &my_charset_latin1), *res; + + if (var->value->result_type() == STRING_RESULT) + { + ulong verb= this->invalid_val; + if (!(res=var->value->val_str(&str)) || + (var->save_result.ulong_value= + (ulong) (verb= msl_option_resolve_by_name(this->opts, res->ptr(), res->length()))) == this->invalid_val) + goto err; + return 0; + } + +err: + my_error(ER_WRONG_ARGUMENTS, MYF(0), var->var->name); + return 1; +} + +byte *sys_var_thd_msl_option::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + ulong val; + val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : + thd->variables.*offset); + const char *verbosity= msl_option_get_name(this->opts, val); + return (byte *) verbosity; +} + + +void sys_var_thd_msl_option::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.*offset= (ulong) this->default_val; + else + thd->variables.*offset= (ulong) (global_system_variables.*offset); +} + + +bool sys_var_thd_msl_option::update(THD *thd, set_var *var) +{ + if (var->type == OPT_GLOBAL) + global_system_variables.*offset= var->save_result.ulong_value; + else + thd->variables.*offset= var->save_result.ulong_value; + return 0; +} + +/**************************************************************************** + Functions to handle log_slow_filter +****************************************************************************/ + +/* Based upon sys_var::check_enum() */ + +bool sys_var_thd_msl_flag::check(THD *thd, set_var *var) +{ + char buff[2 * STRING_BUFFER_USUAL_SIZE]; + String str(buff, sizeof(buff), &my_charset_latin1), *res; + + if (var->value->result_type() == STRING_RESULT) + { + ulong filter= this->none_val; + if (!(res=var->value->val_str(&str)) || + (var->save_result.ulong_value= + (ulong) (filter= msl_flag_resolve_by_name(this->flags, res->ptr(), this->none_val, + this->invalid_val))) == this->invalid_val) + goto err; + return 0; + } + +err: + my_error(ER_WRONG_ARGUMENTS, MYF(0), var->var->name); + return 1; +} + +byte *sys_var_thd_msl_flag::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + ulong val; + val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : + thd->variables.*offset); + msl_flag_get_name(this->flags, this->flags_string, val); + return (byte *) this->flags_string; +} + + +void sys_var_thd_msl_flag::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.*offset= (ulong) this->default_val; + else + thd->variables.*offset= (ulong) (global_system_variables.*offset); +} + + +bool sys_var_thd_msl_flag::update(THD *thd, set_var *var) +{ + if (var->type == OPT_GLOBAL) + global_system_variables.*offset= var->save_result.ulong_value; + else + thd->variables.*offset= var->save_result.ulong_value; + return 0; +} + /**************************************************************************** Functions to handle table_type ****************************************************************************/ diff -r 06eb221fefe3 sql/set_var.h --- a/sql/set_var.h Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/set_var.h Mon Apr 07 14:29:09 2008 +0200 @@ -123,6 +123,7 @@ }; + class sys_var_ulonglong_ptr :public sys_var { public: @@ -309,7 +310,6 @@ } }; - class sys_var_thd_ulong :public sys_var_thd { sys_check_func check_func; @@ -329,6 +329,23 @@ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; +class sys_var_thd_microtime :public sys_var_thd +{ +public: + ulonglong SV::*offset; + sys_var_thd_microtime(const char *name_arg, ulonglong SV::*offset_arg) + :sys_var_thd(name_arg), offset(offset_arg) + {} + bool update(THD *thd, set_var *var); + void set_default(THD *thd, enum_var_type type); + SHOW_TYPE type() { return SHOW_MICROTIME; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + bool check(THD *thd, set_var *var); + bool check_update_type(Item_result type) + { + return type != INT_RESULT && type != DECIMAL_RESULT; + } +}; class sys_var_thd_ha_rows :public sys_var_thd { @@ -346,7 +363,6 @@ SHOW_TYPE show_type() { return SHOW_HA_ROWS; } byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; - class sys_var_thd_ulonglong :public sys_var_thd { @@ -376,7 +392,6 @@ } }; - class sys_var_thd_bool :public sys_var_thd { public: @@ -446,6 +461,66 @@ ulong *length); }; + +class sys_var_thd_msl_option :public sys_var_thd +{ +protected: + ulong SV::*offset; + const ulong none_val; + const ulong default_val; + const ulong invalid_val; + const struct msl_opts *opts; +public: + sys_var_thd_msl_option(const char *name_arg, ulong SV::*offset_arg, + const ulong none_val_arg, + const ulong default_val_arg, + const ulong invalid_val_arg, + const struct msl_opts *opts_arg) + :sys_var_thd(name_arg), offset(offset_arg), none_val(none_val_arg), + default_val(default_val_arg), invalid_val(invalid_val_arg), + opts(opts_arg) + {} + bool check(THD *thd, set_var *var); + SHOW_TYPE show_type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) + { + return type != STRING_RESULT; /* Only accept strings */ + } + void set_default(THD *thd, enum_var_type type); + bool update(THD *thd, set_var *var); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; + + +class sys_var_thd_msl_flag :public sys_var_thd +{ +protected: + char flags_string[2 * STRING_BUFFER_USUAL_SIZE]; + ulong SV::*offset; + const ulong none_val; + const ulong default_val; + const ulong invalid_val; + const struct msl_opts *flags; +public: + sys_var_thd_msl_flag(const char *name_arg, ulong SV::*offset_arg, + const ulong none_val_arg, + const ulong default_val_arg, + const ulong invalid_val_arg, + const struct msl_opts *flags_arg) + :sys_var_thd(name_arg), offset(offset_arg), none_val(none_val_arg), + default_val(default_val_arg), invalid_val(invalid_val_arg), + flags(flags_arg) + {} + bool check(THD *thd, set_var *var); + SHOW_TYPE show_type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) + { + return type != STRING_RESULT; /* Only accept strings */ + } + void set_default(THD *thd, enum_var_type type); + bool update(THD *thd, set_var *var); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; class sys_var_thd_storage_engine :public sys_var_thd { @@ -1042,3 +1117,11 @@ bool process_key_caches(int (* func) (const char *name, KEY_CACHE *)); void delete_elements(I_List *list, void (*free_element)(const char*, gptr)); + +/* Slow log functions */ + +ulong msl_option_resolve_by_name(const struct msl_opts *opts, const char *name, ulong len); +ulong msl_flag_resolve_by_name(const struct msl_opts *opts, const char *names_list, + const ulong none_val, const ulong invalid_val); +const char *msl_option_get_name(const struct msl_opts *opts, ulong val); +char *msl_flag_get_name(const struct msl_opts *opts, char *buf, ulong val); diff -r 06eb221fefe3 sql/slave.cc --- a/sql/slave.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/slave.cc Mon Apr 07 14:29:09 2008 +0200 @@ -2908,6 +2908,12 @@ + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ thd->slave_thread = 1; set_slave_thread_options(thd); + if (opt_log_slow_slave_statements) + { + thd->enable_slow_log= TRUE; + /* Slave thread is excluded from rate limiting the slow log writes. */ + thd->write_to_slow_log= TRUE; + } thd->client_capabilities = CLIENT_LOCAL_FILES; thd->real_id=pthread_self(); pthread_mutex_lock(&LOCK_thread_count); diff -r 06eb221fefe3 sql/sql_cache.cc --- a/sql/sql_cache.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/sql_cache.cc Mon Apr 07 14:29:09 2008 +0200 @@ -1334,6 +1334,7 @@ thd->limit_found_rows = query->found_rows(); thd->status_var.last_query_cost= 0.0; + thd->query_plan_flags|= QPLAN_QC; BLOCK_UNLOCK_RD(query_block); DBUG_RETURN(1); // Result sent to client @@ -1341,6 +1342,7 @@ err_unlock: STRUCT_UNLOCK(&structure_guard_mutex); err: + thd->query_plan_flags|= QPLAN_QC_NO; DBUG_RETURN(0); // Query was not cached } diff -r 06eb221fefe3 sql/sql_class.cc --- a/sql/sql_class.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/sql_class.cc Mon Apr 07 14:29:09 2008 +0200 @@ -174,7 +174,7 @@ lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0), transaction_rollback_request(0), is_fatal_sub_stmt_error(0), - rand_used(0), time_zone_used(0), + rand_used(0), time_zone_used(0), user_timer(0), last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0), clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE), spcont(NULL), m_lip(NULL) @@ -2190,6 +2190,12 @@ backup->cuted_fields= cuted_fields; backup->client_capabilities= client_capabilities; backup->savepoints= transaction.savepoints; + backup->innodb_io_reads= innodb_io_reads; + backup->innodb_io_read= innodb_io_read; + backup->innodb_io_reads_wait_timer= innodb_io_reads_wait_timer; + backup->innodb_lock_que_wait_timer= innodb_lock_que_wait_timer; + backup->innodb_innodb_que_wait_timer= innodb_innodb_que_wait_timer; + backup->innodb_page_access= innodb_page_access; if (!lex->requires_prelocking() || is_update_query(lex->sql_command)) options&= ~OPTION_BIN_LOG; @@ -2206,7 +2212,13 @@ sent_row_count= 0; cuted_fields= 0; transaction.savepoints= 0; - + innodb_io_reads= 0; + innodb_io_read= 0; + innodb_io_reads_wait_timer= 0; + innodb_lock_que_wait_timer= 0; + innodb_innodb_que_wait_timer= 0; + innodb_page_access= 0; + /* Surpress OK packets in case if we will execute statements */ net.no_send_ok= TRUE; } @@ -2259,6 +2271,12 @@ */ examined_row_count+= backup->examined_row_count; cuted_fields+= backup->cuted_fields; + innodb_io_reads+= backup->innodb_io_reads; + innodb_io_read+= backup->innodb_io_read; + innodb_io_reads_wait_timer+= backup->innodb_io_reads_wait_timer; + innodb_lock_que_wait_timer+= backup->innodb_lock_que_wait_timer; + innodb_innodb_que_wait_timer+= backup->innodb_innodb_que_wait_timer; + innodb_page_access+= backup->innodb_page_access; } diff -r 06eb221fefe3 sql/sql_class.h --- a/sql/sql_class.h Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/sql_class.h Mon Apr 07 14:29:09 2008 +0200 @@ -43,6 +43,13 @@ extern char internal_table_name[2]; extern char empty_c_string[1]; extern const char **errmesg; +#ifdef __cplusplus +__BEGIN_DECLS +#endif +extern ulonglong frequency; +#ifdef __cplusplus +__END_DECLS +#endif #define TC_LOG_PAGE_SIZE 8192 #define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE) @@ -314,7 +321,7 @@ bool write(THD *thd, enum enum_server_command command, const char *format, ...) ATTRIBUTE_FORMAT(printf, 4, 5); bool write(THD *thd, const char *query, uint query_length, - time_t query_start=0); + time_t query_start=0, ulonglong query_start_timer=0); bool write(Log_event* event_info); // binary log write bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event); @@ -520,13 +527,14 @@ ulong auto_increment_increment, auto_increment_offset; ulong bulk_insert_buff_size; ulong join_buff_size; - ulong long_query_time; + ulonglong long_query_time; ulong max_allowed_packet; ulong max_error_count; ulong max_length_for_sort_data; ulong max_sort_length; ulong max_tmp_tables; ulong max_insert_delayed_threads; + ulong min_examined_row_limit; ulong multi_range_count; ulong myisam_repair_threads; ulong myisam_sort_buff_size; @@ -541,10 +549,13 @@ ulong optimizer_search_depth; ulong preload_buff_size; ulong query_cache_type; + ulong log_slow_rate_limit; ulong read_buff_size; ulong read_rnd_buff_size; ulong div_precincrement; ulong sortbuff_size; + ulong log_slow_filter; + ulong log_slow_verbosity; ulong table_type; ulong tx_isolation; ulong completion_type; @@ -1111,6 +1122,12 @@ uint in_sub_stmt; bool enable_slow_log, insert_id_used, clear_next_insert_id; bool last_insert_id_used; + ulong innodb_io_reads; + ulonglong innodb_io_read; + ulong innodb_io_reads_wait_timer; + ulong innodb_lock_que_wait_timer; + ulong innodb_innodb_que_wait_timer; + ulong innodb_page_access; my_bool no_send_ok; SAVEPOINT *savepoints; }; @@ -1167,6 +1184,11 @@ class THD :public Statement, public Open_tables_state { +private: + inline ulonglong query_start_timer() { return start_timer; } + inline void set_timer() { if (user_timer) start_timer=timer_after_lock=user_timer; else timer_after_lock=my_timer(&start_timer, frequency); } + inline void end_timer() { my_timer(&start_timer, frequency); } + inline void lock_timer() { my_timer(&timer_after_lock, frequency); } public: /* Constant for THD::where initialization in the beginning of every query. @@ -1272,10 +1294,24 @@ */ const char *where; time_t start_time,time_after_lock,user_time; + ulonglong start_timer,timer_after_lock, user_timer; time_t connect_time,thr_create_time; // track down slow pthread_create thr_lock_type update_lock_default; Delayed_insert *di; + bool write_to_slow_log; + + bool innodb_was_used; + ulong innodb_io_reads; + ulonglong innodb_io_read; + ulong innodb_io_reads_wait_timer; + ulong innodb_lock_que_wait_timer; + ulong innodb_innodb_que_wait_timer; + ulong innodb_page_access; + + ulong query_plan_flags; + ulong query_plan_fsort_passes; + /* <> 0 if we are inside of trigger or stored function. */ uint in_sub_stmt; @@ -1663,11 +1699,11 @@ sql_print_information("time() failed with %d", errno); } - inline time_t query_start() { query_start_used=1; return start_time; } - inline void set_time() { if (user_time) start_time=time_after_lock=user_time; else { safe_time(&start_time); time_after_lock= start_time; }} - inline void end_time() { safe_time(&start_time); } - inline void set_time(time_t t) { time_after_lock=start_time=user_time=t; } - inline void lock_time() { safe_time(&time_after_lock); } + inline time_t query_start() { query_start_timer(); query_start_used=1; return start_time; } + inline void set_time() { set_timer(); if (user_time) start_time=time_after_lock=user_time; else { safe_time(&start_time); time_after_lock= start_time; }} + inline void end_time() { end_timer(); safe_time(&start_time); } + inline void set_time(time_t t) { set_timer(); time_after_lock=start_time=user_time=t; } + inline void lock_time() { lock_timer(); safe_time(&time_after_lock); } inline void insert_id(ulonglong id_arg) { last_insert_id= id_arg; diff -r 06eb221fefe3 sql/sql_parse.cc --- a/sql/sql_parse.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/sql_parse.cc Mon Apr 07 14:29:09 2008 +0200 @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef HAVE_INNOBASE_DB #include "ha_innodb.h" @@ -1194,6 +1195,15 @@ my_net_set_read_timeout(net, thd->variables.net_read_timeout); my_net_set_write_timeout(net, thd->variables.net_write_timeout); + /* + If rate limiting of slow log writes is enabled, decide whether to log this + new thread's queries or not. Uses extremely simple algorithm. :) + */ + thd->write_to_slow_log= FALSE; + if (thd->variables.log_slow_rate_limit <= 1 || + (thd->thread_id % thd->variables.log_slow_rate_limit) == 0) + thd->write_to_slow_log= TRUE; + while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION)) { @@ -2269,26 +2279,52 @@ return; // Don't set time for sub stmt start_of_query= thd->start_time; + ulonglong start_of_query_timer= thd->start_timer; thd->end_time(); // Set start time + + + /* Follow the slow log filter configuration. */ + if (thd->variables.log_slow_filter != SLOG_F_NONE && + (!(thd->variables.log_slow_filter & thd->query_plan_flags) || + ((thd->variables.log_slow_filter & SLOG_F_QC_NO) && + (thd->query_plan_flags & QPLAN_QC)))) + return; + + /* + Low long_query_time value most likely means user is debugging stuff and even + though some thread's queries are not supposed to be logged b/c of the rate + limit, if one of them takes long enough (>= 1 second) it will be sensible + to make an exception and write to slow log anyway. + */ + if (thd->write_to_slow_log != TRUE && thd->variables.long_query_time < 1000000 && + (ulong) (thd->start_timer - thd->timer_after_lock) >= 1000000) + thd->write_to_slow_log= TRUE; + + /* Do not log this thread's queries due to rate limiting. */ + if (thd->write_to_slow_log != TRUE) + return; /* Do not log administrative statements unless the appropriate option is set; do not log into slow log if reading from backup. */ - if (thd->enable_slow_log && !thd->user_time) + if (thd->enable_slow_log && + (!thd->user_time || (thd->slave_thread && opt_log_slow_slave_statements)) + ) { thd->proc_info="logging slow query"; - if ((ulong) (thd->start_time - thd->time_after_lock) > - thd->variables.long_query_time || - (thd->server_status & - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && - opt_log_queries_not_using_indexes && - /* == SQLCOM_END unless this is a SHOW command */ - thd->lex->orig_sql_command == SQLCOM_END) + if (((ulong) (thd->start_timer - thd->timer_after_lock) >= + thd->variables.long_query_time || + (thd->server_status & + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && + opt_log_queries_not_using_indexes && + /* == SQLCOM_END unless this is a SHOW command */ + thd->lex->orig_sql_command == SQLCOM_END) && + thd->examined_row_count >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; - mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query); + mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query, start_of_query_timer); } } } @@ -5940,6 +5976,15 @@ thd->total_warn_count=0; // Warnings for this query thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; + thd->innodb_was_used= FALSE; + thd->innodb_io_reads= 0; + thd->innodb_io_read= 0; + thd->innodb_io_reads_wait_timer= 0; + thd->innodb_lock_que_wait_timer= 0; + thd->innodb_innodb_que_wait_timer= 0; + thd->innodb_page_access= 0; + thd->query_plan_flags= QPLAN_NONE; + thd->query_plan_fsort_passes= 0; } DBUG_VOID_RETURN; } diff -r 06eb221fefe3 sql/sql_select.cc --- a/sql/sql_select.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/sql_select.cc Mon Apr 07 14:29:09 2008 +0200 @@ -6218,8 +6218,11 @@ { join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED; if (statistics) + { statistic_increment(join->thd->status_var.select_scan_count, &LOCK_status); + join->thd->query_plan_flags|= QPLAN_FULL_SCAN; + } } } else @@ -6234,8 +6237,11 @@ { join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED; if (statistics) + { statistic_increment(join->thd->status_var.select_full_join_count, &LOCK_status); + join->thd->query_plan_flags|= QPLAN_FULL_JOIN; + } } } if (!table->no_keyread) @@ -9279,6 +9285,7 @@ (ulong) rows_limit,test(group))); statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status); + thd->query_plan_flags|= QPLAN_TMP_TABLE; if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES)) temp_pool_slot = bitmap_set_next(&temp_pool); @@ -10139,6 +10146,7 @@ } statistic_increment(table->in_use->status_var.created_tmp_disk_tables, &LOCK_status); + table->in_use->query_plan_flags|= QPLAN_TMP_DISK; table->s->db_record_offset= 1; DBUG_RETURN(0); err: diff -r 06eb221fefe3 sql/sql_show.cc --- a/sql/sql_show.cc Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/sql_show.cc Mon Apr 07 14:29:09 2008 +0200 @@ -1488,6 +1488,9 @@ value= ((char *) status_var + (ulonglong) value); case SHOW_LONGLONG: end= longlong10_to_str(*(longlong*) value, buff, 10); + break; + case SHOW_MICROTIME: + end= buff + sprintf(buff, "%.6f", (*(ulonglong*)value) / 1000000.0); break; case SHOW_HA_ROWS: end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10); diff -r 06eb221fefe3 sql/structs.h --- a/sql/structs.h Thu Mar 27 11:23:01 2008 +0100 +++ b/sql/structs.h Mon Apr 07 14:29:09 2008 +0200 @@ -168,8 +168,8 @@ enum SHOW_TYPE { SHOW_UNDEF, - SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, - SHOW_DOUBLE_STATUS, + SHOW_LONG, SHOW_LONGLONG, SHOW_MICROTIME, SHOW_INT, SHOW_CHAR, + SHOW_CHAR_PTR, SHOW_DOUBLE_STATUS, SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION, SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS, SHOW_VARS,